diff --git a/DEPS b/DEPS
index 5419b025..6ad5773 100644
--- a/DEPS
+++ b/DEPS
@@ -195,11 +195,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': '750261f41af6fc636d64d4431cee2eae67d49d84',
+  'skia_revision': 'e61500059aa7471a65631da81aae70bd1111e5be',
   # 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': '69b996bd9bcec21debfa319c5111697c03f8c77d',
+  'v8_revision': '8c06327064717567a0723117ea9e45ad0e0e98e5',
   # 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.
@@ -211,7 +211,7 @@
   # 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': 'b3c1e71eb1cb55ba78a3f884ab4e68ef1bd396da',
+  'swiftshader_revision': '6d93a63356e12fc9945ba0cd40a2125cc8802416',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -258,7 +258,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': '74f8dbb9578277e945548fa2e3378ec426dc2c69',
+  'catapult_revision': '83c2cb1060772ddd0e096c49918785afb11148b4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -266,7 +266,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '0afca615a816673ed828161238d98c5d8483b635',
+  'devtools_frontend_revision': '256b2c2587679c74a8fbdaeb9d0b1601c22e889f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -881,7 +881,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'af5911446cd05354464bc60274f91c6a304d6ade',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'e6a8f4ed40bbe1622f7b3356655175cb69171ea0',
       'condition': 'checkout_chromeos',
   },
 
@@ -901,7 +901,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1407cfd9e5f4de4cf9bd04ecc435ee5b760675c1',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '422c039e8e1b95402a10734e1c1e376084fbd15e',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1237,7 +1237,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '3dd5b80bc4f172dd82925bb259cb7c82348409c5',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + '25493aef9427e1a0d93d993b441dec9e64266725',
+    Var('chromium_git') + '/openscreen' + '@' + 'dee4a03873a1ee6e09a5c4c43faa653470eba795',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '9e97b73e7dd2bfc07745489d728f6a36665c648f',
@@ -1486,7 +1486,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'c401923f3ee3b4ec5423a3ede7e91550e2acd52d',
+    Var('webrtc_git') + '/src.git' + '@' + '04482985b2041a91f4282ce4a3e7bb3716a621f1',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1577,7 +1577,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 't7oX_wB80ik282fRV1dJNehd9v-uldOkRpj9yVV25WwC',
+        'version': 'F5O08dsIWdHTa7NozxSJmHAyJsTLlm6Zxo9jTQjw1qEC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/browser/aw_browser_terminator.cc b/android_webview/browser/aw_browser_terminator.cc
index 5d54028b..4d6a61c 100644
--- a/android_webview/browser/aw_browser_terminator.cc
+++ b/android_webview/browser/aw_browser_terminator.cc
@@ -10,7 +10,10 @@
 #include "android_webview/browser/aw_browser_process.h"
 #include "android_webview/browser/aw_render_process_gone_delegate.h"
 #include "android_webview/common/aw_descriptors.h"
+#include "android_webview/common/crash_reporter/crash_keys.h"
 #include "base/android/scoped_java_ref.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
@@ -123,6 +126,20 @@
   LOG(ERROR) << "Renderer process (" << info.pid << ") crash detected (code "
              << info.crash_signo << ").";
 
+  if (info.crash_signo ==
+      crash_reporter::ChildExitObserver::TerminationInfo::kInvalidSigno) {
+    static auto* termination_info_key = base::debug::AllocateCrashKeyString(
+        crash_keys::kTerminationInfo, base::debug::CrashKeySize::Size32);
+    std::ostringstream stream;
+    stream << info.was_killed_intentionally_by_browser << " "
+           << info.renderer_shutdown_requested << " "
+           << info.threw_exception_during_init << " "
+           << info.renderer_has_visible_clients;
+    base::debug::SetCrashKeyString(termination_info_key, stream.str());
+    base::debug::DumpWithoutCrashing();
+    base::debug::ClearCrashKeyString(termination_info_key);
+  }
+
   std::vector<ScopedJavaGlobalRef<jobject>> java_web_contents;
   GetJavaWebContentsForRenderProcess(rph, &java_web_contents);
 
diff --git a/android_webview/common/crash_reporter/crash_keys.cc b/android_webview/common/crash_reporter/crash_keys.cc
index 83c5512..07d647e 100644
--- a/android_webview/common/crash_reporter/crash_keys.cc
+++ b/android_webview/common/crash_reporter/crash_keys.cc
@@ -15,6 +15,7 @@
 const char kAppProcessName[] = "app-process-name";
 
 const char kAndroidSdkInt[] = "android-sdk-int";
+const char kTerminationInfo[] = "termination-info";
 
 const char kSupportLibraryWebkitVersion[] = "androidx-webkit-version";
 
@@ -28,6 +29,7 @@
     kAppProcessName,
     kAndroidSdkInt,
     kSupportLibraryWebkitVersion,
+    kTerminationInfo,
 
     // process type
     "ptype",
diff --git a/android_webview/common/crash_reporter/crash_keys.h b/android_webview/common/crash_reporter/crash_keys.h
index fbf1d0d..22320d5 100644
--- a/android_webview/common/crash_reporter/crash_keys.h
+++ b/android_webview/common/crash_reporter/crash_keys.h
@@ -22,6 +22,7 @@
 extern const char kAppProcessName[];
 
 extern const char kAndroidSdkInt[];
+extern const char kTerminationInfo[];
 
 extern const char kSupportLibraryWebkitVersion[];
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/services/CrashReceiverServiceTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/services/CrashReceiverServiceTest.java
index e4be9301..8940b07f 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/services/CrashReceiverServiceTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/services/CrashReceiverServiceTest.java
@@ -22,6 +22,7 @@
 import org.chromium.android_webview.services.CrashReceiverService;
 import org.chromium.android_webview.test.AwJUnit4ClassRunner;
 import org.chromium.android_webview.test.OnlyRunIn;
+import org.chromium.base.test.util.Batch;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -30,10 +31,12 @@
 import java.util.Map;
 
 /**
- * Instrumentation tests for CrashReceiverService.
+ * Instrumentation tests for CrashReceiverService. These tests are batched as UNIT_TESTS because
+ * they don't actually launch any services or other components.
  */
 @RunWith(AwJUnit4ClassRunner.class)
 @OnlyRunIn(SINGLE_PROCESS)
+@Batch(Batch.UNIT_TESTS)
 public class CrashReceiverServiceTest {
     private static final String TEST_CRASH_LOCAL_ID = "abc1234";
     private static final String TEST_CRASH_FILE_NAME =
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/services/MetricsBridgeServiceTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/services/MetricsBridgeServiceTest.java
index 7ec7556..d67b83f 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/services/MetricsBridgeServiceTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/services/MetricsBridgeServiceTest.java
@@ -5,16 +5,14 @@
 package org.chromium.android_webview.test.services;
 
 import static org.chromium.android_webview.test.OnlyRunIn.ProcessMode.SINGLE_PROCESS;
+import static org.chromium.android_webview.test.services.MetricsBridgeServiceUnitTest.RETRIEVE_METRICS_TASK_STATUS_SUCCESS_RECORD;
 
 import android.content.Context;
 import android.content.Intent;
-import android.os.IBinder;
 
 import androidx.test.filters.MediumTest;
 
-import org.junit.After;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -22,152 +20,19 @@
 import org.chromium.android_webview.proto.MetricsBridgeRecords.HistogramRecord;
 import org.chromium.android_webview.proto.MetricsBridgeRecords.HistogramRecord.RecordType;
 import org.chromium.android_webview.services.MetricsBridgeService;
-import org.chromium.android_webview.test.AwActivityTestRule;
 import org.chromium.android_webview.test.AwJUnit4ClassRunner;
 import org.chromium.android_webview.test.OnlyRunIn;
 import org.chromium.base.ContextUtils;
-import org.chromium.base.FileUtils;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
 import java.util.List;
-import java.util.concurrent.FutureTask;
 
 /**
- * Test MetricsBridgeService.
+ * Instrumentation tests MetricsBridgeService. These tests are not batched to make sure all unbinded
+ * services are properly killed between tests.
  */
 @RunWith(AwJUnit4ClassRunner.class)
 @OnlyRunIn(SINGLE_PROCESS)
 public class MetricsBridgeServiceTest {
-    private static final byte[] PARSING_LOG_RESULT_SUCCESS_RECORD =
-            HistogramRecord.newBuilder()
-                    .setRecordType(RecordType.HISTOGRAM_LINEAR)
-                    .setHistogramName("Android.WebView.NonEmbeddedMetrics.ParsingLogResult")
-                    .setSample(MetricsBridgeService.ParsingLogResult.SUCCESS)
-                    .setMin(1)
-                    .setMax(MetricsBridgeService.ParsingLogResult.COUNT)
-                    .setNumBuckets(MetricsBridgeService.ParsingLogResult.COUNT + 1)
-                    .build()
-                    .toByteArray();
-
-    private static final byte[] RETRIEVE_METRICS_TASK_STATUS_SUCCESS_RECORD =
-            HistogramRecord.newBuilder()
-                    .setRecordType(RecordType.HISTOGRAM_LINEAR)
-                    .setHistogramName(
-                            "Android.WebView.NonEmbeddedMetrics.RetrieveMetricsTaskStatus")
-                    .setSample(MetricsBridgeService.RetrieveMetricsTaskStatus.SUCCESS)
-                    .setMin(1)
-                    .setMax(MetricsBridgeService.RetrieveMetricsTaskStatus.COUNT)
-                    .setNumBuckets(MetricsBridgeService.RetrieveMetricsTaskStatus.COUNT + 1)
-                    .build()
-                    .toByteArray();
-
-    private File mTempFile;
-
-    @Before
-    public void setUp() throws IOException {
-        mTempFile = File.createTempFile("test_webview_metrics_bridge_logs", null);
-    }
-
-    @After
-    public void tearDown() {
-        if (mTempFile.exists()) {
-            Assert.assertTrue("Failed to delete \"" + mTempFile + "\"", mTempFile.delete());
-        }
-    }
-
-    @Test
-    @MediumTest
-    // Test that the service saves metrics records to file
-    public void testSaveToFile() throws Throwable {
-        HistogramRecord recordBooleanProto = HistogramRecord.newBuilder()
-                                                     .setRecordType(RecordType.HISTOGRAM_BOOLEAN)
-                                                     .setHistogramName("testSaveToFile.boolean")
-                                                     .setSample(1)
-                                                     .build();
-        HistogramRecord recordLinearProto = HistogramRecord.newBuilder()
-                                                    .setRecordType(RecordType.HISTOGRAM_LINEAR)
-                                                    .setHistogramName("testSaveToFile.linear")
-                                                    .setSample(123)
-                                                    .setMin(1)
-                                                    .setMax(1000)
-                                                    .setNumBuckets(50)
-                                                    .build();
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        writeRecordsToStream(out, recordBooleanProto, recordLinearProto, recordBooleanProto);
-        byte[] expectedData = out.toByteArray();
-
-        // Cannot bind to service using real connection since we need to inject test file name.
-        MetricsBridgeService service = new MetricsBridgeService(mTempFile);
-        // Simulate starting the service by calling onCreate()
-        service.onCreate();
-
-        IBinder binder = service.onBind(null);
-        IMetricsBridgeService stub = IMetricsBridgeService.Stub.asInterface(binder);
-        stub.recordMetrics(recordBooleanProto.toByteArray());
-        stub.recordMetrics(recordLinearProto.toByteArray());
-        stub.recordMetrics(recordBooleanProto.toByteArray());
-
-        // Block until all tasks are finished to make sure all records are written to file.
-        FutureTask<Object> blockTask = service.addTaskToBlock();
-        AwActivityTestRule.waitForFuture(blockTask);
-
-        byte[] resultData = FileUtils.readStream(new FileInputStream(mTempFile));
-        Assert.assertArrayEquals(
-                "byte data from file is different from the expected proto byte data", expectedData,
-                resultData);
-    }
-
-    @Test
-    @MediumTest
-    // Test that service recovers saved data from file, appends new records to it and
-    // clears the file after a retrieve call.
-    public void testRetrieveFromFile() throws Throwable {
-        HistogramRecord recordBooleanProto =
-                HistogramRecord.newBuilder()
-                        .setRecordType(RecordType.HISTOGRAM_BOOLEAN)
-                        .setHistogramName("testRecoverFromFile.boolean")
-                        .setSample(1)
-                        .build();
-        HistogramRecord recordLinearProto = HistogramRecord.newBuilder()
-                                                    .setRecordType(RecordType.HISTOGRAM_LINEAR)
-                                                    .setHistogramName("testRecoverFromFile.linear")
-                                                    .setSample(123)
-                                                    .setMin(1)
-                                                    .setMax(1000)
-                                                    .setNumBuckets(50)
-                                                    .build();
-        // write Initial proto data To File
-        writeRecordsToStream(new FileOutputStream(mTempFile), recordBooleanProto, recordLinearProto,
-                recordBooleanProto);
-
-        // Cannot bind to service using real connection since we need to inject test file name.
-        MetricsBridgeService service = new MetricsBridgeService(mTempFile);
-        // Simulate starting the service by calling onCreate()
-        service.onCreate();
-
-        IBinder binder = service.onBind(null);
-        IMetricsBridgeService stub = IMetricsBridgeService.Stub.asInterface(binder);
-        stub.recordMetrics(recordBooleanProto.toByteArray());
-        List<byte[]> retrievedDataList = stub.retrieveNonembeddedMetrics();
-
-        byte[][] expectedData = new byte[][] {recordBooleanProto.toByteArray(),
-                recordLinearProto.toByteArray(), recordBooleanProto.toByteArray(),
-                PARSING_LOG_RESULT_SUCCESS_RECORD, recordBooleanProto.toByteArray(),
-                RETRIEVE_METRICS_TASK_STATUS_SUCCESS_RECORD};
-
-        // Assert file is deleted after the retrieve call
-        Assert.assertFalse(
-                "file should be deleted after retrieve metrics call", mTempFile.exists());
-        Assert.assertNotNull("retrieved byte data from the service is null", retrievedDataList);
-        Assert.assertArrayEquals("retrieved byte data is different from the expected data",
-                expectedData, retrievedDataList.toArray());
-    }
-
     @Test
     @MediumTest
     // Test sending data to the service and retrieving it back.
@@ -229,12 +94,4 @@
                     retrievedDataList.toArray());
         }
     }
-
-    private static void writeRecordsToStream(OutputStream os, HistogramRecord... records)
-            throws IOException {
-        for (HistogramRecord record : records) {
-            record.writeDelimitedTo(os);
-        }
-        os.close();
-    }
 }
\ No newline at end of file
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/services/MetricsBridgeServiceUnitTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/services/MetricsBridgeServiceUnitTest.java
new file mode 100644
index 0000000..d73916a
--- /dev/null
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/services/MetricsBridgeServiceUnitTest.java
@@ -0,0 +1,178 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.android_webview.test.services;
+
+import static org.chromium.android_webview.test.OnlyRunIn.ProcessMode.SINGLE_PROCESS;
+
+import android.os.IBinder;
+
+import androidx.test.filters.MediumTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.android_webview.common.services.IMetricsBridgeService;
+import org.chromium.android_webview.proto.MetricsBridgeRecords.HistogramRecord;
+import org.chromium.android_webview.proto.MetricsBridgeRecords.HistogramRecord.RecordType;
+import org.chromium.android_webview.services.MetricsBridgeService;
+import org.chromium.android_webview.test.AwActivityTestRule;
+import org.chromium.android_webview.test.AwJUnit4ClassRunner;
+import org.chromium.android_webview.test.OnlyRunIn;
+import org.chromium.base.FileUtils;
+import org.chromium.base.test.util.Batch;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.concurrent.FutureTask;
+
+/**
+ * Instrumentation tests for MetricsBridgeService. These tests are batched as UNIT_TESTS because
+ * they don't actually launch any services or other components.
+ */
+@RunWith(AwJUnit4ClassRunner.class)
+@OnlyRunIn(SINGLE_PROCESS)
+@Batch(Batch.UNIT_TESTS)
+public class MetricsBridgeServiceUnitTest {
+    public static final byte[] PARSING_LOG_RESULT_SUCCESS_RECORD =
+            HistogramRecord.newBuilder()
+                    .setRecordType(RecordType.HISTOGRAM_LINEAR)
+                    .setHistogramName("Android.WebView.NonEmbeddedMetrics.ParsingLogResult")
+                    .setSample(MetricsBridgeService.ParsingLogResult.SUCCESS)
+                    .setMin(1)
+                    .setMax(MetricsBridgeService.ParsingLogResult.COUNT)
+                    .setNumBuckets(MetricsBridgeService.ParsingLogResult.COUNT + 1)
+                    .build()
+                    .toByteArray();
+
+    public static final byte[] RETRIEVE_METRICS_TASK_STATUS_SUCCESS_RECORD =
+            HistogramRecord.newBuilder()
+                    .setRecordType(RecordType.HISTOGRAM_LINEAR)
+                    .setHistogramName(
+                            "Android.WebView.NonEmbeddedMetrics.RetrieveMetricsTaskStatus")
+                    .setSample(MetricsBridgeService.RetrieveMetricsTaskStatus.SUCCESS)
+                    .setMin(1)
+                    .setMax(MetricsBridgeService.RetrieveMetricsTaskStatus.COUNT)
+                    .setNumBuckets(MetricsBridgeService.RetrieveMetricsTaskStatus.COUNT + 1)
+                    .build()
+                    .toByteArray();
+
+    private File mTempFile;
+
+    @Before
+    public void setUp() throws IOException {
+        mTempFile = File.createTempFile("test_webview_metrics_bridge_logs", null);
+    }
+
+    @After
+    public void tearDown() {
+        if (mTempFile.exists()) {
+            Assert.assertTrue("Failed to delete \"" + mTempFile + "\"", mTempFile.delete());
+        }
+    }
+
+    @Test
+    @MediumTest
+    // Test that the service saves metrics records to file
+    public void testSaveToFile() throws Throwable {
+        HistogramRecord recordBooleanProto = HistogramRecord.newBuilder()
+                                                     .setRecordType(RecordType.HISTOGRAM_BOOLEAN)
+                                                     .setHistogramName("testSaveToFile.boolean")
+                                                     .setSample(1)
+                                                     .build();
+        HistogramRecord recordLinearProto = HistogramRecord.newBuilder()
+                                                    .setRecordType(RecordType.HISTOGRAM_LINEAR)
+                                                    .setHistogramName("testSaveToFile.linear")
+                                                    .setSample(123)
+                                                    .setMin(1)
+                                                    .setMax(1000)
+                                                    .setNumBuckets(50)
+                                                    .build();
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        writeRecordsToStream(out, recordBooleanProto, recordLinearProto, recordBooleanProto);
+        byte[] expectedData = out.toByteArray();
+
+        // Cannot bind to service using real connection since we need to inject test file name.
+        MetricsBridgeService service = new MetricsBridgeService(mTempFile);
+        // Simulate starting the service by calling onCreate()
+        service.onCreate();
+
+        IBinder binder = service.onBind(null);
+        IMetricsBridgeService stub = IMetricsBridgeService.Stub.asInterface(binder);
+        stub.recordMetrics(recordBooleanProto.toByteArray());
+        stub.recordMetrics(recordLinearProto.toByteArray());
+        stub.recordMetrics(recordBooleanProto.toByteArray());
+
+        // Block until all tasks are finished to make sure all records are written to file.
+        FutureTask<Object> blockTask = service.addTaskToBlock();
+        AwActivityTestRule.waitForFuture(blockTask);
+
+        byte[] resultData = FileUtils.readStream(new FileInputStream(mTempFile));
+        Assert.assertArrayEquals(
+                "byte data from file is different from the expected proto byte data", expectedData,
+                resultData);
+    }
+
+    @Test
+    @MediumTest
+    // Test that service recovers saved data from file, appends new records to it and
+    // clears the file after a retrieve call.
+    public void testRetrieveFromFile() throws Throwable {
+        HistogramRecord recordBooleanProto =
+                HistogramRecord.newBuilder()
+                        .setRecordType(RecordType.HISTOGRAM_BOOLEAN)
+                        .setHistogramName("testRecoverFromFile.boolean")
+                        .setSample(1)
+                        .build();
+        HistogramRecord recordLinearProto = HistogramRecord.newBuilder()
+                                                    .setRecordType(RecordType.HISTOGRAM_LINEAR)
+                                                    .setHistogramName("testRecoverFromFile.linear")
+                                                    .setSample(123)
+                                                    .setMin(1)
+                                                    .setMax(1000)
+                                                    .setNumBuckets(50)
+                                                    .build();
+        // write Initial proto data To File
+        writeRecordsToStream(new FileOutputStream(mTempFile), recordBooleanProto, recordLinearProto,
+                recordBooleanProto);
+
+        // Cannot bind to service using real connection since we need to inject test file name.
+        MetricsBridgeService service = new MetricsBridgeService(mTempFile);
+        // Simulate starting the service by calling onCreate()
+        service.onCreate();
+
+        IBinder binder = service.onBind(null);
+        IMetricsBridgeService stub = IMetricsBridgeService.Stub.asInterface(binder);
+        stub.recordMetrics(recordBooleanProto.toByteArray());
+        List<byte[]> retrievedDataList = stub.retrieveNonembeddedMetrics();
+
+        byte[][] expectedData = new byte[][] {recordBooleanProto.toByteArray(),
+                recordLinearProto.toByteArray(), recordBooleanProto.toByteArray(),
+                PARSING_LOG_RESULT_SUCCESS_RECORD, recordBooleanProto.toByteArray(),
+                RETRIEVE_METRICS_TASK_STATUS_SUCCESS_RECORD};
+
+        // Assert file is deleted after the retrieve call
+        Assert.assertFalse(
+                "file should be deleted after retrieve metrics call", mTempFile.exists());
+        Assert.assertNotNull("retrieved byte data from the service is null", retrievedDataList);
+        Assert.assertArrayEquals("retrieved byte data is different from the expected data",
+                expectedData, retrievedDataList.toArray());
+    }
+
+    private static void writeRecordsToStream(OutputStream os, HistogramRecord... records)
+            throws IOException {
+        for (HistogramRecord record : records) {
+            record.writeDelimitedTo(os);
+        }
+        os.close();
+    }
+}
\ No newline at end of file
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/services/MinidumpUploadJobTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/services/MinidumpUploadJobTest.java
index 925d83b..f24ffba5 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/services/MinidumpUploadJobTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/services/MinidumpUploadJobTest.java
@@ -44,6 +44,9 @@
 /**
  * Instrumentation tests for WebView's implementation of MinidumpUploaderDelegate, and the
  * interoperability of WebView's minidump-copying and minidump-uploading logic.
+ *
+ * These tests loads native library and mark the process as a browser process, it's safer to
+ * leave them unbatched to avoid possible state leaking between tests.
  */
 @RunWith(AwJUnit4ClassRunner.class)
 @OnlyRunIn(SINGLE_PROCESS)
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/services/VariationsSeedServerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/services/VariationsSeedServerTest.java
index 0a4a761..040a529 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/services/VariationsSeedServerTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/services/VariationsSeedServerTest.java
@@ -37,7 +37,8 @@
 import java.util.concurrent.TimeoutException;
 
 /**
- * Test VariationsSeedServer.
+ * Test VariationsSeedServer. These tests are not batched to make sure all unbinded services are
+ * properly killed between tests.
  */
 @RunWith(AwJUnit4ClassRunner.class)
 @OnlyRunIn(SINGLE_PROCESS)
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java
index a6303e0..1360f87 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java
@@ -38,7 +38,8 @@
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 
 /**
- * Test VisualStateCallback when render process is gone.
+ * Test VisualStateCallback when render process is gone. Test is not batched because it tests
+ * behaviour in multiprocesses.
  */
 @RunWith(AwJUnit4ClassRunner.class)
 public class VisualStateCallbackTest {
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index e7f9fd2..335a8f8 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -330,6 +330,7 @@
     "../javatests/src/org/chromium/android_webview/test/devui/util/WebViewCrashLogParserTest.java",
     "../javatests/src/org/chromium/android_webview/test/services/CrashReceiverServiceTest.java",
     "../javatests/src/org/chromium/android_webview/test/services/MetricsBridgeServiceTest.java",
+    "../javatests/src/org/chromium/android_webview/test/services/MetricsBridgeServiceUnitTest.java",
     "../javatests/src/org/chromium/android_webview/test/services/MinidumpUploadJobTest.java",
     "../javatests/src/org/chromium/android_webview/test/services/MockMetricsBridgeService.java",
     "../javatests/src/org/chromium/android_webview/test/services/MockVariationsSeedServer.java",
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 8cd6d77..8bebcd5 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -935,6 +935,8 @@
     "system/enterprise/enterprise_domain_observer.h",
     "system/gesture_education/gesture_education_notification_controller.cc",
     "system/gesture_education/gesture_education_notification_controller.h",
+    "system/holding_space/holding_space_color_provider_impl.cc",
+    "system/holding_space/holding_space_color_provider_impl.h",
     "system/holding_space/holding_space_item_chip_view.cc",
     "system/holding_space/holding_space_item_chip_view.h",
     "system/holding_space/holding_space_item_chips_container.cc",
diff --git a/ash/in_session_auth/in_session_auth_dialog.cc b/ash/in_session_auth/in_session_auth_dialog.cc
index fc691996..6ccb033 100644
--- a/ash/in_session_auth/in_session_auth_dialog.cc
+++ b/ash/in_session_auth/in_session_auth_dialog.cc
@@ -18,55 +18,37 @@
 
 // The initial height does nothing except determining the vertical position of
 // the dialog, since the dialog is centered with the initial height.
-constexpr gfx::Size kDefaultSize(340, 490);
 constexpr int kCornerRadius = 12;
 
-class AuthDialogWidgetDelegate : public views::WidgetDelegate {
- public:
-  AuthDialogWidgetDelegate() {
-    SetOwnedByWidget(true);
-    SetModalType(ui::MODAL_TYPE_SYSTEM);
-  }
-  AuthDialogWidgetDelegate(const AuthDialogWidgetDelegate&) = delete;
-  AuthDialogWidgetDelegate& operator=(const AuthDialogWidgetDelegate&) = delete;
-  ~AuthDialogWidgetDelegate() override = default;
-
-  // views::WidgetDelegate:
-  views::View* GetInitiallyFocusedView() override {
-    return GetWidget()->GetContentsView();
-  }
-};
-
-std::unique_ptr<views::Widget> CreateAuthDialogWidget(aura::Window* parent) {
+std::unique_ptr<views::Widget> CreateAuthDialogWidget(
+    std::unique_ptr<views::View> contents_view) {
   views::Widget::InitParams params(
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params.delegate = new AuthDialogWidgetDelegate();
+  params.delegate = new views::WidgetDelegate();
   params.show_state = ui::SHOW_STATE_NORMAL;
-  params.parent = parent;
+  params.parent = nullptr;
   params.name = "AuthDialogWidget";
   params.shadow_type = views::Widget::InitParams::ShadowType::kDrop;
   params.shadow_elevation = 3;
-  gfx::Rect bounds = display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
-  bounds.ClampToCenteredSize(kDefaultSize);
-  params.bounds = bounds;
+
+  params.delegate->SetInitiallyFocusedView(contents_view.get());
+  params.delegate->SetModalType(ui::MODAL_TYPE_SYSTEM);
+  params.delegate->SetOwnedByWidget(true);
 
   std::unique_ptr<views::Widget> widget = std::make_unique<views::Widget>();
   widget->Init(std::move(params));
   widget->SetVisibilityAnimationTransition(views::Widget::ANIMATE_NONE);
+  widget->SetContentsView(std::move(contents_view));
   return widget;
 }
 
 }  // namespace
 
-InSessionAuthDialog::InSessionAuthDialog(uint32_t auth_methods) {
-  widget_ = CreateAuthDialogWidget(nullptr);
-  contents_view_ = widget_->SetContentsView(
+InSessionAuthDialog::InSessionAuthDialog(uint32_t auth_methods)
+    : auth_methods_(auth_methods) {
+  widget_ = CreateAuthDialogWidget(
       std::make_unique<AuthDialogContentsView>(auth_methods));
-  gfx::Rect bound = widget_->GetWindowBoundsInScreen();
-  // Calculate initial height based on which child views are shown.
-  bound.set_height(contents_view_->GetPreferredSize().height());
-  widget_->SetBounds(bound);
 
   aura::Window* window = widget_->GetNativeWindow();
   rounded_corner_decorator_ = std::make_unique<RoundedCornerDecorator>(
@@ -78,8 +60,7 @@
 InSessionAuthDialog::~InSessionAuthDialog() = default;
 
 uint32_t InSessionAuthDialog::GetAuthMethods() const {
-  DCHECK(contents_view_);
-  return contents_view_->auth_methods();
+  return auth_methods_;
 }
 
 }  // namespace ash
diff --git a/ash/in_session_auth/in_session_auth_dialog.h b/ash/in_session_auth/in_session_auth_dialog.h
index c56b06b..26a3cbd 100644
--- a/ash/in_session_auth/in_session_auth_dialog.h
+++ b/ash/in_session_auth/in_session_auth_dialog.h
@@ -15,7 +15,6 @@
 
 namespace ash {
 
-class AuthDialogContentsView;
 class RoundedCornerDecorator;
 
 // InSessionAuthDialog gets instantiated on every request to show
@@ -41,7 +40,7 @@
 
   // Pointer to the contents view. Used to query and update the set of available
   // auth methods.
-  AuthDialogContentsView* contents_view_ = nullptr;
+  const uint32_t auth_methods_;
   std::unique_ptr<RoundedCornerDecorator> rounded_corner_decorator_;
 };
 
diff --git a/ash/login/ui/login_test_base.cc b/ash/login/ui/login_test_base.cc
index a773f832..ee7688be 100644
--- a/ash/login/ui/login_test_base.cc
+++ b/ash/login/ui/login_test_base.cc
@@ -20,27 +20,6 @@
 
 namespace ash {
 
-// A WidgetDelegate which ensures that |initially_focused| gets focus.
-class LoginTestBase::WidgetDelegate : public views::WidgetDelegate {
- public:
-  explicit WidgetDelegate(views::View* content) : content_(content) {
-    SetOwnedByWidget(true);
-  }
-  ~WidgetDelegate() override = default;
-
-  // views::WidgetDelegate:
-  views::View* GetInitiallyFocusedView() override { return content_; }
-  views::Widget* GetWidget() override { return content_->GetWidget(); }
-  const views::Widget* GetWidget() const override {
-    return content_->GetWidget();
-  }
-
- private:
-  views::View* content_;
-
-  DISALLOW_COPY_AND_ASSIGN(WidgetDelegate);
-};
-
 LoginTestBase::LoginTestBase() = default;
 
 LoginTestBase::~LoginTestBase() = default;
@@ -76,7 +55,10 @@
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.bounds = gfx::Rect(0, 0, 800, 800);
-  params.delegate = new WidgetDelegate(content);
+
+  params.delegate = new views::WidgetDelegate();
+  params.delegate->SetInitiallyFocusedView(content);
+  params.delegate->SetOwnedByWidget(true);
 
   // Set the widget to the lock screen container, since a test may change the
   // session state to locked, which will hide all widgets not associated with
diff --git a/ash/login/ui/login_test_base.h b/ash/login/ui/login_test_base.h
index 0588165..901518b 100644
--- a/ash/login/ui/login_test_base.h
+++ b/ash/login/ui/login_test_base.h
@@ -80,8 +80,6 @@
   void TearDown() override;
 
  private:
-  class WidgetDelegate;
-
   // The widget created using |ShowWidgetWithContent|.
   std::unique_ptr<views::Widget> widget_;
 
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index 17029703..4ac05b3 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -140,6 +140,8 @@
     "frame_utils.h",
     "gesture_action_type.h",
     "holding_space/holding_space_client.h",
+    "holding_space/holding_space_color_provider.cc",
+    "holding_space/holding_space_color_provider.h",
     "holding_space/holding_space_constants.h",
     "holding_space/holding_space_controller.cc",
     "holding_space/holding_space_controller.h",
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index 42021d8..9dac15b3 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -86,7 +86,7 @@
     "NotificationExpansionAnimation", base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kNotificationExperimentalShortTimeouts{
-    "NotificationExperimentalShortTimeouts", base::FEATURE_DISABLED_BY_DEFAULT};
+    "NotificationExperimentalShortTimeouts", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kNotificationScrollBar{"NotificationScrollBar",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ash/public/cpp/caption_buttons/frame_caption_button_container_view.cc b/ash/public/cpp/caption_buttons/frame_caption_button_container_view.cc
index dbe2f50..782fc16 100644
--- a/ash/public/cpp/caption_buttons/frame_caption_button_container_view.cc
+++ b/ash/public/cpp/caption_buttons/frame_caption_button_container_view.cc
@@ -10,10 +10,10 @@
 #include "ash/public/cpp/caption_buttons/caption_button_model.h"
 #include "ash/public/cpp/caption_buttons/frame_size_button.h"
 #include "ash/public/cpp/caption_buttons/snap_controller.h"
-#include "ash/public/cpp/tablet_mode.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/numerics/ranges.h"
+#include "chromeos/ui/tablet_state.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -420,7 +420,7 @@
     }
   } else if (sender == close_button_) {
     frame_->Close();
-    if (TabletMode::Get()->InTabletMode())
+    if (chromeos::TabletState::Get()->InTabletMode())
       RecordAction(UserMetricsAction("Tablet_WindowCloseFromCaptionButton"));
     else
       RecordAction(UserMetricsAction("CloseButton_Clk"));
diff --git a/ash/public/cpp/holding_space/holding_space_color_provider.cc b/ash/public/cpp/holding_space/holding_space_color_provider.cc
new file mode 100644
index 0000000..346abc7
--- /dev/null
+++ b/ash/public/cpp/holding_space/holding_space_color_provider.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 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 "ash/public/cpp/holding_space/holding_space_color_provider.h"
+
+#include "base/check_op.h"
+
+namespace ash {
+
+namespace {
+
+// The singleton instance.
+HoldingSpaceColorProvider* g_instance = nullptr;
+
+}  // namespace
+
+HoldingSpaceColorProvider::~HoldingSpaceColorProvider() {
+  DCHECK_EQ(g_instance, this);
+  g_instance = nullptr;
+}
+
+// static
+HoldingSpaceColorProvider* HoldingSpaceColorProvider::Get() {
+  return g_instance;
+}
+
+HoldingSpaceColorProvider::HoldingSpaceColorProvider() {
+  DCHECK_EQ(g_instance, nullptr);
+  g_instance = this;
+}
+
+}  // namespace ash
diff --git a/ash/public/cpp/holding_space/holding_space_color_provider.h b/ash/public/cpp/holding_space/holding_space_color_provider.h
new file mode 100644
index 0000000..0a78d82
--- /dev/null
+++ b/ash/public/cpp/holding_space/holding_space_color_provider.h
@@ -0,0 +1,30 @@
+// Copyright 2020 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 ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_COLOR_PROVIDER_H_
+#define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_COLOR_PROVIDER_H_
+
+#include "ash/public/cpp/ash_public_export.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace ash {
+
+// The interface for the singleton which provides colors to holding space.
+class ASH_PUBLIC_EXPORT HoldingSpaceColorProvider {
+ public:
+  virtual ~HoldingSpaceColorProvider();
+
+  // Returns the singleton instance.
+  static HoldingSpaceColorProvider* Get();
+
+  // Returns the color to be used for file icons.
+  virtual SkColor GetFileIconColor() const = 0;
+
+ protected:
+  HoldingSpaceColorProvider();
+};
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_COLOR_PROVIDER_H_
diff --git a/ash/public/cpp/holding_space/holding_space_controller.cc b/ash/public/cpp/holding_space/holding_space_controller.cc
index 7f4a828..b444a565 100644
--- a/ash/public/cpp/holding_space/holding_space_controller.cc
+++ b/ash/public/cpp/holding_space/holding_space_controller.cc
@@ -4,6 +4,7 @@
 
 #include "ash/public/cpp/holding_space/holding_space_controller.h"
 
+#include "ash/public/cpp/holding_space/holding_space_color_provider.h"
 #include "ash/public/cpp/holding_space/holding_space_controller_observer.h"
 #include "ash/public/cpp/session/session_controller.h"
 #include "base/check.h"
@@ -16,7 +17,9 @@
 
 }  // namespace
 
-HoldingSpaceController::HoldingSpaceController() {
+HoldingSpaceController::HoldingSpaceController(
+    std::unique_ptr<HoldingSpaceColorProvider> color_provider)
+    : color_provider_(std::move(color_provider)) {
   CHECK(!g_instance);
   g_instance = this;
 
diff --git a/ash/public/cpp/holding_space/holding_space_controller.h b/ash/public/cpp/holding_space/holding_space_controller.h
index 14ce07af..66430a7012 100644
--- a/ash/public/cpp/holding_space/holding_space_controller.h
+++ b/ash/public/cpp/holding_space/holding_space_controller.h
@@ -5,6 +5,8 @@
 #ifndef ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_CONTROLLER_H_
 #define ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_CONTROLLER_H_
 
+#include <memory>
+
 #include "ash/public/cpp/ash_public_export.h"
 #include "ash/public/cpp/session/session_observer.h"
 #include "base/observer_list.h"
@@ -13,6 +15,7 @@
 namespace ash {
 
 class HoldingSpaceClient;
+class HoldingSpaceColorProvider;
 class HoldingSpaceControllerObserver;
 class HoldingSpaceModel;
 
@@ -23,7 +26,7 @@
 // using HoldingSpaceController::Get().
 class ASH_PUBLIC_EXPORT HoldingSpaceController : public SessionObserver {
  public:
-  HoldingSpaceController();
+  explicit HoldingSpaceController(std::unique_ptr<HoldingSpaceColorProvider>);
   HoldingSpaceController(const HoldingSpaceController& other) = delete;
   HoldingSpaceController& operator=(const HoldingSpaceController& other) =
       delete;
@@ -53,6 +56,9 @@
   void SetClient(HoldingSpaceClient* client);
   void SetModel(HoldingSpaceModel* model);
 
+  // The singleton provider for colors used by holding space.
+  std::unique_ptr<HoldingSpaceColorProvider> color_provider_;
+
   // The currently active holding space client, set by `SetClient()`.
   HoldingSpaceClient* client_ = nullptr;
 
diff --git a/ash/shell.cc b/ash/shell.cc
index 2ab1aa69..83fc1dc 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -109,6 +109,7 @@
 #include "ash/system/brightness/brightness_controller_chromeos.h"
 #include "ash/system/brightness_control_delegate.h"
 #include "ash/system/caps_lock_notification_controller.h"
+#include "ash/system/holding_space/holding_space_color_provider_impl.h"
 #include "ash/system/keyboard_brightness/keyboard_brightness_controller.h"
 #include "ash/system/keyboard_brightness_control_delegate.h"
 #include "ash/system/locale/locale_update_controller_impl.h"
@@ -1250,8 +1251,10 @@
         std::make_unique<DisplayAlignmentController>();
   }
 
-  if (features::IsTemporaryHoldingSpaceEnabled())
-    holding_space_controller_ = std::make_unique<HoldingSpaceController>();
+  if (features::IsTemporaryHoldingSpaceEnabled()) {
+    holding_space_controller_ = std::make_unique<HoldingSpaceController>(
+        std::make_unique<HoldingSpaceColorProviderImpl>());
+  }
 
   for (auto& observer : shell_observers_)
     observer.OnShellInitialized();
diff --git a/ash/system/holding_space/holding_space_color_provider_impl.cc b/ash/system/holding_space/holding_space_color_provider_impl.cc
new file mode 100644
index 0000000..a881e31
--- /dev/null
+++ b/ash/system/holding_space/holding_space_color_provider_impl.cc
@@ -0,0 +1,20 @@
+// Copyright 2020 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 "ash/system/holding_space/holding_space_color_provider_impl.h"
+
+#include "ash/style/ash_color_provider.h"
+
+namespace ash {
+
+HoldingSpaceColorProviderImpl::HoldingSpaceColorProviderImpl() = default;
+
+HoldingSpaceColorProviderImpl::~HoldingSpaceColorProviderImpl() = default;
+
+SkColor HoldingSpaceColorProviderImpl::GetFileIconColor() const {
+  return AshColorProvider::Get()->GetContentLayerColor(
+      AshColorProvider::ContentLayerType::kIconColorPrimary);
+}
+
+}  // namespace ash
diff --git a/ash/system/holding_space/holding_space_color_provider_impl.h b/ash/system/holding_space/holding_space_color_provider_impl.h
new file mode 100644
index 0000000..282e4d3
--- /dev/null
+++ b/ash/system/holding_space/holding_space_color_provider_impl.h
@@ -0,0 +1,28 @@
+// Copyright 2020 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 ASH_SYSTEM_HOLDING_SPACE_HOLDING_SPACE_COLOR_PROVIDER_IMPL_H_
+#define ASH_SYSTEM_HOLDING_SPACE_HOLDING_SPACE_COLOR_PROVIDER_IMPL_H_
+
+#include "ash/public/cpp/holding_space/holding_space_color_provider.h"
+
+namespace ash {
+
+// The implementation of the singleton which provides colors to holding space.
+class HoldingSpaceColorProviderImpl : public HoldingSpaceColorProvider {
+ public:
+  HoldingSpaceColorProviderImpl();
+  HoldingSpaceColorProviderImpl(const HoldingSpaceColorProviderImpl&) = delete;
+  HoldingSpaceColorProviderImpl& operator=(
+      const HoldingSpaceColorProviderImpl&) = delete;
+  ~HoldingSpaceColorProviderImpl() override;
+
+ private:
+  // HoldingSpaceColorProvider:
+  SkColor GetFileIconColor() const override;
+};
+
+}  // namespace ash
+
+#endif  // ASH_PUBLIC_CPP_HOLDING_SPACE_HOLDING_SPACE_COLOR_PROVIDER_H_
diff --git a/ash/system/phonehub/quick_action_item.h b/ash/system/phonehub/quick_action_item.h
index bc5304a9..910abb6 100644
--- a/ash/system/phonehub/quick_action_item.h
+++ b/ash/system/phonehub/quick_action_item.h
@@ -16,7 +16,8 @@
 namespace ash {
 
 // A toggle button with labels used in the quick action view.
-class QuickActionItem : public views::View, public views::ButtonListener {
+class ASH_EXPORT QuickActionItem : public views::View,
+                                   public views::ButtonListener {
  public:
   class Delegate {
    public:
diff --git a/ash/system/phonehub/quick_actions_view_unittest.cc b/ash/system/phonehub/quick_actions_view_unittest.cc
index 99a8e553..ed8f022 100644
--- a/ash/system/phonehub/quick_actions_view_unittest.cc
+++ b/ash/system/phonehub/quick_actions_view_unittest.cc
@@ -22,11 +22,15 @@
   DummyEvent() : Event(ui::ET_UNKNOWN, base::TimeTicks(), 0) {}
 };
 
+constexpr base::TimeDelta kWaitForRequestTimeout =
+    base::TimeDelta::FromSeconds(10);
+
 }  // namespace
 
 class QuickActionsViewTest : public AshTestBase {
  public:
-  QuickActionsViewTest() = default;
+  QuickActionsViewTest()
+      : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
   ~QuickActionsViewTest() override = default;
 
   // AshTestBase:
@@ -105,6 +109,22 @@
   actions_view()->silence_phone_for_testing()->ButtonPressed(nullptr,
                                                              DummyEvent());
   EXPECT_FALSE(dnd_controller()->IsDndEnabled());
+
+  // Test the error state.
+  dnd_controller()->SetShouldRequestFail(true);
+  actions_view()->silence_phone_for_testing()->ButtonPressed(nullptr,
+                                                             DummyEvent());
+
+  // In error state, do not disturb is disabled but the button should still be
+  // on after being pressed.
+  EXPECT_FALSE(dnd_controller()->IsDndEnabled());
+  EXPECT_TRUE(actions_view()->silence_phone_for_testing()->IsToggled());
+
+  // After a certain time, the button should be corrected to be off.
+  task_environment()->FastForwardBy(kWaitForRequestTimeout);
+  EXPECT_FALSE(actions_view()->silence_phone_for_testing()->IsToggled());
+
+  dnd_controller()->SetShouldRequestFail(false);
 }
 
 TEST_F(QuickActionsViewTest, LocatePhoneToggle) {
diff --git a/ash/system/phonehub/silence_phone_quick_action_controller.cc b/ash/system/phonehub/silence_phone_quick_action_controller.cc
index 90d9987..6b7701f 100644
--- a/ash/system/phonehub/silence_phone_quick_action_controller.cc
+++ b/ash/system/phonehub/silence_phone_quick_action_controller.cc
@@ -7,10 +7,20 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/phonehub/quick_action_item.h"
+#include "base/timer/timer.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace ash {
 
+namespace {
+
+// Time to wait until we check the state of the phone to prevent showing wrong
+// state
+constexpr base::TimeDelta kWaitForRequestTimeout =
+    base::TimeDelta::FromSeconds(10);
+
+}  // namespace
+
 SilencePhoneQuickActionController::SilencePhoneQuickActionController(
     chromeos::phonehub::DoNotDisturbController* dnd_controller)
     : dnd_controller_(dnd_controller) {
@@ -31,18 +41,32 @@
 }
 
 void SilencePhoneQuickActionController::OnButtonPressed(bool is_now_enabled) {
-  SetState(ActionState::kConnecting);
+  requested_state_ = is_now_enabled ? ActionState::kOff : ActionState::kOn;
+  SetItemState(requested_state_.value());
+
+  check_requested_state_timer_ = std::make_unique<base::OneShotTimer>();
+  check_requested_state_timer_->Start(
+      FROM_HERE, kWaitForRequestTimeout,
+      base::BindOnce(&SilencePhoneQuickActionController::CheckRequestedState,
+                     base::Unretained(this)));
+
   dnd_controller_->RequestNewDoNotDisturbState(!is_now_enabled);
-  // TODO(leandre): Add a timer to switch back to off state after connecting
-  // failed.
 }
 
 void SilencePhoneQuickActionController::OnDndStateChanged() {
-  dnd_controller_->IsDndEnabled() ? SetState(ActionState::kOn)
-                                  : SetState(ActionState::kOff);
+  state_ =
+      dnd_controller_->IsDndEnabled() ? ActionState::kOn : ActionState::kOff;
+  SetItemState(state_);
+
+  // If |requested_state_| correctly resembles the current state, reset it and
+  // the timer.
+  if (state_ == requested_state_) {
+    check_requested_state_timer_.reset();
+    requested_state_.reset();
+  }
 }
 
-void SilencePhoneQuickActionController::SetState(ActionState state) {
+void SilencePhoneQuickActionController::SetItemState(ActionState state) {
   bool icon_enabled;
   int state_text_id;
   int sub_label_text;
@@ -52,11 +76,6 @@
       state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_DISABLED_STATE_TOOLTIP;
       sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_OFF_STATE;
       break;
-    case ActionState::kConnecting:
-      icon_enabled = true;
-      state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_CONNECTING_STATE_TOOLTIP;
-      sub_label_text = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_CONNECTING_STATE;
-      break;
     case ActionState::kOn:
       icon_enabled = true;
       state_text_id = IDS_ASH_PHONE_HUB_QUICK_ACTIONS_ENABLED_STATE_TOOLTIP;
@@ -73,4 +92,14 @@
                                  item_->GetItemLabel(), tooltip_state));
 }
 
+void SilencePhoneQuickActionController::CheckRequestedState() {
+  // If the current state is different from the requested state, it means that
+  // we fail to change the state, so switch back to the original one.
+  if (state_ != requested_state_)
+    SetItemState(state_);
+
+  check_requested_state_timer_.reset();
+  requested_state_.reset();
+}
+
 }  // namespace ash
diff --git a/ash/system/phonehub/silence_phone_quick_action_controller.h b/ash/system/phonehub/silence_phone_quick_action_controller.h
index bd8c3bcb..38c2b8c 100644
--- a/ash/system/phonehub/silence_phone_quick_action_controller.h
+++ b/ash/system/phonehub/silence_phone_quick_action_controller.h
@@ -8,6 +8,10 @@
 #include "ash/system/phonehub/quick_action_controller_base.h"
 #include "chromeos/components/phonehub/do_not_disturb_controller.h"
 
+namespace base {
+class OneShotTimer;
+}  // namespace base
+
 namespace ash {
 
 // Controller of a quick action item that toggles silence phone mode.
@@ -33,13 +37,28 @@
  private:
   // All the possible states that the silence phone button can be viewed. Each
   // state has a corresponding icon, labels and tooltip view.
-  enum class ActionState { kOff, kConnecting, kOn };
+  enum class ActionState { kOff, kOn };
 
   // Set the item (including icon, label and tooltips) to a certain state.
-  void SetState(ActionState state);
+  void SetItemState(ActionState state);
+
+  // Check to see if the requested state is similar to current state of the
+  // phone. Make changes to item's state if necessary.
+  void CheckRequestedState();
 
   chromeos::phonehub::DoNotDisturbController* dnd_controller_ = nullptr;
   QuickActionItem* item_ = nullptr;
+
+  // Keep track the current state of the item.
+  ActionState state_;
+
+  // State that user requests when clicking the button.
+  base::Optional<ActionState> requested_state_;
+
+  // Timer that fires to prevent showing wrong state in the item. It will check
+  // if the requested state is similar to the current state after the button is
+  // pressed for a certain time.
+  std::unique_ptr<base::OneShotTimer> check_requested_state_timer_;
 };
 
 }  // namespace ash
diff --git a/ash/touch/touch_devices_controller.cc b/ash/touch/touch_devices_controller.cc
index 8c4e314..0b34ab4 100644
--- a/ash/touch/touch_devices_controller.cc
+++ b/ash/touch/touch_devices_controller.cc
@@ -21,7 +21,6 @@
 #include "components/prefs/pref_service.h"
 #include "ui/ozone/public/input_controller.h"
 #include "ui/ozone/public/ozone_platform.h"
-#include "ui/wm/core/cursor_manager.h"
 
 namespace ash {
 
@@ -173,23 +172,11 @@
 }
 
 void TouchDevicesController::UpdateTouchpadEnabled() {
-  bool enabled = GetTouchpadEnabled(TouchDeviceEnabledSource::GLOBAL) &&
-                 GetTouchpadEnabled(TouchDeviceEnabledSource::USER_PREF);
-  ui::InputController* input_controller =
-      ui::OzonePlatform::GetInstance()->GetInputController();
-  const bool old_value = input_controller->IsInternalTouchpadEnabled();
-  input_controller->SetInternalTouchpadEnabled(enabled);
-  if (old_value == input_controller->IsInternalTouchpadEnabled())
-    return;  // Value didn't actually change.
-
-  ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
-  if (!cursor_manager)
-    return;
-
-  if (enabled)
-    cursor_manager->ShowCursor();
-  else
-    cursor_manager->HideCursor();
+  ui::OzonePlatform::GetInstance()
+      ->GetInputController()
+      ->SetInternalTouchpadEnabled(
+          GetTouchpadEnabled(TouchDeviceEnabledSource::GLOBAL) &&
+          GetTouchpadEnabled(TouchDeviceEnabledSource::USER_PREF));
 }
 
 void TouchDevicesController::UpdateTouchscreenEnabled() {
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index b26da6f..ad1597d 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -54,6 +54,7 @@
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/gfx/geometry/vector3d_f.h"
 #include "ui/views/widget/widget.h"
+#include "ui/wm/core/cursor_manager.h"
 #include "ui/wm/core/window_util.h"
 
 namespace ash {
@@ -888,6 +889,7 @@
     VLOG(1) << "Exit tablet mode.";
 
     UpdateInternalInputDevicesEventBlocker();
+    Shell::Get()->cursor_manager()->ShowCursor();
   }
 }
 
@@ -1152,6 +1154,7 @@
   }
 
   UpdateInternalInputDevicesEventBlocker();
+  Shell::Get()->cursor_manager()->HideCursor();
 
   VLOG(1) << "Enter tablet mode.";
 }
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index 903a1bfc..172c1382 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -65,6 +65,7 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/vector3d_f.h"
 #include "ui/message_center/message_center.h"
+#include "ui/wm/core/cursor_manager.h"
 #include "ui/wm/core/window_util.h"
 
 namespace ash {
@@ -1069,6 +1070,19 @@
   EXPECT_TRUE(AreEventsBlocked());
 }
 
+// Test that the mouse cursor is hidden when entering tablet mode, and shown
+// when exiting tablet mode.
+TEST_P(TabletModeControllerTest, ShowAndHideMouseCursorTest) {
+  wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
+  EXPECT_TRUE(cursor_manager->IsCursorVisible());
+
+  tablet_mode_controller()->SetEnabledForTest(true);
+  EXPECT_FALSE(cursor_manager->IsCursorVisible());
+
+  tablet_mode_controller()->SetEnabledForTest(false);
+  EXPECT_TRUE(cursor_manager->IsCursorVisible());
+}
+
 class TabletModeControllerForceTabletModeTest
     : public TabletModeControllerTest {
  public:
diff --git a/base/allocator/partition_allocator/partition_lock.h b/base/allocator/partition_allocator/partition_lock.h
index f28acefe..263f48d 100644
--- a/base/allocator/partition_allocator/partition_lock.h
+++ b/base/allocator/partition_allocator/partition_lock.h
@@ -14,7 +14,7 @@
 #include "base/threading/platform_thread.h"
 #include "build/build_config.h"
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #include "base/allocator/partition_allocator/spinning_futex_linux.h"
 #endif
 
@@ -142,7 +142,7 @@
   }
 
  private:
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
   base::NoDestructor<SpinningFutex> lock_;
 #else
   // base::Lock is slower on the fast path than SpinLock, hence we still use it
diff --git a/base/allocator/partition_allocator/spinning_futex_linux.cc b/base/allocator/partition_allocator/spinning_futex_linux.cc
index 4944ff6..fa620d8 100644
--- a/base/allocator/partition_allocator/spinning_futex_linux.cc
+++ b/base/allocator/partition_allocator/spinning_futex_linux.cc
@@ -7,7 +7,7 @@
 #include "base/allocator/partition_allocator/partition_alloc_check.h"
 #include "build/build_config.h"
 
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
 
 #include <errno.h>
 #include <linux/futex.h>
@@ -70,4 +70,4 @@
 }  // namespace internal
 }  // namespace base
 
-#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
diff --git a/base/allocator/partition_allocator/spinning_futex_linux.h b/base/allocator/partition_allocator/spinning_futex_linux.h
index b7fd6df..795040dd 100644
--- a/base/allocator/partition_allocator/spinning_futex_linux.h
+++ b/base/allocator/partition_allocator/spinning_futex_linux.h
@@ -12,7 +12,7 @@
 #include "base/compiler_specific.h"
 #include "build/build_config.h"
 
-#if !(defined(OS_LINUX) || defined(OS_ANDROID))
+#if !(defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID))
 #error "Not supported"
 #endif
 
diff --git a/base/allocator/partition_allocator/thread_cache_unittest.cc b/base/allocator/partition_allocator/thread_cache_unittest.cc
index 70c7ee0..a6716af 100644
--- a/base/allocator/partition_allocator/thread_cache_unittest.cc
+++ b/base/allocator/partition_allocator/thread_cache_unittest.cc
@@ -27,7 +27,8 @@
 // on Windows 7 (at least). As long as it doesn't use something else on Windows,
 // disable the cache (and tests)
 #if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
-    !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) && defined(OS_LINUX)
+    !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) &&  \
+    (defined(OS_LINUX) || defined(OS_CHROMEOS))
 
 namespace base {
 namespace internal {
@@ -402,4 +403,5 @@
 }  // namespace base
 
 #endif  // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) &&
-        // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) && defined(OS_LINUX)
+        // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) &&
+        // (defined(OS_LINUX) || defined(OS_CHROMEOS))
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index 0fa50eb..6de4ea7 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -27,7 +27,9 @@
 _CHROMIUM_SRC = os.path.join(_FILE_DIR, os.pardir, os.pardir, os.pardir)
 _BUILD_ANDROID_GYP = os.path.join(_CHROMIUM_SRC, 'build', 'android', 'gyp')
 
-sys.path.append(_BUILD_ANDROID_GYP)
+# Item 0 of sys.path is the directory of the main file; item 1 is PYTHONPATH
+# (if set); item 2 is system libraries.
+sys.path.insert(1, _BUILD_ANDROID_GYP)
 
 from util import build_utils
 
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
index b8d6487..618e1e37 100644
--- a/base/debug/stack_trace.h
+++ b/base/debug/stack_trace.h
@@ -152,7 +152,7 @@
 // scanning area at the origin of the stack, wasting time and not finding any
 // frames (since Android libraries don't have frame pointers). Scanning is not
 // enabled on other posix platforms due to legacy reasons.
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 constexpr bool kEnableScanningByDefault = true;
 #else
 constexpr bool kEnableScanningByDefault = false;
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc
index 5010309..750cd731 100644
--- a/base/win/windows_version.cc
+++ b/base/win/windows_version.cc
@@ -13,6 +13,7 @@
 #include "base/check_op.h"
 #include "base/file_version_info_win.h"
 #include "base/files/file_path.h"
+#include "base/logging.h"
 #include "base/no_destructor.h"
 #include "base/notreached.h"
 #include "base/strings/string_util.h"
@@ -199,6 +200,16 @@
   return kernel32_version;
 }
 
+OSInfo::VersionNumber OSInfo::Kernel32VersionNumber() const {
+  DCHECK(Kernel32BaseVersion().components().size() == 4);
+  static const VersionNumber version = {
+      .major = Kernel32BaseVersion().components()[0],
+      .minor = Kernel32BaseVersion().components()[1],
+      .build = Kernel32BaseVersion().components()[2],
+      .patch = Kernel32BaseVersion().components()[3]};
+  return version;
+}
+
 // Retrieve a version from kernel32. This is useful because when running in
 // compatibility mode for a down-level version of the OS, the file version of
 // kernel32 will still be the "real" version.
diff --git a/base/win/windows_version.h b/base/win/windows_version.h
index 95bd9fc..872f8ae7 100644
--- a/base/win/windows_version.h
+++ b/base/win/windows_version.h
@@ -120,20 +120,42 @@
   // process.  This doesn't touch member state, so you can bypass the singleton.
   static WOW64Status GetWOW64StatusForProcess(HANDLE process_handle);
 
+  // Returns the OS Version as returned from a call to GetVersionEx().
   const Version& version() const { return version_; }
-  Version Kernel32Version() const;
-  base::Version Kernel32BaseVersion() const;
-  // The next two functions return arrays of values, [major, minor(, build)].
+
+  // Returns detailed version info containing major, minor, build and patch.
   const VersionNumber& version_number() const { return version_number_; }
+
+  // The Kernel32* set of functions return the OS version as determined by a
+  // call to VerQueryValue() on kernel32.dll. This avoids any running App Compat
+  // shims from manipulating the version reported.
+  Version Kernel32Version() const;
+  VersionNumber Kernel32VersionNumber() const;
+  base::Version Kernel32BaseVersion() const;
+
+  // Functions to determine Version Type (e.g. Enterprise/Home) and Service Pack
+  // value. See above for definitions of these values.
   const VersionType& version_type() const { return version_type_; }
   const ServicePack& service_pack() const { return service_pack_; }
   const std::string& service_pack_str() const { return service_pack_str_; }
+
+  // Returns the number of processors on the system.
   const int& processors() const { return processors_; }
+
+  // Returns the allocation granularity. See
+  // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info.
   const size_t& allocation_granularity() const {
     return allocation_granularity_;
   }
+
+  // Returns the WOW64 status of the running process. See above for definitions
+  // of the values.
   const WOW64Status& wow64_status() const { return wow64_status_; }
+
+  // Processor name as read from registry.
   std::string processor_model_name();
+
+  // Returns the "ReleaseId" (Windows 10 release number) from the registry.
   const std::string& release_id() const { return release_id_; }
 
  private:
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 193d518..a979b5e 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20201005.1.1
+0.20201005.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 193d518..a979b5e 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20201005.1.1
+0.20201005.2.1
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 0e3616c..47688e1 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -352,6 +352,7 @@
     "//chrome/browser/ui/android/favicon:java",
     "//chrome/browser/ui/android/native_page:java",
     "//chrome/browser/ui/messages/android:java",
+    "//chrome/browser/uid/android:java",
     "//chrome/browser/user_education:java",
     "//chrome/browser/util:java",
     "//chrome/browser/version:java",
@@ -828,6 +829,7 @@
     "//chrome/browser/ui/messages/android:junit",
     "//chrome/browser/user_education:java",
     "//chrome/browser/util:java",
+    "//chrome/browser/version:java",
     "//chrome/browser/video_tutorials:java",
     "//chrome/browser/video_tutorials/internal:junit",
     "//chrome/browser/xsurface:java",
@@ -843,6 +845,7 @@
     "//components/browser_ui/site_settings/android:java",
     "//components/browser_ui/util/android:java",
     "//components/browser_ui/widget/android:java",
+    "//components/content_capture/android:java",
     "//components/content_settings/android:content_settings_enums_java",
     "//components/dom_distiller/core/android:dom_distiller_core_java",
     "//components/embedder_support/android:browser_context_java",
@@ -962,6 +965,7 @@
   sources = chrome_test_java_sources
 
   deps = [
+    ":base_module_java",
     ":browser_java_test_support",
     ":chrome_app_java_resources",
     ":chrome_test_util_java",
@@ -1032,7 +1036,10 @@
     "//chrome/browser/ui/android/favicon:java",
     "//chrome/browser/ui/android/native_page:java",
     "//chrome/browser/ui/messages/android:java",
+    "//chrome/browser/uid/android:java",
+    "//chrome/browser/uid/android:javatests",
     "//chrome/browser/util:java",
+    "//chrome/browser/version:java",
     "//chrome/test:sync_integration_test_support_java",
     "//chrome/test/android:chrome_java_test_pagecontroller",
     "//chrome/test/android:chrome_java_test_support",
@@ -2031,6 +2038,7 @@
     "//android_webview:android_webview_java",
     "//base:base_java",
     "//chrome/android:chrome_java",
+    "//chrome/browser/version:java",
     "//content/public/android:content_java",
   ]
   sources =
@@ -2057,6 +2065,13 @@
   sources = [
     "java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java",
     "java/src/org/chromium/chrome/browser/base/SplitCompatApplication.java",
+    "java/src/org/chromium/chrome/browser/base/SplitCompatIntentService.java",
+    "java/src/org/chromium/chrome/browser/base/SplitCompatJobService.java",
+    "java/src/org/chromium/chrome/browser/base/SplitCompatService.java",
+    "java/src/org/chromium/chrome/browser/base/SplitCompatUtils.java",
+    "java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java",
+    "java/src/org/chromium/chrome/browser/notifications/NotificationJobService.java",
+    "java/src/org/chromium/chrome/browser/notifications/NotificationService.java",
   ]
   deps = [
     ":chrome_base_module_resources",
diff --git a/chrome/android/DEPS b/chrome/android/DEPS
index 177aa58..945413da 100644
--- a/chrome/android/DEPS
+++ b/chrome/android/DEPS
@@ -22,6 +22,7 @@
   "+chrome/browser/ui/android/favicon/java",
   "+chrome/browser/ui/android/native_page",
   "+chrome/browser/ui/messages/android",
+  "+chrome/browser/uid/android",
   "+chrome/browser/user_education",
   "+chrome/browser/util/android/java",
   "+chrome/browser/version",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 5084fadc..8d234c6 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -27,7 +27,6 @@
   "java/src/org/chromium/chrome/browser/ChromeStringConstants.java",
   "java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java",
   "java/src/org/chromium/chrome/browser/ChromeTabbedActivity2.java",
-  "java/src/org/chromium/chrome/browser/ChromeVersionInfo.java",
   "java/src/org/chromium/chrome/browser/ChromeWindow.java",
   "java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java",
   "java/src/org/chromium/chrome/browser/DefaultBrowserInfo2.java",
@@ -526,7 +525,7 @@
   "java/src/org/chromium/chrome/browser/download/DownloadActivity.java",
   "java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java",
   "java/src/org/chromium/chrome/browser/download/DownloadController.java",
-  "java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java",
+  "java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceImpl.java",
   "java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManager.java",
   "java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceObservers.java",
   "java/src/org/chromium/chrome/browser/download/DownloadInfoBarController.java",
@@ -798,10 +797,8 @@
   "java/src/org/chromium/chrome/browser/homepage/settings/HomepageMetricsEnums.java",
   "java/src/org/chromium/chrome/browser/homepage/settings/HomepageSettings.java",
   "java/src/org/chromium/chrome/browser/homepage/settings/RadioButtonGroupHomepagePreference.java",
-  "java/src/org/chromium/chrome/browser/identity/SettingsSecureBasedIdentificationGenerator.java",
   "java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGenerator.java",
   "java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactory.java",
-  "java/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGenerator.java",
   "java/src/org/chromium/chrome/browser/identity_disc/IdentityDiscController.java",
   "java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java",
   "java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationPresenceController.java",
@@ -960,9 +957,9 @@
   "java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java",
   "java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java",
   "java/src/org/chromium/chrome/browser/notifications/NotificationIntentInterceptor.java",
-  "java/src/org/chromium/chrome/browser/notifications/NotificationJobService.java",
+  "java/src/org/chromium/chrome/browser/notifications/NotificationJobServiceImpl.java",
   "java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java",
-  "java/src/org/chromium/chrome/browser/notifications/NotificationService.java",
+  "java/src/org/chromium/chrome/browser/notifications/NotificationServiceImpl.java",
   "java/src/org/chromium/chrome/browser/notifications/NotificationSettingsBridge.java",
   "java/src/org/chromium/chrome/browser/notifications/NotificationSystemStatusUtil.java",
   "java/src/org/chromium/chrome/browser/notifications/NotificationTriggerBackgroundTask.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni
index 468658f4..e29ec44f 100644
--- a/chrome/android/chrome_junit_test_java_sources.gni
+++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -48,6 +48,7 @@
   "junit/src/org/chromium/chrome/browser/compositor/layouts/StaticLayoutUnitTest.java",
   "junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java",
   "junit/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayMediatorTest.java",
+  "junit/src/org/chromium/chrome/browser/content_capture/ContentCaptureHistoryDeletionObserverTest.java",
   "junit/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuCoordinatorTest.java",
   "junit/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderMediatorTest.java",
   "junit/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchContextTest.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 0a87b36e..bf18b5a 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -225,9 +225,6 @@
   "javatests/src/org/chromium/chrome/browser/homepage/HomepageTestRule.java",
   "javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentTest.java",
   "javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentWithEditorTest.java",
-  "javatests/src/org/chromium/chrome/browser/identity/SettingsSecureBasedIdentificationGeneratorTest.java",
-  "javatests/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactoryTest.java",
-  "javatests/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGeneratorTest.java",
   "javatests/src/org/chromium/chrome/browser/identity_disc/IdentityDiscControllerTest.java",
   "javatests/src/org/chromium/chrome/browser/incognito/IncognitoCookieLeakageTest.java",
   "javatests/src/org/chromium/chrome/browser/incognito/IncognitoDataTestUtils.java",
diff --git a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
index 8525b27..cc102ae8 100644
--- a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
@@ -926,11 +926,15 @@
     <receiver  # DIFF-ANCHOR: de24469c
         android:exported="false"
         android:name="org.chromium.chrome.browser.notifications.NotificationService$Receiver">
+    </receiver>  # DIFF-ANCHOR: de24469c
+    <receiver  # DIFF-ANCHOR: 2934478c
+        android:exported="false"
+        android:name="org.chromium.chrome.browser.notifications.NotificationServiceImpl$Receiver">
       <intent-filter>  # DIFF-ANCHOR: 1c1c5ed8
         <action android:name="org.chromium.chrome.browser.notifications.CLICK_NOTIFICATION"/>
         <action android:name="org.chromium.chrome.browser.notifications.CLOSE_NOTIFICATION"/>
       </intent-filter>  # DIFF-ANCHOR: 1c1c5ed8
-    </receiver>  # DIFF-ANCHOR: de24469c
+    </receiver>  # DIFF-ANCHOR: 2934478c
     <receiver  # DIFF-ANCHOR: e1c4d394
         android:exported="false"
         android:name="org.chromium.chrome.browser.notifications.scheduler.DisplayAgent$Receiver">
diff --git a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
index 886f0cc2a..a9f3572 100644
--- a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
@@ -866,11 +866,15 @@
     <receiver  # DIFF-ANCHOR: de24469c
         android:exported="false"
         android:name="org.chromium.chrome.browser.notifications.NotificationService$Receiver">
+    </receiver>  # DIFF-ANCHOR: de24469c
+    <receiver  # DIFF-ANCHOR: 2934478c
+        android:exported="false"
+        android:name="org.chromium.chrome.browser.notifications.NotificationServiceImpl$Receiver">
       <intent-filter>  # DIFF-ANCHOR: 1c1c5ed8
         <action android:name="org.chromium.chrome.browser.notifications.CLICK_NOTIFICATION"/>
         <action android:name="org.chromium.chrome.browser.notifications.CLOSE_NOTIFICATION"/>
       </intent-filter>  # DIFF-ANCHOR: 1c1c5ed8
-    </receiver>  # DIFF-ANCHOR: de24469c
+    </receiver>  # DIFF-ANCHOR: 2934478c
     <receiver  # DIFF-ANCHOR: e1c4d394
         android:exported="false"
         android:name="org.chromium.chrome.browser.notifications.scheduler.DisplayAgent$Receiver">
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataBinder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataBinder.java
index 05b5e35..3366291e 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataBinder.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/AssistantCollectUserDataBinder.java
@@ -11,7 +11,6 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.base.task.PostTask;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.autofill.prefeditor.EditorDialog;
 import org.chromium.chrome.browser.autofill_assistant.generic_ui.AssistantValue;
 import org.chromium.chrome.browser.autofill_assistant.user_data.additional_sections.AssistantAdditionalSection.Delegate;
@@ -23,6 +22,7 @@
 import org.chromium.chrome.browser.payments.CardEditor;
 import org.chromium.chrome.browser.payments.ContactEditor;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.payments.BasicCardUtils;
 import org.chromium.components.payments.MethodStrings;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java
index 9804b8e..c8dceaa 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceLayout.java
@@ -20,7 +20,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.Supplier;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.compositor.LayerTitleCache;
 import org.chromium.chrome.browser.compositor.animation.CompositorAnimationHandler;
@@ -38,6 +37,7 @@
 import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher;
 import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
 import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.browser_ui.widget.animation.Interpolators;
 import org.chromium.ui.resources.ResourceManager;
 
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 4fb1cd15..9f77221 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -1038,6 +1038,8 @@
         <service android:name="org.chromium.chrome.browser.notifications.NotificationService"
             android:exported="false"/>
         <receiver android:name="org.chromium.chrome.browser.notifications.NotificationService$Receiver"
+            android:exported="false"/>
+        <receiver android:name="org.chromium.chrome.browser.notifications.NotificationServiceImpl$Receiver"
             android:exported="false">
             <intent-filter>
                 <action android:name="org.chromium.chrome.browser.notifications.CLICK_NOTIFICATION" />
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS
index 6200d927..e95500a 100644
--- a/chrome/android/java/DEPS
+++ b/chrome/android/java/DEPS
@@ -2,6 +2,7 @@
   "-chrome/android/features/keyboard_accessory/internal",
 
   "+chrome/browser/android/lifecycle",
+  "+chrome/browser/device",
   "+chrome/browser/privacy",
   "+chrome/browser/profiles/android/java",
   "+chrome/browser/share/android",
diff --git a/chrome/android/java/res/layout/fre_tosanduma.xml b/chrome/android/java/res/layout/fre_tosanduma.xml
index d6e0224..6fa5e53 100644
--- a/chrome/android/java/res/layout/fre_tosanduma.xml
+++ b/chrome/android/java/res/layout/fre_tosanduma.xml
@@ -91,6 +91,7 @@
                         android:layout_height="wrap_content"
                         android:lineSpacingMultiplier="1.4"
                         android:text="@string/fre_send_report_check"
+                        android:paddingStart="@dimen/fre_tos_checkbox_padding"
                         android:textAppearance="@style/TextAppearance.TextMedium.Primary" />
                 </LinearLayout>
             </LinearLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java
index c964f54..dc9bedb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java
@@ -18,6 +18,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.strictmode.KnownViolations;
 import org.chromium.components.strictmode.StrictModePolicyViolation;
 import org.chromium.components.strictmode.ThreadStrictModeInterceptor;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeVersionInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeVersionInfo.java
deleted file mode 100644
index bc796d8..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeVersionInfo.java
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser;
-
-/**
- * Temporary class left until references are moved to the new package and build target.
- *
- * TODO(crbug.com/1131982): Remove this.
- */
-public class ChromeVersionInfo extends org.chromium.chrome.browser.version.ChromeVersionInfo {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java
index 7d233a4..657b2ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/MonochromeApplication.java
@@ -12,6 +12,7 @@
 import org.chromium.base.annotations.UsedByReflection;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.chrome.browser.base.SplitMonochromeApplication;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.content_public.browser.ChildProcessCreationParams;
 
 /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/about_settings/AboutChromeSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/about_settings/AboutChromeSettings.java
index c12b88f..e984d4f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/about_settings/AboutChromeSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/about_settings/AboutChromeSettings.java
@@ -14,8 +14,8 @@
 import androidx.preference.PreferenceFragmentCompat;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.tracing.settings.DeveloperSettings;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.browser_ui.settings.SettingsUtils;
 import org.chromium.ui.widget.Toast;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index e451fd73e..fe4cf431 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -1739,7 +1739,7 @@
         mCompositorViewHolder.setUrlBar(urlBar);
         mCompositorViewHolder.setInsetObserverView(getInsetObserverView());
         mCompositorViewHolder.onFinishNativeInitialization(
-                getTabModelSelector(), this, mContextualSearchManager, mActivityTabProvider);
+                getTabModelSelector(), this, mContextualSearchManager);
 
         if (controlContainer != null && DeviceClassManager.enableToolbarSwipe()
                 && getCompositorViewHolder().getLayoutManager().getToolbarSwipeHandler() != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalCardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalCardEditor.java
index ed82127..f014d03 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalCardEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/settings/AutofillLocalCardEditor.java
@@ -23,12 +23,12 @@
 import org.chromium.base.annotations.UsedByReflection;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.payments.SettingsAutofillAndPaymentsObserver;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
index cb326b6..6858380 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitChromeApplication.java
@@ -5,10 +5,6 @@
 package org.chromium.chrome.browser.base;
 
 import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Build;
-
-import org.chromium.base.compat.ApiHelperForO;
 
 /**
  * Application class to use for Chrome when //chrome code is in an isolated split. This class will
@@ -30,8 +26,8 @@
     @Override
     protected void attachBaseContext(Context context) {
         if (isBrowserProcess()) {
-            context = createChromeContext(context);
-            setImpl(createChromeApplication(context));
+            context = SplitCompatUtils.createChromeContext(context);
+            setImpl((Impl) SplitCompatUtils.newInstance(context, mChromeApplicationClassName));
         } else {
             setImpl(createNonBrowserApplication());
         }
@@ -41,29 +37,4 @@
     protected Impl createNonBrowserApplication() {
         return new Impl();
     }
-
-    private Impl createChromeApplication(Context context) {
-        try {
-            return (Impl) context.getClassLoader()
-                    .loadClass(mChromeApplicationClassName)
-                    .newInstance();
-        } catch (ReflectiveOperationException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    private Context createChromeContext(Context base) {
-        assert isBrowserProcess();
-        // Isolated splits are only supported in O+, so just return the base context on other
-        // versions, since this will have access to all splits.
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
-            return base;
-        }
-        try {
-            return ApiHelperForO.createContextForSplit(base, "chrome");
-        } catch (PackageManager.NameNotFoundException e) {
-            // This application class should not be used if the chrome split does not exist.
-            throw new RuntimeException(e);
-        }
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatIntentService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatIntentService.java
new file mode 100644
index 0000000..91b22513c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatIntentService.java
@@ -0,0 +1,63 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.base;
+
+import android.app.IntentService;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * IntentService base class which will call through to the given {@link Impl}. This class must be
+ * present in the base module, while the Impl can be in the chrome module.
+ */
+public class SplitCompatIntentService extends IntentService {
+    private String mServiceClassName;
+    private Impl mImpl;
+
+    public SplitCompatIntentService(String serviceClassName, String name) {
+        super(name);
+        mServiceClassName = serviceClassName;
+    }
+
+    @Override
+    protected void attachBaseContext(Context context) {
+        context = SplitCompatUtils.createChromeContext(context);
+        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        mImpl.setService(this);
+        super.attachBaseContext(context);
+    }
+
+    private IBinder superOnBind(Intent intent) {
+        return super.onBind(intent);
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        mImpl.onHandleIntent(intent);
+    }
+
+    /**
+     * Holds the implementation of service logic. Will be called by {@link
+     * SplitCompatIntentService}.
+     */
+    public abstract static class Impl {
+        private SplitCompatIntentService mService;
+
+        private void setService(SplitCompatIntentService service) {
+            mService = service;
+        }
+
+        protected final IntentService getService() {
+            return mService;
+        }
+
+        public IBinder onBind(Intent intent) {
+            return mService.superOnBind(intent);
+        }
+
+        protected abstract void onHandleIntent(Intent intent);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatJobService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatJobService.java
new file mode 100644
index 0000000..15ccc74
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatJobService.java
@@ -0,0 +1,58 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.base;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.content.Context;
+
+/**
+ * JobService base class which will call through to the given {@link Impl}. This class must be
+ * present in the base module, while the Impl can be in the chrome module.
+ */
+public class SplitCompatJobService extends JobService {
+    private String mServiceClassName;
+    private Impl mImpl;
+
+    public SplitCompatJobService(String serviceClassName) {
+        mServiceClassName = serviceClassName;
+    }
+
+    @Override
+    protected void attachBaseContext(Context context) {
+        context = SplitCompatUtils.createChromeContext(context);
+        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        mImpl.setService(this);
+        super.attachBaseContext(context);
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        return mImpl.onStartJob(params);
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        return mImpl.onStopJob(params);
+    }
+
+    /**
+     * Holds the implementation of service logic. Will be called by {@link SplitCompatJobService}.
+     */
+    public abstract static class Impl {
+        private SplitCompatJobService mService;
+
+        private void setService(SplitCompatJobService service) {
+            mService = service;
+        }
+
+        protected final JobService getService() {
+            return mService;
+        }
+
+        public abstract boolean onStartJob(JobParameters params);
+        public abstract boolean onStopJob(JobParameters params);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java
new file mode 100644
index 0000000..6a5b422
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatService.java
@@ -0,0 +1,98 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.base;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Service base class which will call through to the given {@link Impl}. This class must be present
+ * in the base module, while the Impl can be in the chrome module.
+ */
+public class SplitCompatService extends Service {
+    private String mServiceClassName;
+    private Impl mImpl;
+
+    public SplitCompatService(String serviceClassName) {
+        mServiceClassName = serviceClassName;
+    }
+
+    @Override
+    protected void attachBaseContext(Context context) {
+        context = SplitCompatUtils.createChromeContext(context);
+        mImpl = (Impl) SplitCompatUtils.newInstance(context, mServiceClassName);
+        mImpl.setService(this);
+        super.attachBaseContext(context);
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mImpl.onCreate();
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        return mImpl.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mImpl.onDestroy();
+    }
+
+    @Override
+    public void onTaskRemoved(Intent rootIntent) {
+        super.onTaskRemoved(rootIntent);
+        mImpl.onTaskRemoved(rootIntent);
+    }
+
+    @Override
+    public void onLowMemory() {
+        super.onLowMemory();
+        mImpl.onLowMemory();
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mImpl.onBind(intent);
+    }
+
+    private int superOnStartCommand(Intent intent, int flags, int startId) {
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    /**
+     * Holds the implementation of service logic. Will be called by {@link SplitCompatService}.
+     */
+    public abstract static class Impl {
+        private SplitCompatService mService;
+
+        protected void setService(SplitCompatService service) {
+            mService = service;
+        }
+
+        protected final Service getService() {
+            return mService;
+        }
+
+        public void onCreate() {}
+
+        public int onStartCommand(Intent intent, int flags, int startId) {
+            return mService.superOnStartCommand(intent, flags, startId);
+        }
+
+        public void onDestroy() {}
+
+        public void onTaskRemoved(Intent rootIntent) {}
+
+        public void onLowMemory() {}
+
+        public abstract IBinder onBind(Intent intent);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatUtils.java
new file mode 100644
index 0000000..207cd06
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/base/SplitCompatUtils.java
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.base;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import org.chromium.base.compat.ApiHelperForO;
+
+/** Utils for compatibility with isolated splits. */
+public class SplitCompatUtils {
+    private SplitCompatUtils() {}
+
+    /** Creates a context which can be used to load code and resources in the chrome split. */
+    public static Context createChromeContext(Context base) {
+        // Isolated splits are only supported in O+, so just return the base context on other
+        // versions, since this will have access to all splits.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+            return base;
+        }
+        try {
+            return ApiHelperForO.createContextForSplit(base, "chrome");
+        } catch (PackageManager.NameNotFoundException e) {
+            // This application class should not be used if the chrome split does not exist.
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Constructs a new instance of the given class name using the class loader from the context.
+     */
+    public static Object newInstance(Context context, String className) {
+        try {
+            return context.getClassLoader().loadClass(className).newInstance();
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClientAppBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClientAppBroadcastReceiver.java
index ae024e9..bf498a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClientAppBroadcastReceiver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ClientAppBroadcastReceiver.java
@@ -10,9 +10,9 @@
 
 import org.chromium.base.Log;
 import org.chromium.chrome.browser.ChromeApplication;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.browserservices.permissiondelegation.PermissionUpdater;
 import org.chromium.chrome.browser.metrics.WebApkUma;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.embedder_support.util.Origin;
 import org.chromium.components.webapk.lib.common.WebApkConstants;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index 7a9562f..8fd5697 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -43,7 +43,6 @@
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsUtils;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
@@ -1241,16 +1240,14 @@
      *                                represent.
      * @param tabCreatorManager       The {@link TabCreatorManager} for this view.
      * @param contextualSearchManager A {@link ContextualSearchManagementDelegate} instance.
-     * @param tabProvider             A means of acquiring the active tab.
      */
     public void onFinishNativeInitialization(TabModelSelector tabModelSelector,
             TabCreatorManager tabCreatorManager,
-            ContextualSearchManagementDelegate contextualSearchManager,
-            ActivityTabProvider tabProvider) {
+            ContextualSearchManagementDelegate contextualSearchManager) {
         assert mLayoutManager != null;
         mLayoutManager.init(tabModelSelector, tabCreatorManager, mControlContainer,
                 contextualSearchManager,
-                mCompositorView.getResourceManager().getDynamicResourceLoader(), tabProvider);
+                mCompositorView.getResourceManager().getDynamicResourceLoader());
 
         mTabModelSelector = tabModelSelector;
         tabModelSelector.addObserver(new EmptyTabModelSelectorObserver() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
index af0c27c0..602916c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -14,13 +14,13 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.content.ContentUtils;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid;
 import org.chromium.components.embedder_support.view.ContentView;
 import org.chromium.components.external_intents.ExternalNavigationHandler;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
index fec85cff..7142f40 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
@@ -17,7 +17,6 @@
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.content.ContentUtils;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
@@ -29,6 +28,7 @@
 import org.chromium.chrome.browser.tabmodel.TabCreator;
 import org.chromium.chrome.browser.ui.favicon.FaviconHelper;
 import org.chromium.chrome.browser.ui.favicon.FaviconUtils;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
index 8d9550c..215d728 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
@@ -16,12 +16,10 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.Callback;
 import org.chromium.base.ObserverList;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
-import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsUtils;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsVisibilityManager;
@@ -43,7 +41,6 @@
 import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer;
 import org.chromium.chrome.browser.compositor.scene_layer.ScrollingBottomViewSceneLayer;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate;
-import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.fullscreen.BrowserControlsManager;
 import org.chromium.chrome.browser.gesturenav.HistoryNavigationCoordinator;
 import org.chromium.chrome.browser.native_page.NativePageFactory;
@@ -66,10 +63,12 @@
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
 import org.chromium.chrome.browser.toolbar.ControlContainer;
 import org.chromium.chrome.browser.toolbar.ToolbarColors;
-import org.chromium.components.browser_ui.widget.ClipDrawableProgressBar;
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.base.SPenSupport;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 import org.chromium.ui.resources.ResourceManager;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
 import org.chromium.ui.util.TokenHolder;
@@ -139,7 +138,6 @@
     private boolean mUpdateRequested;
     private ContextualSearchPanel mContextualSearchPanel;
     private final OverlayPanelManager mOverlayPanelManager;
-    private TopToolbarOverlayCoordinator mToolbarOverlay;
     private SceneOverlay mGestureNavigationOverscrollGlow;
 
     /** A delegate for interacting with the Contextual Search manager. */
@@ -454,7 +452,7 @@
     public void init(TabModelSelector selector, TabCreatorManager creator,
             @Nullable ControlContainer controlContainer,
             ContextualSearchManagementDelegate contextualSearchDelegate,
-            DynamicResourceLoader dynamicResourceLoader, ActivityTabProvider tabProvider) {
+            DynamicResourceLoader dynamicResourceLoader) {
         LayoutRenderHost renderHost = mHost.getLayoutRenderHost();
 
         // Build Layouts
@@ -466,19 +464,6 @@
 
         setNextLayout(null);
 
-        // If fullscreen is disabled, don't bother creating this overlay; only the android view will
-        // ever be shown.
-        if (DeviceClassManager.enableFullscreen()) {
-            Callback<ClipDrawableProgressBar.DrawingInfo> progressInfoCallback = (info) -> {
-                if (controlContainer == null) return;
-                controlContainer.getProgressBarDrawingInfo(info);
-            };
-            mToolbarOverlay = new TopToolbarOverlayCoordinator(mContext, mFrameRequestSupplier,
-                    this, progressInfoCallback, tabProvider, getBrowserControlsManager(),
-                    mAndroidViewShownSupplier, () -> renderHost.getResourceManager());
-            addSceneOverlay(mToolbarOverlay);
-        }
-
         // Initialize Layouts
         mStaticLayout.onFinishNativeInitialization();
 
@@ -563,7 +548,6 @@
      * Cleans up and destroys this object.  It should not be used after this.
      */
     public void destroy() {
-        if (mToolbarOverlay != null) mToolbarOverlay.destroy();
         mAnimationHandler.destroy();
         mSceneChangeObservers.clear();
         if (mStaticLayout != null) mStaticLayout.destroy();
@@ -578,6 +562,27 @@
         }
     }
 
+    /** @return A resource manager to pull textures from. */
+    public ResourceManager getResourceManager() {
+        if (mHost.getLayoutRenderHost() == null) return null;
+        return mHost.getLayoutRenderHost().getResourceManager();
+    }
+
+    /**
+     * Creates a CompositorModelChangeProcessor observing the given {@code model} that will operate
+     * on this {@link LayoutManager}'s frame cycle. The model will be bound to the view initially
+     * and request a new frame.
+     * @param model The model containing the data to be bound to the view.
+     * @param view The view which the model will be bound to.
+     * @param viewBinder This is used to bind the model to the view.
+     */
+    public <V extends SceneLayer> CompositorModelChangeProcessor<V> createCompositorMCP(
+            PropertyModel model, V view,
+            PropertyModelChangeProcessor.ViewBinder<PropertyModel, V, PropertyKey> viewBinder) {
+        return CompositorModelChangeProcessor.create(
+                model, view, viewBinder, mFrameRequestSupplier, true);
+    }
+
     /**
      * @param observer Adds {@code observer} to be notified when the active {@code Layout} changes.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
index 706cf73..22cc928 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
@@ -15,7 +15,6 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.OneshotSupplierImpl;
-import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.accessibility_tab_switcher.OverviewListLayout;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.compositor.TitleCache;
@@ -169,7 +168,7 @@
     public void init(TabModelSelector selector, TabCreatorManager creator,
             ControlContainer controlContainer,
             ContextualSearchManagementDelegate contextualSearchDelegate,
-            DynamicResourceLoader dynamicResourceLoader, ActivityTabProvider tabProvider) {
+            DynamicResourceLoader dynamicResourceLoader) {
         Context context = mHost.getContext();
         LayoutRenderHost renderHost = mHost.getLayoutRenderHost();
         BrowserControlsStateProvider browserControlsStateProvider =
@@ -188,7 +187,7 @@
         }
 
         super.init(selector, creator, controlContainer, contextualSearchDelegate,
-                dynamicResourceLoader, tabProvider);
+                dynamicResourceLoader);
 
         // TODO: TitleCache should be a part of the ResourceManager.
         mTitleCache = mHost.getTitleCache();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
index dd6da30..3c32937 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
@@ -9,7 +9,6 @@
 
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.OneshotSupplierImpl;
-import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.compositor.layouts.phone.SimpleAnimationLayout;
 import org.chromium.chrome.browser.compositor.overlays.SceneOverlay;
@@ -52,7 +51,7 @@
     public void init(TabModelSelector selector, TabCreatorManager creator,
             ControlContainer controlContainer,
             ContextualSearchManagementDelegate contextualSearchDelegate,
-            DynamicResourceLoader dynamicResourceLoader, ActivityTabProvider tabProvider) {
+            DynamicResourceLoader dynamicResourceLoader) {
         Context context = mHost.getContext();
         LayoutRenderHost renderHost = mHost.getLayoutRenderHost();
 
@@ -60,7 +59,7 @@
         mSimpleAnimationLayout = new SimpleAnimationLayout(context, this, renderHost);
 
         super.init(selector, creator, controlContainer, contextualSearchDelegate,
-                dynamicResourceLoader, tabProvider);
+                dynamicResourceLoader);
 
         // Set up layout parameters
         mStaticLayout.setLayoutHandlesTabLifecycles(false);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
index 46d3eccc..2766759 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
@@ -9,7 +9,6 @@
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate;
@@ -85,13 +84,13 @@
     public void init(TabModelSelector selector, TabCreatorManager creator,
             ControlContainer controlContainer,
             ContextualSearchManagementDelegate contextualSearchDelegate,
-            DynamicResourceLoader dynamicResourceLoader, ActivityTabProvider tabProvider) {
+            DynamicResourceLoader dynamicResourceLoader) {
         if (mTabStripLayoutHelperManager != null) {
             mTabStripLayoutHelperManager.setTabModelSelector(selector, creator);
         }
 
         super.init(selector, creator, controlContainer, contextualSearchDelegate,
-                dynamicResourceLoader, tabProvider);
+                dynamicResourceLoader);
 
         // Make sure any tabs already restored get loaded into the title cache.
         List<TabModel> models = selector.getModels();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayCoordinator.java
index c6ff93c..a4e4a75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayCoordinator.java
@@ -8,8 +8,6 @@
 import android.graphics.RectF;
 
 import org.chromium.base.Callback;
-import org.chromium.base.supplier.ObservableSupplier;
-import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
@@ -40,14 +38,10 @@
     /** Business logic for this overlay. */
     private final TopToolbarOverlayMediator mMediator;
 
-    public TopToolbarOverlayCoordinator(Context context,
-            CompositorModelChangeProcessor.FrameRequestSupplier frameRequestSupplier,
-            LayoutManager layoutManager,
+    public TopToolbarOverlayCoordinator(Context context, LayoutManager layoutManager,
             Callback<ClipDrawableProgressBar.DrawingInfo> progressInfoCallback,
             ActivityTabProvider tabSupplier,
-            BrowserControlsStateProvider browserControlsStateProvider,
-            ObservableSupplier<Boolean> androidViewShownSupplier,
-            Supplier<ResourceManager> resourceManagerSupplier) {
+            BrowserControlsStateProvider browserControlsStateProvider) {
         mModel = new PropertyModel.Builder(TopToolbarOverlayProperties.ALL_KEYS)
                          .with(TopToolbarOverlayProperties.RESOURCE_ID, R.id.control_container)
                          .with(TopToolbarOverlayProperties.URL_BAR_RESOURCE_ID,
@@ -56,13 +50,20 @@
                          .with(TopToolbarOverlayProperties.CONTENT_OFFSET,
                                  browserControlsStateProvider.getContentOffset())
                          .build();
-        mSceneLayer = new TopToolbarSceneLayer(resourceManagerSupplier);
-        mChangeProcessor = CompositorModelChangeProcessor.create(
-                mModel, mSceneLayer, TopToolbarSceneLayer::bind, frameRequestSupplier, true);
+        mSceneLayer = new TopToolbarSceneLayer(() -> layoutManager.getResourceManager());
+        mChangeProcessor =
+                layoutManager.createCompositorMCP(mModel, mSceneLayer, TopToolbarSceneLayer::bind);
 
-        mMediator =
-                new TopToolbarOverlayMediator(mModel, context, layoutManager, progressInfoCallback,
-                        tabSupplier, browserControlsStateProvider, androidViewShownSupplier);
+        mMediator = new TopToolbarOverlayMediator(mModel, context, layoutManager,
+                progressInfoCallback, tabSupplier, browserControlsStateProvider);
+    }
+
+    /**
+     * Set whether the android view corresponding with this overlay is showing.
+     * @param isVisible Whether the android view is visible.
+     */
+    public void setIsAndroidViewVisible(boolean isVisible) {
+        mMediator.setIsAndroidViewVisible(isVisible);
     }
 
     /** Clean up this component. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayMediator.java
index e22db22..2b7fe3c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayMediator.java
@@ -10,7 +10,6 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
-import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsUtils;
@@ -58,12 +57,6 @@
     /** An observer of the browser controls offsets. */
     private final BrowserControlsStateProvider.Observer mBrowserControlsObserver;
 
-    /** A means of checking whether the toolbar android view is being force-hidden or shown. */
-    private final ObservableSupplier<Boolean> mAndroidViewShownSupplier;
-
-    /** An observer of the android view's hidden state. */
-    private final Callback<Boolean> mAndroidViewShownObserver;
-
     /** The view state for this overlay. */
     private final PropertyModel mModel;
 
@@ -73,17 +66,18 @@
     /** Whether the active layout has its own toolbar to display instead of this one. */
     private boolean mLayoutHasOwnToolbar;
 
+    /** Whether the android view for this overlay is visible. */
+    private boolean mIsAndroidViewVisible;
+
     TopToolbarOverlayMediator(PropertyModel model, Context context, LayoutManager layoutManager,
             Callback<ClipDrawableProgressBar.DrawingInfo> progressInfoCallback,
             ActivityTabProvider tabSupplier,
-            BrowserControlsStateProvider browserControlsStateProvider,
-            ObservableSupplier<Boolean> androidViewShownSupplier) {
+            BrowserControlsStateProvider browserControlsStateProvider) {
         mContext = context;
         mLayoutManager = layoutManager;
         mProgressInfoCallback = progressInfoCallback;
         mTabSupplier = tabSupplier;
         mBrowserControlsStateProvider = browserControlsStateProvider;
-        mAndroidViewShownSupplier = androidViewShownSupplier;
         mModel = model;
 
         mSceneChangeObserver = new SceneChangeObserver() {
@@ -134,9 +128,6 @@
         };
         mTabSupplier.addObserverAndTrigger(mTabSupplierObserver);
 
-        mAndroidViewShownObserver = (shown) -> updateShadowState();
-        mAndroidViewShownSupplier.addObserver(mAndroidViewShownObserver);
-
         mBrowserControlsObserver = new BrowserControlsStateProvider.Observer() {
             @Override
             public void onControlsOffsetChanged(int topOffset, int topControlsMinHeightOffset,
@@ -158,13 +149,22 @@
     }
 
     /**
+     * Set whether the android view corresponding with this overlay is showing.
+     * @param isVisible Whether the android view is visible.
+     */
+    void setIsAndroidViewVisible(boolean isVisible) {
+        mIsAndroidViewVisible = isVisible;
+        updateShadowState();
+    }
+
+    /**
      * Compute whether the texture's shadow should be visible. The shadow is visible whenever the
      * android view is not shown.
      */
     private void updateShadowState() {
         boolean drawControlsAsTexture =
                 BrowserControlsUtils.drawControlsAsTexture(mBrowserControlsStateProvider);
-        boolean showShadow = drawControlsAsTexture || !mAndroidViewShownSupplier.get();
+        boolean showShadow = drawControlsAsTexture || !mIsAndroidViewVisible;
         mModel.set(TopToolbarOverlayProperties.SHOW_SHADOW, showShadow);
     }
 
@@ -231,7 +231,6 @@
         mLastActiveTab = null;
 
         mLayoutManager.removeSceneChangeObserver(mSceneChangeObserver);
-        mAndroidViewShownSupplier.removeObserver(mAndroidViewShownObserver);
         mBrowserControlsStateProvider.removeObserver(mBrowserControlsObserver);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/content_capture/ContentCaptureHistoryDeletionObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/content_capture/ContentCaptureHistoryDeletionObserver.java
index f322b34..043ca55 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/content_capture/ContentCaptureHistoryDeletionObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/content_capture/ContentCaptureHistoryDeletionObserver.java
@@ -4,27 +4,37 @@
 
 package org.chromium.chrome.browser.content_capture;
 
+import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.history.HistoryDeletionBridge;
 import org.chromium.chrome.browser.history.HistoryDeletionInfo;
 import org.chromium.components.content_capture.ContentCaptureController;
 
 /** History deletion observer that calls ContentCapture methods. */
 public class ContentCaptureHistoryDeletionObserver implements HistoryDeletionBridge.Observer {
+    Supplier<ContentCaptureController> mContentCaptureControllerSupplier;
+
+    public ContentCaptureHistoryDeletionObserver(
+            Supplier<ContentCaptureController> contentCaptureControllerSupplier) {
+        mContentCaptureControllerSupplier = contentCaptureControllerSupplier;
+    }
+
     /** Observer method when a bit of history is deleted. */
     @Override
     public void onURLsDeleted(HistoryDeletionInfo historyDeletionInfo) {
-        ContentCaptureController contentCaptureController = ContentCaptureController.getInstance();
+        ContentCaptureController contentCaptureController = mContentCaptureControllerSupplier.get();
         if (contentCaptureController == null) return;
 
-        if (historyDeletionInfo.isTimeRangeForAllTime()
-                || (historyDeletionInfo.isTimeRangeValid()
-                        && historyDeletionInfo.getTimeRangeBegin()
-                                != historyDeletionInfo.getTimeRangeEnd())) {
+        // A timerange deletion is equivalent to deleting "all" history.
+        if (historyDeletionInfo.isTimeRangeForAllTime() || historyDeletionInfo.isTimeRangeValid()) {
             contentCaptureController.clearAllContentCaptureData();
         } else {
             String[] deletedURLs = historyDeletionInfo.getDeletedURLs();
             if (deletedURLs.length > 0) {
-                contentCaptureController.clearContentCaptureDataForURLs(deletedURLs);
+                try {
+                    contentCaptureController.clearContentCaptureDataForURLs(deletedURLs);
+                } catch (RuntimeException e) {
+                    throw new RuntimeException("Deleted URLs length: " + deletedURLs.length, e);
+                }
             }
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
index 47c67c0..b32e3b26 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -15,7 +15,6 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.CollectionUtil;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial.ContextualSearchSetting;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial.ContextualSearchSwitch;
@@ -27,6 +26,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
 import org.chromium.chrome.browser.signin.UnifiedConsentServiceBridge;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.embedder_support.util.UrlConstants;
 
 import java.net.URL;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/PureJavaExceptionReporter.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/PureJavaExceptionReporter.java
index 452b70a..4739e8b2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/PureJavaExceptionReporter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/PureJavaExceptionReporter.java
@@ -19,7 +19,7 @@
 import org.chromium.base.PiiElider;
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.annotations.MainDex;
-import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.crash.CrashKeys;
 
 import java.io.File;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 79b99fe..d78d69bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -40,11 +40,11 @@
 import org.chromium.base.Log;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.flags.ActivityType;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.browser_ui.widget.TintedDrawable;
 import org.chromium.components.embedder_support.util.UrlConstants;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java
index f252594..49a4e4c4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundService.java
@@ -1,248 +1,16 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 package org.chromium.chrome.browser.download;
 
-import static org.chromium.chrome.browser.download.DownloadSnackbarController.INVALID_NOTIFICATION_ID;
+import org.chromium.chrome.browser.base.SplitCompatService;
 
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Binder;
-import android.os.Build;
-import android.os.IBinder;
-
-import androidx.annotation.IntDef;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-import androidx.core.app.ServiceCompat;
-
-import org.chromium.base.ContextUtils;
-import org.chromium.base.Log;
-import org.chromium.components.browser_ui.notifications.ForegroundServiceUtils;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Keep-alive foreground service for downloads.
- */
-public class DownloadForegroundService extends Service {
-    private static final String TAG = "DownloadFg";
-    private final IBinder mBinder = new LocalBinder();
-
-    private NotificationManager mNotificationManager;
-
-    @IntDef({StopForegroundNotification.KILL, StopForegroundNotification.DETACH})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface StopForegroundNotification {
-        int KILL = 0; // Kill notification regardless of ability to detach.
-        int DETACH = 1; // Try to detach, otherwise kill and relaunch.
-    }
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-
-        mNotificationManager =
-                (NotificationManager) ContextUtils.getApplicationContext().getSystemService(
-                        Context.NOTIFICATION_SERVICE);
-    }
-
-    /**
-     * Start the foreground service with this given context.
-     * @param context The context used to start service.
-     */
-    public static void startDownloadForegroundService(Context context) {
-        // TODO(crbug.com/770389): Grab a WakeLock here until the service has started.
-        ForegroundServiceUtils.getInstance().startForegroundService(
-                new Intent(context, DownloadForegroundService.class));
-    }
-
-    /**
-     * Start the foreground service or update it to be pinned to a different notification.
-     *
-     * @param newNotificationId   The ID of the new notification to pin the service to.
-     * @param newNotification     The new notification to be pinned to the service.
-     * @param oldNotificationId   The ID of the original notification that was pinned to the
-     *                            service, can be INVALID_NOTIFICATION_ID if the service is just
-     *                            starting.
-     * @param oldNotification     The original notification the service was pinned to, in case an
-     *                            adjustment needs to be made (in the case it could not be
-     *                            detached).
-     * @param killOldNotification Whether or not to detach or kill the old notification.
-     */
-    public void startOrUpdateForegroundService(int newNotificationId, Notification newNotification,
-            int oldNotificationId, Notification oldNotification, boolean killOldNotification) {
-        Log.w(TAG,
-                "startOrUpdateForegroundService new: " + newNotificationId
-                        + ", old: " + oldNotificationId + ", kill old: " + killOldNotification);
-        // Handle notifications and start foreground.
-        if (oldNotificationId == INVALID_NOTIFICATION_ID && oldNotification == null) {
-            // If there is no old notification or old notification id, just start foreground.
-            startForegroundInternal(newNotificationId, newNotification);
-        } else {
-            if (getCurrentSdk() >= 24) {
-                // If possible, detach notification so it doesn't get cancelled by accident.
-                stopForegroundInternal(killOldNotification ? ServiceCompat.STOP_FOREGROUND_REMOVE
-                                                           : ServiceCompat.STOP_FOREGROUND_DETACH);
-                startForegroundInternal(newNotificationId, newNotification);
-            } else {
-                // Otherwise start the foreground and relaunch the originally pinned notification.
-                startForegroundInternal(newNotificationId, newNotification);
-                if (!killOldNotification) {
-                    relaunchOldNotification(oldNotificationId, oldNotification);
-                }
-            }
-        }
-
-        // Record when starting foreground and when updating pinned notification.
-        if (oldNotificationId == INVALID_NOTIFICATION_ID) {
-            DownloadNotificationUmaHelper.recordForegroundServiceLifecycleHistogram(
-                    DownloadNotificationUmaHelper.ForegroundLifecycle.START);
-        } else {
-            if (oldNotificationId != newNotificationId) {
-                DownloadNotificationUmaHelper.recordForegroundServiceLifecycleHistogram(
-                        DownloadNotificationUmaHelper.ForegroundLifecycle.UPDATE);
-            }
-        }
-    }
-
-    /**
-     * Stop the foreground service that is running.
-     *
-     * @param stopForegroundNotification    How to handle the notification upon the foreground
-     *                                      stopping (options are: kill, detach or adjust, or detach
-     *                                      or persist, see {@link StopForegroundNotification}.
-     * @param pinnedNotificationId          Id of the notification that is pinned to the foreground
-     *                                      and would need adjustment.
-     * @param pinnedNotification            The actual notification that is pinned to the foreground
-     *                                      and would need adjustment.
-     */
-    public void stopDownloadForegroundService(
-            @StopForegroundNotification int stopForegroundNotification, int pinnedNotificationId,
-            Notification pinnedNotification) {
-        Log.w(TAG,
-                "stopDownloadForegroundService status: " + stopForegroundNotification
-                        + ", id: " + pinnedNotificationId);
-        // Record when stopping foreground.
-        DownloadNotificationUmaHelper.recordForegroundServiceLifecycleHistogram(
-                DownloadNotificationUmaHelper.ForegroundLifecycle.STOP);
-        DownloadNotificationUmaHelper.recordServiceStoppedHistogram(
-                DownloadNotificationUmaHelper.ServiceStopped.STOPPED, true /* withForeground */);
-
-        // Handle notifications and stop foreground.
-        if (stopForegroundNotification == StopForegroundNotification.KILL) {
-            // Regardless of the SDK level, stop foreground and kill if so indicated.
-            stopForegroundInternal(ServiceCompat.STOP_FOREGROUND_REMOVE);
-        } else {
-            if (getCurrentSdk() >= 24) {
-                // Android N+ has the option to detach notifications from the service, so detach or
-                // kill the notification as needed when stopping service.
-                stopForegroundInternal(ServiceCompat.STOP_FOREGROUND_DETACH);
-            } else if (getCurrentSdk() >= 23) {
-                // Android M+ can't detach the notification but doesn't have other caveats. Kill the
-                // notification and relaunch if detach was desired.
-                stopForegroundInternal(ServiceCompat.STOP_FOREGROUND_REMOVE);
-                relaunchOldNotification(pinnedNotificationId, pinnedNotification);
-            } else {
-                // In phones that are Lollipop and older (API < 23), the service gets killed with
-                // the task, which might result in the notification being unable to be relaunched
-                // where it needs to be. kill and relaunch the old notification before stopping the
-                // service.
-                relaunchOldNotification(
-                        getNewNotificationIdFor(pinnedNotificationId), pinnedNotification);
-                stopForegroundInternal(ServiceCompat.STOP_FOREGROUND_REMOVE);
-            }
-        }
-        stopSelf();
-    }
-
-    @VisibleForTesting
-    void relaunchOldNotification(int notificationId, Notification notification) {
-        if (notificationId != INVALID_NOTIFICATION_ID && notification != null) {
-            mNotificationManager.notify(notificationId, notification);
-        }
-    }
-
-    @Override
-    public int onStartCommand(Intent intent, int flags, int startId) {
-        // In the case the service was restarted when the intent is null.
-        if (intent == null) {
-            DownloadNotificationUmaHelper.recordServiceStoppedHistogram(
-                    DownloadNotificationUmaHelper.ServiceStopped.START_STICKY, true);
-
-            // Allow observers to restart service on their own, if needed.
-            stopSelf();
-        }
-
-        // This should restart service after Chrome gets killed (except for Android 4.4.2).
-        return START_STICKY;
-    }
-
-    @Override
-    public void onDestroy() {
-        DownloadNotificationUmaHelper.recordServiceStoppedHistogram(
-                DownloadNotificationUmaHelper.ServiceStopped.DESTROYED, true /* withForeground */);
-        DownloadForegroundServiceObservers.alertObserversServiceDestroyed();
-        super.onDestroy();
-    }
-
-    @Override
-    public void onTaskRemoved(Intent rootIntent) {
-        DownloadNotificationUmaHelper.recordServiceStoppedHistogram(
-                DownloadNotificationUmaHelper.ServiceStopped.TASK_REMOVED, true /*withForeground*/);
-        DownloadForegroundServiceObservers.alertObserversTaskRemoved();
-        super.onTaskRemoved(rootIntent);
-    }
-
-    @Override
-    public void onLowMemory() {
-        DownloadNotificationUmaHelper.recordServiceStoppedHistogram(
-                DownloadNotificationUmaHelper.ServiceStopped.LOW_MEMORY, true /* withForeground */);
-        super.onLowMemory();
-    }
-
-    @Nullable
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mBinder;
-    }
-
-    /**
-     * Class for clients to access.
-     */
-    class LocalBinder extends Binder {
-        DownloadForegroundService getService() {
-            return DownloadForegroundService.this;
-        }
-    }
-
-    /** Methods for testing. */
-
-    @VisibleForTesting
-    int getNewNotificationIdFor(int oldNotificationId) {
-        return DownloadNotificationService.getNewNotificationIdFor(oldNotificationId);
-    }
-
-    @VisibleForTesting
-    void startForegroundInternal(int notificationId, Notification notification) {
-        Log.w(TAG, "startForegroundInternal id: " + notificationId);
-        ForegroundServiceUtils.getInstance().startForeground(
-                this, notificationId, notification, 0 /* foregroundServiceType */);
-    }
-
-    @VisibleForTesting
-    void stopForegroundInternal(int flags) {
-        Log.w(TAG, "stopForegroundInternal flags: " + flags);
-        ForegroundServiceUtils.getInstance().stopForeground(this, flags);
-    }
-
-    @VisibleForTesting
-    int getCurrentSdk() {
-        return Build.VERSION.SDK_INT;
+/** See {@link DownloadForegroundServiceImpl}. */
+public class DownloadForegroundService extends SplitCompatService {
+    // TODO(crbug.com/1126301):  Use R8's -identifiernamestring to verify this and other
+    // SplitCompatService subclasses.
+    public DownloadForegroundService() {
+        super("org.chromium.chrome.browser.download.DownloadForegroundServiceImpl");
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceImpl.java
new file mode 100644
index 0000000..ce190d2d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceImpl.java
@@ -0,0 +1,253 @@
+// 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.
+
+package org.chromium.chrome.browser.download;
+
+import static org.chromium.chrome.browser.download.DownloadSnackbarController.INVALID_NOTIFICATION_ID;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IBinder;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.core.app.ServiceCompat;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
+import org.chromium.base.annotations.UsedByReflection;
+import org.chromium.components.browser_ui.notifications.ForegroundServiceUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Keep-alive foreground service for downloads.
+ */
+@UsedByReflection("DownloadForegroundService.java")
+public class DownloadForegroundServiceImpl extends DownloadForegroundService.Impl {
+    private static final String TAG = "DownloadFg";
+    private final IBinder mBinder = new LocalBinder();
+
+    private NotificationManager mNotificationManager;
+
+    @IntDef({StopForegroundNotification.KILL, StopForegroundNotification.DETACH})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StopForegroundNotification {
+        int KILL = 0; // Kill notification regardless of ability to detach.
+        int DETACH = 1; // Try to detach, otherwise kill and relaunch.
+    }
+
+    @UsedByReflection("DownloadForegroundService.java")
+    public DownloadForegroundServiceImpl() {}
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mNotificationManager =
+                (NotificationManager) ContextUtils.getApplicationContext().getSystemService(
+                        Context.NOTIFICATION_SERVICE);
+    }
+
+    /**
+     * Start the foreground service with this given context.
+     * @param context The context used to start service.
+     */
+    public static void startDownloadForegroundService(Context context) {
+        // TODO(crbug.com/770389): Grab a WakeLock here until the service has started.
+        ForegroundServiceUtils.getInstance().startForegroundService(
+                new Intent(context, DownloadForegroundService.class));
+    }
+
+    /**
+     * Start the foreground service or update it to be pinned to a different notification.
+     *
+     * @param newNotificationId   The ID of the new notification to pin the service to.
+     * @param newNotification     The new notification to be pinned to the service.
+     * @param oldNotificationId   The ID of the original notification that was pinned to the
+     *                            service, can be INVALID_NOTIFICATION_ID if the service is just
+     *                            starting.
+     * @param oldNotification     The original notification the service was pinned to, in case an
+     *                            adjustment needs to be made (in the case it could not be
+     *                            detached).
+     * @param killOldNotification Whether or not to detach or kill the old notification.
+     */
+    public void startOrUpdateForegroundService(int newNotificationId, Notification newNotification,
+            int oldNotificationId, Notification oldNotification, boolean killOldNotification) {
+        Log.w(TAG,
+                "startOrUpdateForegroundService new: " + newNotificationId
+                        + ", old: " + oldNotificationId + ", kill old: " + killOldNotification);
+        // Handle notifications and start foreground.
+        if (oldNotificationId == INVALID_NOTIFICATION_ID && oldNotification == null) {
+            // If there is no old notification or old notification id, just start foreground.
+            startForegroundInternal(newNotificationId, newNotification);
+        } else {
+            if (getCurrentSdk() >= 24) {
+                // If possible, detach notification so it doesn't get cancelled by accident.
+                stopForegroundInternal(killOldNotification ? ServiceCompat.STOP_FOREGROUND_REMOVE
+                                                           : ServiceCompat.STOP_FOREGROUND_DETACH);
+                startForegroundInternal(newNotificationId, newNotification);
+            } else {
+                // Otherwise start the foreground and relaunch the originally pinned notification.
+                startForegroundInternal(newNotificationId, newNotification);
+                if (!killOldNotification) {
+                    relaunchOldNotification(oldNotificationId, oldNotification);
+                }
+            }
+        }
+
+        // Record when starting foreground and when updating pinned notification.
+        if (oldNotificationId == INVALID_NOTIFICATION_ID) {
+            DownloadNotificationUmaHelper.recordForegroundServiceLifecycleHistogram(
+                    DownloadNotificationUmaHelper.ForegroundLifecycle.START);
+        } else {
+            if (oldNotificationId != newNotificationId) {
+                DownloadNotificationUmaHelper.recordForegroundServiceLifecycleHistogram(
+                        DownloadNotificationUmaHelper.ForegroundLifecycle.UPDATE);
+            }
+        }
+    }
+
+    /**
+     * Stop the foreground service that is running.
+     *
+     * @param stopForegroundNotification    How to handle the notification upon the foreground
+     *                                      stopping (options are: kill, detach or adjust, or detach
+     *                                      or persist, see {@link StopForegroundNotification}.
+     * @param pinnedNotificationId          Id of the notification that is pinned to the foreground
+     *                                      and would need adjustment.
+     * @param pinnedNotification            The actual notification that is pinned to the foreground
+     *                                      and would need adjustment.
+     */
+    public void stopDownloadForegroundService(
+            @StopForegroundNotification int stopForegroundNotification, int pinnedNotificationId,
+            Notification pinnedNotification) {
+        Log.w(TAG,
+                "stopDownloadForegroundService status: " + stopForegroundNotification
+                        + ", id: " + pinnedNotificationId);
+        // Record when stopping foreground.
+        DownloadNotificationUmaHelper.recordForegroundServiceLifecycleHistogram(
+                DownloadNotificationUmaHelper.ForegroundLifecycle.STOP);
+        DownloadNotificationUmaHelper.recordServiceStoppedHistogram(
+                DownloadNotificationUmaHelper.ServiceStopped.STOPPED, true /* withForeground */);
+
+        // Handle notifications and stop foreground.
+        if (stopForegroundNotification == StopForegroundNotification.KILL) {
+            // Regardless of the SDK level, stop foreground and kill if so indicated.
+            stopForegroundInternal(ServiceCompat.STOP_FOREGROUND_REMOVE);
+        } else {
+            if (getCurrentSdk() >= 24) {
+                // Android N+ has the option to detach notifications from the service, so detach or
+                // kill the notification as needed when stopping service.
+                stopForegroundInternal(ServiceCompat.STOP_FOREGROUND_DETACH);
+            } else if (getCurrentSdk() >= 23) {
+                // Android M+ can't detach the notification but doesn't have other caveats. Kill the
+                // notification and relaunch if detach was desired.
+                stopForegroundInternal(ServiceCompat.STOP_FOREGROUND_REMOVE);
+                relaunchOldNotification(pinnedNotificationId, pinnedNotification);
+            } else {
+                // In phones that are Lollipop and older (API < 23), the service gets killed with
+                // the task, which might result in the notification being unable to be relaunched
+                // where it needs to be. kill and relaunch the old notification before stopping the
+                // service.
+                relaunchOldNotification(
+                        getNewNotificationIdFor(pinnedNotificationId), pinnedNotification);
+                stopForegroundInternal(ServiceCompat.STOP_FOREGROUND_REMOVE);
+            }
+        }
+        getService().stopSelf();
+    }
+
+    @VisibleForTesting
+    void relaunchOldNotification(int notificationId, Notification notification) {
+        if (notificationId != INVALID_NOTIFICATION_ID && notification != null) {
+            mNotificationManager.notify(notificationId, notification);
+        }
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        // In the case the service was restarted when the intent is null.
+        if (intent == null) {
+            DownloadNotificationUmaHelper.recordServiceStoppedHistogram(
+                    DownloadNotificationUmaHelper.ServiceStopped.START_STICKY, true);
+
+            // Allow observers to restart service on their own, if needed.
+            getService().stopSelf();
+        }
+
+        // This should restart service after Chrome gets killed (except for Android 4.4.2).
+        return Service.START_STICKY;
+    }
+
+    @Override
+    public void onDestroy() {
+        DownloadNotificationUmaHelper.recordServiceStoppedHistogram(
+                DownloadNotificationUmaHelper.ServiceStopped.DESTROYED, true /* withForeground */);
+        DownloadForegroundServiceObservers.alertObserversServiceDestroyed();
+        super.onDestroy();
+    }
+
+    @Override
+    public void onTaskRemoved(Intent rootIntent) {
+        DownloadNotificationUmaHelper.recordServiceStoppedHistogram(
+                DownloadNotificationUmaHelper.ServiceStopped.TASK_REMOVED, true /*withForeground*/);
+        DownloadForegroundServiceObservers.alertObserversTaskRemoved();
+        super.onTaskRemoved(rootIntent);
+    }
+
+    @Override
+    public void onLowMemory() {
+        DownloadNotificationUmaHelper.recordServiceStoppedHistogram(
+                DownloadNotificationUmaHelper.ServiceStopped.LOW_MEMORY, true /* withForeground */);
+        super.onLowMemory();
+    }
+
+    @Nullable
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+    /**
+     * Class for clients to access.
+     */
+    class LocalBinder extends Binder {
+        DownloadForegroundServiceImpl getService() {
+            return DownloadForegroundServiceImpl.this;
+        }
+    }
+
+    /** Methods for testing. */
+
+    @VisibleForTesting
+    int getNewNotificationIdFor(int oldNotificationId) {
+        return DownloadNotificationService.getNewNotificationIdFor(oldNotificationId);
+    }
+
+    @VisibleForTesting
+    void startForegroundInternal(int notificationId, Notification notification) {
+        Log.w(TAG, "startForegroundInternal id: " + notificationId);
+        ForegroundServiceUtils.getInstance().startForeground(
+                getService(), notificationId, notification, 0 /* foregroundServiceType */);
+    }
+
+    @VisibleForTesting
+    void stopForegroundInternal(int flags) {
+        Log.w(TAG, "stopForegroundInternal flags: " + flags);
+        ForegroundServiceUtils.getInstance().stopForeground(getService(), flags);
+    }
+
+    @VisibleForTesting
+    int getCurrentSdk() {
+        return Build.VERSION.SDK_INT;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManager.java
index ec2ad32..7678179 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManager.java
@@ -80,7 +80,7 @@
     private boolean mStartForegroundCalled;
 
     // This is non-null when onServiceConnected has been called (aka service is active).
-    private DownloadForegroundService mBoundService;
+    private DownloadForegroundServiceImpl mBoundService;
 
     @VisibleForTesting
     final Map<Integer, DownloadUpdate> mDownloadUpdateQueue = new HashMap<>();
@@ -221,7 +221,7 @@
 
     @VisibleForTesting
     void startAndBindServiceInternal(Context context) {
-        DownloadForegroundService.startDownloadForegroundService(context);
+        DownloadForegroundServiceImpl.startDownloadForegroundService(context);
         context.bindService(new Intent(context, DownloadForegroundService.class), mConnection,
                 Context.BIND_AUTO_CREATE);
     }
@@ -230,13 +230,13 @@
         @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
             Log.w(TAG, "onServiceConnected");
-            if (!(service instanceof DownloadForegroundService.LocalBinder)) {
+            if (!(service instanceof DownloadForegroundServiceImpl.LocalBinder)) {
                 Log.w(TAG,
                         "Not from DownloadNotificationService, do not connect."
                                 + " Component name: " + className);
                 return;
             }
-            mBoundService = ((DownloadForegroundService.LocalBinder) service).getService();
+            mBoundService = ((DownloadForegroundServiceImpl.LocalBinder) service).getService();
             DownloadForegroundServiceObservers.addObserver(
                     DownloadNotificationServiceObserver.class);
             processDownloadUpdateQueue(true /* isProcessingPending */);
@@ -307,13 +307,14 @@
         checkNotNull(mBoundService);
         mIsServiceBound = false;
 
-        @DownloadForegroundService.StopForegroundNotification
+        @DownloadForegroundServiceImpl.StopForegroundNotification
         int stopForegroundNotification;
         if (downloadStatus == DownloadNotificationService.DownloadStatus.CANCELLED) {
-            stopForegroundNotification = DownloadForegroundService.StopForegroundNotification.KILL;
+            stopForegroundNotification =
+                    DownloadForegroundServiceImpl.StopForegroundNotification.KILL;
         } else {
             stopForegroundNotification =
-                    DownloadForegroundService.StopForegroundNotification.DETACH;
+                    DownloadForegroundServiceImpl.StopForegroundNotification.DETACH;
         }
 
         DownloadUpdate downloadUpdate = mDownloadUpdateQueue.get(mPinnedNotificationId);
@@ -330,7 +331,7 @@
 
     @VisibleForTesting
     void stopAndUnbindServiceInternal(
-            @DownloadForegroundService.StopForegroundNotification int stopForegroundStatus,
+            @DownloadForegroundServiceImpl.StopForegroundNotification int stopForegroundStatus,
             int pinnedNotificationId, Notification pinnedNotification) {
         mBoundService.stopDownloadForegroundService(
                 stopForegroundStatus, pinnedNotificationId, pinnedNotification);
@@ -343,7 +344,7 @@
     /** Helper code for testing. */
 
     @VisibleForTesting
-    void setBoundService(DownloadForegroundService service) {
+    void setBoundService(DownloadForegroundServiceImpl service) {
         mBoundService = service;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java
index ba7e11a..ba3fc17 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAndUMAFirstRunFragment.java
@@ -16,11 +16,10 @@
 import android.widget.TextView;
 
 import androidx.annotation.VisibleForTesting;
-import androidx.core.view.ViewCompat;
 import androidx.fragment.app.Fragment;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.signin.ChildAccountStatus;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
 import org.chromium.ui.text.SpanApplier;
@@ -80,11 +79,6 @@
             }
         });
 
-        int paddingStart = getResources().getDimensionPixelSize(R.dimen.fre_tos_checkbox_padding);
-        ViewCompat.setPaddingRelative(mSendReportCheckBox,
-                ViewCompat.getPaddingStart(mSendReportCheckBox) + paddingStart,
-                mSendReportCheckBox.getPaddingTop(), ViewCompat.getPaddingEnd(mSendReportCheckBox),
-                mSendReportCheckBox.getPaddingBottom());
         mSendReportCheckBox.setChecked(FirstRunActivity.DEFAULT_METRICS_AND_CRASH_REPORTING);
 
         if (!canShowUmaCheckBox()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryDeletionInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryDeletionInfo.java
index b71abd1..db99a9a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryDeletionInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryDeletionInfo.java
@@ -45,26 +45,10 @@
         return HistoryDeletionInfoJni.get().isTimeRangeForAllTime(mHistoryDeletionInfoPtr);
     }
 
-    /**
-     * @return The beginning of the time range if the time range is valid.
-     */
-    public long getTimeRangeBegin() {
-        return HistoryDeletionInfoJni.get().getTimeRangeBegin(mHistoryDeletionInfoPtr);
-    }
-
-    /**
-     * @return The end of the time range if the time range is valid.
-     */
-    public long getTimeRangeEnd() {
-        return HistoryDeletionInfoJni.get().getTimeRangeBegin(mHistoryDeletionInfoPtr);
-    }
-
     @NativeMethods
     interface Natives {
         String[] getDeletedURLs(long historyDeletionInfoPtr);
         boolean isTimeRangeValid(long historyDeletionInfoPtr);
         boolean isTimeRangeForAllTime(long historyDeletionInfoPtr);
-        long getTimeRangeBegin(long historyDeletionInfoPtr);
-        long getTimeRangeEnd(long historyDeletionInfoPtr);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGenerator.java b/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGenerator.java
index 35f771f6..3605b959 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGenerator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGenerator.java
@@ -4,20 +4,9 @@
 
 package org.chromium.chrome.browser.identity;
 
-import androidx.annotation.Nullable;
-
 /**
  * Interface used for uniquely identifying an installation of Chrome. To get an instance you should
  * use {@link UniqueIdentificationGeneratorFactory}.
  */
-public interface UniqueIdentificationGenerator {
-    /**
-     * Creates a string that uniquely identifies this installation.
-     * <p/>
-     * If there is an error in generating the string, an empty string must be returned, not null.
-     *
-     * @param salt the salt to use for the unique ID.
-     * @return a unique ID. On failure to generate, it must return the empty string.
-     */
-    String getUniqueId(@Nullable String salt);
-}
+public interface UniqueIdentificationGenerator
+        extends org.chromium.chrome.browser.uid.UniqueIdentificationGenerator {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactory.java
index 9780f57..3205138e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactory.java
@@ -4,11 +4,6 @@
 
 package org.chromium.chrome.browser.identity;
 
-import androidx.annotation.VisibleForTesting;
-
-import java.util.HashMap;
-import java.util.Map;
-
 /**
  * Factory for setting and retrieving instances of {@link UniqueIdentificationGenerator}s.
  * <p/>
@@ -17,27 +12,6 @@
  * field in the generator itself.
  */
 public final class UniqueIdentificationGeneratorFactory {
-    private static final Object LOCK = new Object();
-    private static final Map<String, UniqueIdentificationGenerator> GENERATOR_MAP =
-            new HashMap<String, UniqueIdentificationGenerator>();
-
-    private UniqueIdentificationGeneratorFactory() {
-    }
-
-    /**
-     * Returns a UniqueIdentificationGenerator if it exists, else throws IllegalArgumentException.
-     *
-     * @param generatorType the generator type you want
-     * @return a unique ID generator
-     */
-    public static UniqueIdentificationGenerator getInstance(String generatorType) {
-        synchronized (LOCK) {
-            if (!GENERATOR_MAP.containsKey(generatorType)) {
-                throw new IllegalArgumentException("Unknown generator type " + generatorType);
-            }
-            return GENERATOR_MAP.get(generatorType);
-        }
-    }
 
     /**
      * During startup of the application, and before any calls to
@@ -51,18 +25,8 @@
      */
     public static void registerGenerator(String generatorType, UniqueIdentificationGenerator gen,
                                          boolean force) {
-        synchronized (LOCK) {
-            if (GENERATOR_MAP.containsKey(generatorType) && !force) {
-                return;
-            }
-            GENERATOR_MAP.put(generatorType, gen);
-        }
-    }
-
-    @VisibleForTesting
-    public static void clearGeneratorMapForTest() {
-        synchronized (LOCK) {
-            GENERATOR_MAP.clear();
-        }
+        // TODO(crbug.com/1131415): remove this file after the downstream is updated.
+        org.chromium.chrome.browser.uid.UniqueIdentificationGeneratorFactory.registerGenerator(
+                generatorType, gen, force);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncher.java
index d0854818..9c5c01f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabLauncher.java
@@ -24,10 +24,10 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.chrome.browser.ChromeApplication;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.customtabs.CustomTabsConnection;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 
 /**
  * An exposed Activity that allows launching an Incognito Tab.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitTaskRunner.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitTaskRunner.java
index 1b2f9de..017a891 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitTaskRunner.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitTaskRunner.java
@@ -15,8 +15,8 @@
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
 import org.chromium.chrome.browser.ChromeActivitySessionTracker;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.flags.CachedFeatureFlags;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.variations.firstrun.VariationsSeedFetcher;
 import org.chromium.content_public.browser.ChildProcessLauncherHelper;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
index dc215e92..e0c17ad1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -51,8 +51,6 @@
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.history.HistoryDeletionBridge;
 import org.chromium.chrome.browser.homepage.HomepageManager;
-import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
-import org.chromium.chrome.browser.identity.UuidBasedUniqueIdentificationGenerator;
 import org.chromium.chrome.browser.incognito.IncognitoTabLauncher;
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.media.MediaCaptureNotificationService;
@@ -75,6 +73,8 @@
 import org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardShareActivity;
 import org.chromium.chrome.browser.signin.SigninHelper;
 import org.chromium.chrome.browser.sync.SyncController;
+import org.chromium.chrome.browser.uid.UniqueIdentificationGeneratorFactory;
+import org.chromium.chrome.browser.uid.UuidBasedUniqueIdentificationGenerator;
 import org.chromium.chrome.browser.webapps.WebApkVersionManager;
 import org.chromium.chrome.browser.webapps.WebappRegistry;
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
@@ -83,6 +83,7 @@
 import org.chromium.components.browser_ui.photo_picker.PhotoPickerDialog;
 import org.chromium.components.browser_ui.share.ShareImageFileUtils;
 import org.chromium.components.browser_ui.util.ConversionUtils;
+import org.chromium.components.content_capture.ContentCaptureController;
 import org.chromium.components.minidump_uploader.CrashFileManager;
 import org.chromium.components.signin.AccountManagerFacadeImpl;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
@@ -259,8 +260,8 @@
                 });
 
         SearchWidgetProvider.initialize();
-        HistoryDeletionBridge.getInstance().addObserver(
-                new ContentCaptureHistoryDeletionObserver());
+        HistoryDeletionBridge.getInstance().addObserver(new ContentCaptureHistoryDeletionObserver(
+                () -> ContentCaptureController.getInstance()));
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobService.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobService.java
index 62110db..190d6ee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobService.java
@@ -1,96 +1,14 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 package org.chromium.chrome.browser.notifications;
 
-import android.annotation.TargetApi;
-import android.app.job.JobParameters;
-import android.app.job.JobService;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.PersistableBundle;
-import android.os.SystemClock;
+import org.chromium.chrome.browser.base.SplitCompatJobService;
 
-import org.chromium.base.ThreadUtils;
-
-/**
- * Processes jobs scheduled when user actions are issued on web notifications.
- * We use this instead of starting the NotificationService on N+.
- */
-@TargetApi(Build.VERSION_CODES.N)
-public class NotificationJobService extends JobService {
-    static PersistableBundle getJobExtrasFromIntent(Intent intent) {
-        PersistableBundle bundle = new PersistableBundle();
-        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_ID,
-                intent.getStringExtra(NotificationConstants.EXTRA_NOTIFICATION_ID));
-        bundle.putInt(NotificationConstants.EXTRA_NOTIFICATION_TYPE,
-                intent.getIntExtra(NotificationConstants.EXTRA_NOTIFICATION_TYPE,
-                        NotificationType.WEB_PERSISTENT));
-        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN,
-                intent.getStringExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN));
-        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_INFO_SCOPE,
-                intent.getStringExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_SCOPE));
-        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_ID,
-                intent.getStringExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_ID));
-        bundle.putBoolean(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_INCOGNITO,
-                intent.getBooleanExtra(
-                        NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_INCOGNITO, false));
-        bundle.putInt(NotificationConstants.EXTRA_NOTIFICATION_INFO_ACTION_INDEX,
-                intent.getIntExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ACTION_INDEX, -1));
-        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_INFO_WEBAPK_PACKAGE,
-                intent.getStringExtra(
-                        NotificationConstants.EXTRA_NOTIFICATION_INFO_WEBAPK_PACKAGE));
-        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_ACTION, intent.getAction());
-        // Only primitives can be set on a persistable bundle, so extract the raw reply.
-        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_REPLY,
-                NotificationPlatformBridge.getNotificationReply(intent));
-        return bundle;
-    }
-
-    /**
-     * Called when a Notification has been interacted with by the user. If we can verify that
-     * the Intent has a notification Id, start Chrome (if needed) on the UI thread.
-     *
-     * We get a wakelock for our process for the duration of this method.
-     *
-     * @return True if there is more work to be done to handle the job, to signal we would like our
-     * wakelock extended until we call {@link #jobFinished}. False if we have finished handling the
-     * job.
-     */
-    @Override
-    public boolean onStartJob(final JobParameters params) {
-        PersistableBundle extras = params.getExtras();
-        putJobStartedTimeInExtras(extras);
-        if (!extras.containsKey(NotificationConstants.EXTRA_NOTIFICATION_ID)
-                || !extras.containsKey(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN)) {
-            return false;
-        }
-
-        Intent intent =
-                new Intent(extras.getString(NotificationConstants.EXTRA_NOTIFICATION_ACTION));
-        intent.putExtras(new Bundle(extras));
-
-        ThreadUtils.assertOnUiThread();
-        NotificationService.dispatchIntentOnUIThread(intent);
-
-        // TODO(crbug.com/685197): Return true here and call jobFinished to release the wake
-        // lock only after the event has been completely handled by the service worker.
-        return false;
-    }
-
-    private static void putJobStartedTimeInExtras(PersistableBundle extras) {
-        extras.putLong(
-                NotificationConstants.EXTRA_JOB_STARTED_TIME_MS, SystemClock.elapsedRealtime());
-    }
-
-    @Override
-    public boolean onStopJob(JobParameters params) {
-        // As it stands, all our job processing is done synchronously in onStartJob so there is
-        // nothing to do here. Even once we include further async processing in our jobs
-        // (crbug.com/685197) it may by infeasible to cancel this halfway through.
-        // TODO(crbug.com/685197): Check what we can safely do here and update comment.
-        return false;
+/** See {@link NotificationJobServiceImpl}. */
+public class NotificationJobService extends SplitCompatJobService {
+    public NotificationJobService() {
+        super("org.chromium.chrome.browser.notifications.NotificationJobServiceImpl");
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobServiceImpl.java
new file mode 100644
index 0000000..39d5054
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationJobServiceImpl.java
@@ -0,0 +1,100 @@
+// 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.
+
+package org.chromium.chrome.browser.notifications;
+
+import android.annotation.TargetApi;
+import android.app.job.JobParameters;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.os.SystemClock;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.UsedByReflection;
+
+/**
+ * Processes jobs scheduled when user actions are issued on web notifications.
+ * We use this instead of starting the NotificationService on N+.
+ */
+@UsedByReflection("NotificationService.java")
+@TargetApi(Build.VERSION_CODES.N)
+public class NotificationJobServiceImpl extends NotificationJobService.Impl {
+    @UsedByReflection("NotificationService.java")
+    public NotificationJobServiceImpl() {}
+
+    static PersistableBundle getJobExtrasFromIntent(Intent intent) {
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_ID,
+                intent.getStringExtra(NotificationConstants.EXTRA_NOTIFICATION_ID));
+        bundle.putInt(NotificationConstants.EXTRA_NOTIFICATION_TYPE,
+                intent.getIntExtra(NotificationConstants.EXTRA_NOTIFICATION_TYPE,
+                        NotificationType.WEB_PERSISTENT));
+        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN,
+                intent.getStringExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN));
+        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_INFO_SCOPE,
+                intent.getStringExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_SCOPE));
+        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_ID,
+                intent.getStringExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_ID));
+        bundle.putBoolean(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_INCOGNITO,
+                intent.getBooleanExtra(
+                        NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_INCOGNITO, false));
+        bundle.putInt(NotificationConstants.EXTRA_NOTIFICATION_INFO_ACTION_INDEX,
+                intent.getIntExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ACTION_INDEX, -1));
+        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_INFO_WEBAPK_PACKAGE,
+                intent.getStringExtra(
+                        NotificationConstants.EXTRA_NOTIFICATION_INFO_WEBAPK_PACKAGE));
+        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_ACTION, intent.getAction());
+        // Only primitives can be set on a persistable bundle, so extract the raw reply.
+        bundle.putString(NotificationConstants.EXTRA_NOTIFICATION_REPLY,
+                NotificationPlatformBridge.getNotificationReply(intent));
+        return bundle;
+    }
+
+    /**
+     * Called when a Notification has been interacted with by the user. If we can verify that
+     * the Intent has a notification Id, start Chrome (if needed) on the UI thread.
+     *
+     * We get a wakelock for our process for the duration of this method.
+     *
+     * @return True if there is more work to be done to handle the job, to signal we would like our
+     * wakelock extended until we call {@link #jobFinished}. False if we have finished handling the
+     * job.
+     */
+    @Override
+    public boolean onStartJob(final JobParameters params) {
+        PersistableBundle extras = params.getExtras();
+        putJobStartedTimeInExtras(extras);
+        if (!extras.containsKey(NotificationConstants.EXTRA_NOTIFICATION_ID)
+                || !extras.containsKey(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN)) {
+            return false;
+        }
+
+        Intent intent =
+                new Intent(extras.getString(NotificationConstants.EXTRA_NOTIFICATION_ACTION));
+        intent.putExtras(new Bundle(extras));
+
+        ThreadUtils.assertOnUiThread();
+        NotificationServiceImpl.dispatchIntentOnUIThread(intent);
+
+        // TODO(crbug.com/685197): Return true here and call jobFinished to release the wake
+        // lock only after the event has been completely handled by the service worker.
+        return false;
+    }
+
+    private static void putJobStartedTimeInExtras(PersistableBundle extras) {
+        extras.putLong(
+                NotificationConstants.EXTRA_JOB_STARTED_TIME_MS, SystemClock.elapsedRealtime());
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        // As it stands, all our job processing is done synchronously in onStartJob so there is
+        // nothing to do here. Even once we include further async processing in our jobs
+        // (crbug.com/685197) it may by infeasible to cancel this halfway through.
+        // TODO(crbug.com/685197): Check what we can safely do here and update comment.
+        return false;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
index cf9d0ae..ede170ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
@@ -327,7 +327,7 @@
             int actionIndex) {
         Uri intentData = makeIntentData(notificationId, origin, actionIndex);
         Intent intent = new Intent(action, intentData);
-        intent.setClass(context, NotificationService.Receiver.class);
+        intent.setClass(context, NotificationServiceImpl.Receiver.class);
 
         // Make sure to update NotificationJobService.getJobExtrasFromIntent() when changing any
         // of the extras included with the |intent|.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java
index c72c141..ff173b64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java
@@ -1,119 +1,34 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 package org.chromium.chrome.browser.notifications;
 
-import android.annotation.TargetApi;
-import android.app.IntentService;
-import android.app.job.JobInfo;
-import android.app.job.JobScheduler;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
-import android.os.PersistableBundle;
-import android.os.SystemClock;
-import android.util.Log;
 
-import org.chromium.base.task.PostTask;
-import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
-import org.chromium.chrome.browser.webapps.WebappRegistry;
-import org.chromium.components.background_task_scheduler.TaskIds;
-import org.chromium.content_public.browser.UiThreadTaskTraits;
+import org.chromium.chrome.browser.base.SplitCompatIntentService;
+import org.chromium.chrome.browser.base.SplitCompatUtils;
 
-/**
- * The Notification service receives intents fired as responses to user actions issued on Android
- * notifications displayed in the notification tray.
- */
-public class NotificationService extends IntentService {
+/** See {@link NotificationServiceImpl}. */
+public class NotificationService extends SplitCompatIntentService {
     private static final String TAG = NotificationService.class.getSimpleName();
 
+    public NotificationService() {
+        super("org.chromium.chrome.browser.notifications.NotificationServiceImpl", TAG);
+    }
+
     /**
-     * The class which receives the intents from the Android framework. It initializes the
-     * Notification service, and forward the intents there. Declared public as it needs to be
-     * initialized by the Android framework.
+     * This receiver forwards the onReceive() call to the implementation version. This is needed to
+     * handle pending intents referring to the old receiver name.
      */
     public static class Receiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            Log.i(TAG, "Received a notification intent in the NotificationService's receiver.");
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                // Android encourages us not to start services directly on N+, so instead we
-                // schedule a job to handle the notification intent. We use the Android JobScheduler
-                // rather than GcmNetworkManager or FirebaseJobDispatcher since the JobScheduler
-                // allows us to execute immediately by setting an override deadline of zero
-                // milliseconds.
-                JobScheduler scheduler =
-                        (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
-                PersistableBundle extras = NotificationJobService.getJobExtrasFromIntent(intent);
-                putJobScheduledTimeInExtras(extras);
-                JobInfo job =
-                        new JobInfo
-                                .Builder(TaskIds.NOTIFICATION_SERVICE_JOB_ID,
-                                        new ComponentName(context, NotificationJobService.class))
-                                .setExtras(extras)
-                                .setOverrideDeadline(0)
-                                .build();
-                scheduler.schedule(job);
-            } else {
-                // TODO(peter): Do we need to acquire a wake lock here?
-
-                intent.setClass(context, NotificationService.class);
-                context.startService(intent);
-            }
+            BroadcastReceiver receiver = (BroadcastReceiver) SplitCompatUtils.newInstance(context,
+                    "org.chromium.chrome.browser.notifications.NotificationServiceImpl$Receiver");
+            receiver.onReceive(context, intent);
         }
-
-        @TargetApi(Build.VERSION_CODES.N)
-        private static void putJobScheduledTimeInExtras(PersistableBundle extras) {
-            extras.putLong(NotificationConstants.EXTRA_JOB_SCHEDULED_TIME_MS,
-                    SystemClock.elapsedRealtime());
-        }
-    }
-
-    public NotificationService() {
-        super(TAG);
-    }
-
-    /**
-     * Called when a Notification has been interacted with by the user. If we can verify that
-     * the Intent has a notification Id, start Chrome (if needed) on the UI thread.
-     *
-     * @param intent The intent containing the specific information.
-     */
-    @Override
-    public void onHandleIntent(final Intent intent) {
-        if (!intent.hasExtra(NotificationConstants.EXTRA_NOTIFICATION_ID)
-                || !intent.hasExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN)) {
-            return;
-        }
-
-        PostTask.runOrPostTask(
-                UiThreadTaskTraits.DEFAULT, () -> { dispatchIntentOnUIThread(intent); });
-    }
-
-    /**
-     * Initializes Chrome and starts the browser process if it's not running as of yet, and
-     * dispatch |intent| to the NotificationPlatformBridge once this is done.
-     *
-     * @param intent The intent containing the notification's information.
-     */
-    static void dispatchIntentOnUIThread(Intent intent) {
-        ChromeBrowserInitializer.getInstance().handleSynchronousStartup();
-
-        // Warm up the WebappRegistry, as we need to check if this notification should launch a
-        // standalone web app. This no-ops if the registry is already initialized and warmed.
-        WebappRegistry.getInstance();
-        WebappRegistry.warmUpSharedPrefs();
-
-        // Now that the browser process is initialized, we pass forward the call to the
-        // NotificationPlatformBridge which will take care of delivering the appropriate events.
-        if (!NotificationPlatformBridge.dispatchNotificationEvent(intent)) {
-            Log.w(TAG, "Unable to dispatch the notification event to Chrome.");
-        }
-
-        // TODO(peter): Verify that the lifetime of the NotificationService is sufficient
-        // when a notification event could be dispatched successfully.
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationServiceImpl.java
new file mode 100644
index 0000000..8b044b5
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationServiceImpl.java
@@ -0,0 +1,120 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.notifications;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.PersistableBundle;
+import android.os.SystemClock;
+import android.util.Log;
+
+import org.chromium.base.annotations.UsedByReflection;
+import org.chromium.base.task.PostTask;
+import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
+import org.chromium.chrome.browser.webapps.WebappRegistry;
+import org.chromium.components.background_task_scheduler.TaskIds;
+import org.chromium.content_public.browser.UiThreadTaskTraits;
+
+/**
+ * The Notification service receives intents fired as responses to user actions issued on Android
+ * notifications displayed in the notification tray.
+ */
+@UsedByReflection("NotificationService.java")
+public class NotificationServiceImpl extends NotificationService.Impl {
+    private static final String TAG = NotificationServiceImpl.class.getSimpleName();
+
+    /**
+     * The class which receives the intents from the Android framework. It initializes the
+     * Notification service, and forward the intents there. Declared public as it needs to be
+     * initialized by the Android framework.
+     */
+    public static class Receiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.i(TAG, "Received a notification intent in the NotificationService's receiver.");
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                // Android encourages us not to start services directly on N+, so instead we
+                // schedule a job to handle the notification intent. We use the Android JobScheduler
+                // rather than GcmNetworkManager or FirebaseJobDispatcher since the JobScheduler
+                // allows us to execute immediately by setting an override deadline of zero
+                // milliseconds.
+                JobScheduler scheduler =
+                        (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+                PersistableBundle extras =
+                        NotificationJobServiceImpl.getJobExtrasFromIntent(intent);
+                putJobScheduledTimeInExtras(extras);
+                JobInfo job =
+                        new JobInfo
+                                .Builder(TaskIds.NOTIFICATION_SERVICE_JOB_ID,
+                                        new ComponentName(context, NotificationJobService.class))
+                                .setExtras(extras)
+                                .setOverrideDeadline(0)
+                                .build();
+                scheduler.schedule(job);
+            } else {
+                // TODO(peter): Do we need to acquire a wake lock here?
+
+                intent.setClass(context, NotificationService.class);
+                context.startService(intent);
+            }
+        }
+
+        @TargetApi(Build.VERSION_CODES.N)
+        private static void putJobScheduledTimeInExtras(PersistableBundle extras) {
+            extras.putLong(NotificationConstants.EXTRA_JOB_SCHEDULED_TIME_MS,
+                    SystemClock.elapsedRealtime());
+        }
+    }
+
+    @UsedByReflection("NotificationService.java")
+    public NotificationServiceImpl() {}
+
+    /**
+     * Called when a Notification has been interacted with by the user. If we can verify that
+     * the Intent has a notification Id, start Chrome (if needed) on the UI thread.
+     *
+     * @param intent The intent containing the specific information.
+     */
+    @Override
+    public void onHandleIntent(final Intent intent) {
+        if (!intent.hasExtra(NotificationConstants.EXTRA_NOTIFICATION_ID)
+                || !intent.hasExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN)) {
+            return;
+        }
+
+        PostTask.runOrPostTask(
+                UiThreadTaskTraits.DEFAULT, () -> { dispatchIntentOnUIThread(intent); });
+    }
+
+    /**
+     * Initializes Chrome and starts the browser process if it's not running as of yet, and
+     * dispatch |intent| to the NotificationPlatformBridge once this is done.
+     *
+     * @param intent The intent containing the notification's information.
+     */
+    static void dispatchIntentOnUIThread(Intent intent) {
+        ChromeBrowserInitializer.getInstance().handleSynchronousStartup();
+
+        // Warm up the WebappRegistry, as we need to check if this notification should launch a
+        // standalone web app. This no-ops if the registry is already initialized and warmed.
+        WebappRegistry.getInstance();
+        WebappRegistry.warmUpSharedPrefs();
+
+        // Now that the browser process is initialized, we pass forward the call to the
+        // NotificationPlatformBridge which will take care of delivering the appropriate events.
+        if (!NotificationPlatformBridge.dispatchNotificationEvent(intent)) {
+            Log.w(TAG, "Unable to dispatch the notification event to Chrome.");
+        }
+
+        // TODO(peter): Verify that the lifetime of the NotificationService is sufficient
+        // when a notification event could be dispatched successfully.
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineDetector.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineDetector.java
index d28e028..8b534480 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineDetector.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineDetector.java
@@ -15,9 +15,9 @@
 import org.chromium.base.Callback;
 import org.chromium.base.Log;
 import org.chromium.base.supplier.Supplier;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.offlinepages.indicator.ConnectivityDetector.ConnectionState;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.variations.VariationsAssociatedData;
 
 /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java
index 92879e7b..41610a2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/OmahaBase.java
@@ -18,7 +18,7 @@
 import org.chromium.base.Log;
 import org.chromium.base.StreamUtil;
 import org.chromium.base.ThreadUtils;
-import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
index 3c7e92696..b135fdf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
@@ -14,8 +14,8 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import org.chromium.base.BuildInfo;
-import org.chromium.chrome.browser.identity.SettingsSecureBasedIdentificationGenerator;
-import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
+import org.chromium.chrome.browser.uid.SettingsSecureBasedIdentificationGenerator;
+import org.chromium.chrome.browser.uid.UniqueIdentificationGeneratorFactory;
 import org.chromium.ui.base.DeviceFormFactor;
 
 import java.io.IOException;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksShim.java b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksShim.java
index 819eaf3..375443c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksShim.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksShim.java
@@ -7,8 +7,8 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 
 /**
  * The Java counterpart for the C++ partner bookmarks shim.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java b/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java
index 088531d..cb15407b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/PartnerBrowserCustomizations.java
@@ -21,9 +21,9 @@
 import org.chromium.base.task.AsyncTask;
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.AppHooks;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.ntp.NewTabPage;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.embedder_support.util.UrlConstants;
 import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerCoordinator.java
index be4cd7a..c8417d5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerCoordinator.java
@@ -6,10 +6,10 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.payments.handler.toolbar.PaymentHandlerToolbarCoordinator;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
 import org.chromium.components.embedder_support.view.ContentView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
index dcabb36..d42de57 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -37,7 +37,6 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.Callback;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.autofill.prefeditor.EditorDialog;
 import org.chromium.chrome.browser.autofill.prefeditor.EditorObserverForTest;
 import org.chromium.chrome.browser.lifecycle.PauseResumeWithNativeObserver;
@@ -48,6 +47,7 @@
 import org.chromium.chrome.browser.payments.ui.PaymentUIsManager.PaymentUisShowStateReconciler;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.IdentityServicesProvider;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.autofill.EditableOption;
 import org.chromium.components.browser_ui.widget.FadingEdgeScrollView;
 import org.chromium.components.browser_ui.widget.animation.FocusAnimator;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java b/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java
index a2aed4ca..98fda62 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java
@@ -12,9 +12,9 @@
 import android.os.Messenger;
 
 import org.chromium.chrome.browser.AppHooks;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.externalauth.ExternalAuthUtils;
 import org.chromium.chrome.browser.externalauth.VerifiedHandler;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 
 /**
  * A bound service that does nothing. Kept here to prevent old clients relying on it being
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java
index f79e64fc..f686bdb0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java
@@ -10,8 +10,8 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
-import org.chromium.chrome.browser.identity.SettingsSecureBasedIdentificationGenerator;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.uid.SettingsSecureBasedIdentificationGenerator;
 
 import java.util.List;
 import java.util.Locale;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java
index 03e6401..fe6e6b9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java
@@ -9,7 +9,6 @@
 import androidx.annotation.Nullable;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.omaha.VersionNumber;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
@@ -20,6 +19,7 @@
 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager.SnackbarController;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 
 import java.util.concurrent.TimeUnit;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java
index 8602a9c..348fe787 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java
@@ -14,9 +14,9 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountUtils;
 import org.chromium.components.signin.base.CoreAccountInfo;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java
index a847b2e..9f875f7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivity.java
@@ -28,7 +28,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.about_settings.AboutChromeSettings;
 import org.chromium.chrome.browser.init.BrowserParts;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
@@ -40,6 +39,7 @@
 import org.chromium.chrome.browser.searchwidget.SearchWidgetProvider;
 import org.chromium.chrome.browser.settings.SettingsLauncher;
 import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.browser_ui.site_settings.AllSiteSettings;
 import org.chromium.components.browser_ui.site_settings.SingleCategorySettings;
 import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
index ecf89e6..b98aede 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java
@@ -18,7 +18,6 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.task.AsyncTask;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
@@ -35,6 +34,7 @@
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.infobars.InfoBarAnimationListener;
 import org.chromium.components.infobars.InfoBarUiItem;
 import org.chromium.components.variations.VariationsAssociatedData;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
index 27c9182..f0cc5985 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/SyncController.java
@@ -12,11 +12,11 @@
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.chrome.browser.identity.UniqueIdentificationGenerator;
-import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.SigninManager;
+import org.chromium.chrome.browser.uid.UniqueIdentificationGenerator;
+import org.chromium.chrome.browser.uid.UniqueIdentificationGeneratorFactory;
 import org.chromium.components.sync.ModelType;
 import org.chromium.components.sync.PassphraseType;
 import org.chromium.components.sync.StopSource;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
index bf259e7..7f0f324 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -25,6 +25,7 @@
   "+chrome/browser/preferences",
   "+chrome/browser/tab",
   "+chrome/browser/ui/android/native_page",
+  "+chrome/browser/version",
   "+components/browser_ui/styles/android",
   "+components/browser_ui/widget/android",
   "+content/public/android/java/src/org/chromium/content_public",
@@ -47,7 +48,6 @@
   'TabImpl\.java': [
     "+chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java",
-    "+chrome/android/java/src/org/chromium/chrome/browser/ChromeVersionInfo.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/WebContentsFactory.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/content/ContentUtils.java",
@@ -70,9 +70,6 @@
     "+ui/android/java/src/org/chromium/ui/base",
     "+ui/android/java/src/org/chromium/ui/mojom",
   ],
-  'TabStateFileManager\.java': [
-    "+chrome/android/java/src/org/chromium/chrome/browser/ChromeVersionInfo.java",
-  ],
   'TabStateBrowserControlsVisibilityDelegate\.java': [
     "+chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/ChromeAccessibilityUtil.java",
   ],
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
index 68b45557..cdbbb8af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -25,7 +25,6 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.WarmupManager;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.app.ChromeActivity;
@@ -42,6 +41,7 @@
 import org.chromium.chrome.browser.ui.TabObscuringHandler;
 import org.chromium.chrome.browser.ui.native_page.FrozenNativePage;
 import org.chromium.chrome.browser.ui.native_page.NativePage;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
 import org.chromium.components.embedder_support.util.UrlConstants;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateFileManager.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateFileManager.java
index 6341e7db..9e24bfc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateFileManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateFileManager.java
@@ -10,8 +10,8 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.StreamUtil;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.crypto.CipherFactory;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 
 import java.io.BufferedOutputStream;
 import java.io.DataInputStream;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/JourneyManager.java b/chrome/android/java/src/org/chromium/chrome/browser/tasks/JourneyManager.java
index 7ce51f370..05eec56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/JourneyManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/JourneyManager.java
@@ -14,7 +14,6 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.AsyncTask;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
@@ -27,6 +26,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.NavigationHandle;
 import org.chromium.ui.base.PageTransition;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 6c423a5..eacaabd0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -322,6 +322,7 @@
         mToolbar = createTopToolbarCoordinator(controlContainer, toolbarLayout, buttonDataProviders,
                 browsingModeThemeColorProvider, startSurfaceMenuButtonCoordinator, invalidator,
                 identityDiscController);
+
         mActionModeController =
                 new ActionModeController(mActivity, mActionBarDelegate, toolbarActionModeCallback);
 
@@ -731,7 +732,8 @@
 
         mToolbar.initializeWithNative(layoutManager::requestUpdate, tabSwitcherClickHandler,
                 tabSwitcherLongClickHandler, newTabClickHandler, bookmarkClickHandler,
-                customTabsBackClickHandler);
+                customTabsBackClickHandler, layoutManager, mActivityTabProvider,
+                mBrowserControlsSizer);
 
         mToolbar.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
index 8ada087..9d61264 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarLayout.java
@@ -28,6 +28,8 @@
 import org.chromium.base.TraceEvent;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
+import org.chromium.chrome.browser.compositor.overlays.toolbar.TopToolbarOverlayCoordinator;
+import org.chromium.chrome.browser.findinpage.FindToolbar;
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omnibox.LocationBar;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
@@ -83,6 +85,8 @@
     private MenuButtonCoordinator mMenuButtonCoordinator;
     private AppMenuButtonHelper mAppMenuButtonHelper;
 
+    private TopToolbarOverlayCoordinator mOverlayCoordinator;
+
     /**
      * Basic constructor for {@link ToolbarLayout}.
      */
@@ -119,6 +123,20 @@
         mMenuButtonCoordinator = menuButtonCoordinator;
     }
 
+    /** @param overlay The coordinator for the texture version of the top toolbar. */
+    void setOverlayCoordinator(TopToolbarOverlayCoordinator overlay) {
+        mOverlayCoordinator = overlay;
+        mOverlayCoordinator.setIsAndroidViewVisible(getVisibility() == View.VISIBLE);
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+        if (mOverlayCoordinator != null) {
+            mOverlayCoordinator.setIsAndroidViewVisible(visibility == View.VISIBLE);
+        }
+    }
+
     /**
      * @param appMenuButtonHelper The helper for managing menu button interactions.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
index ced8a04..ed9a5b8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -20,7 +20,14 @@
 import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ActivityTabProvider;
+import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
+import org.chromium.chrome.browser.compositor.Invalidator;
+import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
+import org.chromium.chrome.browser.compositor.overlays.toolbar.TopToolbarOverlayCoordinator;
+import org.chromium.chrome.browser.device.DeviceClassManager;
+import org.chromium.chrome.browser.findinpage.FindToolbar;
 import org.chromium.chrome.browser.omnibox.LocationBar;
 import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -36,6 +43,7 @@
 import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
 import org.chromium.chrome.browser.user_education.UserEducationHelper;
 import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration;
+import org.chromium.components.browser_ui.widget.ClipDrawableProgressBar;
 
 import java.util.List;
 
@@ -79,6 +87,9 @@
     private ObservableSupplier<AppMenuButtonHelper> mAppMenuButtonHelperSupplier;
     private CallbackController mCallbackController = new CallbackController();
     private ObservableSupplier<TabModelSelector> mTabModelSelectorSupplier;
+    private TopToolbarOverlayCoordinator mOverlayCoordinator;
+
+    private Callback<ClipDrawableProgressBar.DrawingInfo> mProgressDrawInfoCallback;
 
     /**
      * Creates a new {@link TopToolbarCoordinator}.
@@ -118,6 +129,10 @@
         mMenuButtonCoordinator = browsingModeMenuButtonCoordinator;
         mOptionalButtonController = new OptionalBrowsingModeButtonController(buttonDataProviders,
                 userEducationHelper, mToolbarLayout, () -> toolbarDataProvider.getTab());
+        mProgressDrawInfoCallback = (info) -> {
+            if (controlContainer == null) return;
+            controlContainer.getProgressBarDrawingInfo(info);
+        };
 
         overviewModeBehaviorSupplier.onAvailable(
                 mCallbackController.makeCancelable(this::setOverviewModeBehavior));
@@ -165,11 +180,16 @@
      * @param newTabClickHandler The click handler for the new tab button.
      * @param bookmarkClickHandler The click handler for the bookmarks button.
      * @param customTabsBackClickHandler The click handler for the custom tabs back button.
+     * @param layoutManager A means of adding SceneOverlays.
+     * @param tabProvider A means of accessing the currently active tab.
+     * @param browserControlsStateProvider Access to the state of the browser controls.
      */
     public void initializeWithNative(Runnable layoutUpdater,
             OnClickListener tabSwitcherClickHandler,
             OnLongClickListener tabSwitcherLongClickHandler, OnClickListener newTabClickHandler,
-            OnClickListener bookmarkClickHandler, OnClickListener customTabsBackClickHandler) {
+            OnClickListener bookmarkClickHandler, OnClickListener customTabsBackClickHandler,
+            LayoutManager layoutManager, ActivityTabProvider tabProvider,
+            BrowserControlsStateProvider browserControlsStateProvider) {
         assert mTabModelSelectorSupplier.get() != null;
         if (mTabSwitcherModeCoordinatorPhone != null) {
             mTabSwitcherModeCoordinatorPhone.setOnTabSwitcherClickHandler(tabSwitcherClickHandler);
@@ -194,6 +214,16 @@
         mToolbarLayout.setLayoutUpdater(layoutUpdater);
 
         mToolbarLayout.onNativeLibraryReady();
+
+        // If fullscreen is disabled, don't bother creating this overlay; only the android view will
+        // ever be shown.
+        if (DeviceClassManager.enableFullscreen()) {
+            mOverlayCoordinator =
+                    new TopToolbarOverlayCoordinator(mToolbarLayout.getContext(), layoutManager,
+                            mProgressDrawInfoCallback, tabProvider, browserControlsStateProvider);
+            layoutManager.addSceneOverlay(mOverlayCoordinator);
+            mToolbarLayout.setOverlayCoordinator(mOverlayCoordinator);
+        }
     }
 
     private void setOverviewModeBehavior(OverviewModeBehavior overviewModeBehavior) {
@@ -226,6 +256,11 @@
      * Cleans up any code as necessary.
      */
     public void destroy() {
+        if (mOverlayCoordinator != null) {
+            mOverlayCoordinator.destroy();
+            mOverlayCoordinator = null;
+        }
+
         mToolbarLayout.destroy();
         if (mTabSwitcherModeCoordinatorPhone != null) {
             mTabSwitcherModeCoordinatorPhone.destroy();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tracing/settings/DeveloperSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/tracing/settings/DeveloperSettings.java
index e07a8f2f..1f9156c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tracing/settings/DeveloperSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tracing/settings/DeveloperSettings.java
@@ -10,9 +10,9 @@
 import androidx.preference.PreferenceFragmentCompat;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.browser_ui.settings.SettingsUtils;
 import org.chromium.components.version_info.Channel;
 import org.chromium.components.version_info.VersionConstants;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
index efdab39c..064de37 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
@@ -12,7 +12,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.task.PostTask;
-import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.components.webapk.lib.client.ChromeWebApkHostSignature;
 import org.chromium.components.webapk.lib.client.WebApkValidator;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
index bc1b24f..70183175 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
@@ -177,7 +177,7 @@
         tabContentManagerSupplier.set(tabContentManager);
         mManager = mManagerPhone;
         CompositorAnimationHandler.setTestingMode(true);
-        mManager.init(mTabModelSelector, null, null, null, null, mTabSupplier);
+        mManager.init(mTabModelSelector, null, null, null, null);
         initializeMotionEvent();
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
index fe026212..72542e8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityIncognitoTest.java
@@ -11,7 +11,6 @@
 import static org.chromium.chrome.browser.customtabs.CustomTabsTestUtils.addActionButtonToIntent;
 import static org.chromium.chrome.browser.customtabs.CustomTabsTestUtils.createTestBitmap;
 
-import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -43,6 +42,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils.OnFinishedForTest;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
@@ -197,7 +197,7 @@
     @MediumTest
     @Features.EnableFeatures({ChromeFeatureList.CCT_INCOGNITO})
     @TargetApi(Build.VERSION_CODES.M)
-    @SuppressLint("NewApi")
+    @MinAndroidSdkLevel(Build.VERSION_CODES.M)
     public void closeAllIncognitoNotificationIsNotDisplayed() throws Exception {
         // It may happen that some previous incognito notification from tabbed activity may be
         // already be lying around. So, we test the delta instead to be 0.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/OWNERS
index 8c01572..a73e0828 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/OWNERS
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/OWNERS
@@ -1 +1,2 @@
 file://chrome/android/java/src/org/chromium/chrome/browser/customtabs/OWNERS
+per-file *CustomTabActivityIncognitoTest*=roagarwal@chromium.org
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManagerTest.java
index f3ac086c..0f2880e6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceManagerTest.java
@@ -72,7 +72,7 @@
         }
 
         @Override
-        void stopAndUnbindServiceInternal(@DownloadForegroundService.StopForegroundNotification
+        void stopAndUnbindServiceInternal(@DownloadForegroundServiceImpl.StopForegroundNotification
                                           int stopForegroundNotification,
                 int pinnedNotificationId, Notification pinnedNotification) {
             mStopForegroundNotificationFlag = stopForegroundNotification;
@@ -102,7 +102,7 @@
      * Implementation of DownloadForegroundService for testing.
      * Does not implement startOrUpdateForegroundService to avoid test service lifecycle.
      */
-    public static class MockDownloadForegroundService extends DownloadForegroundService {
+    public static class MockDownloadForegroundService extends DownloadForegroundServiceImpl {
         @Override
         public void startOrUpdateForegroundService(int newNotificationId,
                 Notification newNotification, int oldNotificationId, Notification oldNotification,
@@ -231,7 +231,7 @@
         mDownloadServiceManager.updateDownloadStatus(mContext,
                 DownloadNotificationService.DownloadStatus.PAUSED, FAKE_DOWNLOAD_1, mNotification);
         assertFalse(mDownloadServiceManager.mIsServiceBound);
-        assertEquals(DownloadForegroundService.StopForegroundNotification.DETACH,
+        assertEquals(DownloadForegroundServiceImpl.StopForegroundNotification.DETACH,
                 mDownloadServiceManager.mStopForegroundNotificationFlag);
 
         // Service restarts and then is cancelled, so notification is killed.
@@ -245,7 +245,7 @@
                 DownloadNotificationService.DownloadStatus.CANCELLED, FAKE_DOWNLOAD_1,
                 mNotification);
         assertFalse(mDownloadServiceManager.mIsServiceBound);
-        assertEquals(DownloadForegroundService.StopForegroundNotification.KILL,
+        assertEquals(DownloadForegroundServiceImpl.StopForegroundNotification.KILL,
                 mDownloadServiceManager.mStopForegroundNotificationFlag);
 
         // Download starts and completes, notification is either detached or killed.
@@ -259,7 +259,7 @@
                 DownloadNotificationService.DownloadStatus.COMPLETED, FAKE_DOWNLOAD_2,
                 mNotification);
         assertFalse(mDownloadServiceManager.mIsServiceBound);
-        assertEquals(DownloadForegroundService.StopForegroundNotification.DETACH,
+        assertEquals(DownloadForegroundServiceImpl.StopForegroundNotification.DETACH,
                 mDownloadServiceManager.mStopForegroundNotificationFlag);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceTest.java
index f746c2c..6c31240 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadForegroundServiceTest.java
@@ -47,7 +47,7 @@
      * Implementation of DownloadForegroundService for testing.
      * Mimics behavior of DownloadForegroundService except for calls to the actual service.
      */
-    public static class MockDownloadForegroundService extends DownloadForegroundService {
+    public static class MockDownloadForegroundService extends DownloadForegroundServiceImpl {
         @IntDef({MethodID.START_FOREGROUND, MethodID.STOP_FOREGROUND_FLAGS,
                 MethodID.RELAUNCH_NOTIFICATION})
         @Retention(RetentionPolicy.SOURCE)
@@ -65,6 +65,10 @@
         // Used for saving MethodID values.
         List<Integer> mMethodCalls = new ArrayList<>();
 
+        public MockDownloadForegroundService() {
+            setService(new DownloadForegroundService());
+        }
+
         // Clears stored flags/boolean/id/method calls. Call between tests runs.
         void clearStoredState() {
             mStopForegroundFlags = -1;
@@ -214,7 +218,7 @@
         mForegroundService.clearStoredState();
 
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.DETACH,
+                DownloadForegroundServiceImpl.StopForegroundNotification.DETACH,
                 INVALID_NOTIFICATION_ID, null);
         assertEquals(expectedMethodCalls, mForegroundService.mMethodCalls);
         assertEquals(STOP_FOREGROUND_DETACH, mForegroundService.mStopForegroundFlags);
@@ -225,7 +229,7 @@
         mForegroundService.clearStoredState();
 
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.DETACH,
+                DownloadForegroundServiceImpl.StopForegroundNotification.DETACH,
                 INVALID_NOTIFICATION_ID, null);
         assertEquals(expectedMethodCalls, mForegroundService.mMethodCalls);
         assertEquals(STOP_FOREGROUND_DETACH, mForegroundService.mStopForegroundFlags);
@@ -236,8 +240,8 @@
         mForegroundService.clearStoredState();
 
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.KILL, INVALID_NOTIFICATION_ID,
-                null);
+                DownloadForegroundServiceImpl.StopForegroundNotification.KILL,
+                INVALID_NOTIFICATION_ID, null);
         assertEquals(expectedMethodCalls, mForegroundService.mMethodCalls);
         assertEquals(STOP_FOREGROUND_REMOVE, mForegroundService.mStopForegroundFlags);
     }
@@ -260,7 +264,7 @@
         mForegroundService.clearStoredState();
 
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
+                DownloadForegroundServiceImpl.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
                 mNotification);
         List<Integer> expectedMethodCalls =
                 Arrays.asList(MockDownloadForegroundService.MethodID.STOP_FOREGROUND_FLAGS,
@@ -276,7 +280,7 @@
         mForegroundService.clearStoredState();
 
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
+                DownloadForegroundServiceImpl.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
                 mNotification);
         expectedMethodCalls =
                 Arrays.asList(MockDownloadForegroundService.MethodID.STOP_FOREGROUND_FLAGS,
@@ -291,7 +295,7 @@
         mForegroundService.clearStoredState();
 
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.KILL, FAKE_DOWNLOAD_ID1,
+                DownloadForegroundServiceImpl.StopForegroundNotification.KILL, FAKE_DOWNLOAD_ID1,
                 mNotification);
         expectedMethodCalls =
                 Arrays.asList(MockDownloadForegroundService.MethodID.STOP_FOREGROUND_FLAGS);
@@ -316,7 +320,7 @@
         mForegroundService.clearStoredState();
 
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
+                DownloadForegroundServiceImpl.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
                 mNotification);
         List<Integer> expectedMethodCalls =
                 Arrays.asList(MockDownloadForegroundService.MethodID.RELAUNCH_NOTIFICATION,
@@ -331,7 +335,7 @@
 
         mForegroundService.mNextNotificationId = FAKE_DOWNLOAD_ID2;
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
+                DownloadForegroundServiceImpl.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
                 mNotification);
         expectedMethodCalls =
                 Arrays.asList(MockDownloadForegroundService.MethodID.RELAUNCH_NOTIFICATION,
@@ -347,7 +351,7 @@
         mForegroundService.clearStoredState();
 
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.KILL, FAKE_DOWNLOAD_ID1,
+                DownloadForegroundServiceImpl.StopForegroundNotification.KILL, FAKE_DOWNLOAD_ID1,
                 mNotification);
         expectedMethodCalls =
                 Arrays.asList(MockDownloadForegroundService.MethodID.STOP_FOREGROUND_FLAGS);
@@ -371,7 +375,7 @@
 
         mForegroundService.mNextNotificationId = FAKE_DOWNLOAD_ID2;
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
+                DownloadForegroundServiceImpl.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
                 mNotification);
         List<Integer> expectedMethodCalls =
                 Arrays.asList(MockDownloadForegroundService.MethodID.RELAUNCH_NOTIFICATION,
@@ -388,7 +392,7 @@
 
         mForegroundService.mNextNotificationId = FAKE_DOWNLOAD_ID2;
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
+                DownloadForegroundServiceImpl.StopForegroundNotification.DETACH, FAKE_DOWNLOAD_ID1,
                 mNotification);
         assertEquals(expectedMethodCalls, mForegroundService.mMethodCalls);
         assertEquals(ServiceCompat.STOP_FOREGROUND_REMOVE, mForegroundService.mStopForegroundFlags);
@@ -401,7 +405,7 @@
         mForegroundService.clearStoredState();
 
         mForegroundService.stopDownloadForegroundService(
-                DownloadForegroundService.StopForegroundNotification.KILL, FAKE_DOWNLOAD_ID1,
+                DownloadForegroundServiceImpl.StopForegroundNotification.KILL, FAKE_DOWNLOAD_ID1,
                 mNotification);
         expectedMethodCalls =
                 Arrays.asList(MockDownloadForegroundService.MethodID.STOP_FOREGROUND_FLAGS);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java
index 4bad010d..9872ae5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/firstrun/TosAndUmaFirstRunFragmentWithEnterpriseSupportTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.firstrun;
 
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 
 import android.app.Activity;
@@ -11,6 +13,8 @@
 import android.app.Instrumentation.ActivityMonitor;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
@@ -35,6 +39,7 @@
 import org.chromium.base.CommandLine;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -44,6 +49,7 @@
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.privacy.settings.PrivacyPreferencesManager;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.ChromeRenderTestRule;
 import org.chromium.components.policy.PolicyService;
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
@@ -82,6 +88,10 @@
     @Rule
     public DisableAnimationsTestRule mDisableAnimationsTestRule = new DisableAnimationsTestRule();
 
+    @Rule
+    public ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus().build();
+
     @Mock
     public FirstRunAppRestrictionInfo mMockAppRestrictionInfo;
     @Mock
@@ -174,7 +184,7 @@
         assertHistograms(true, SpeedComparedToInflation.SLOWER,
                 SpeedComparedToInflation.NOT_RECORDED, SpeedComparedToInflation.NOT_RECORDED);
 
-        // Try to accept Tos.
+        // Try to accept ToS.
         TestThreadUtils.runOnUiThreadBlocking((Runnable) mAcceptButton::performClick);
         Assert.assertTrue("Crash report should be enabled.",
                 PrivacyPreferencesManager.getInstance().isUsageAndCrashReportingPermittedByUser());
@@ -402,6 +412,26 @@
                 PrivacyPreferencesManager.getInstance().isUsageAndCrashReportingPermittedByUser());
     }
 
+    @Test
+    @SmallTest
+    @Feature({"RenderTest", "FirstRun"})
+    public void testRender() throws Exception {
+        launchFirstRunThroughCustomTab();
+        assertUIState(FragmentState.LOADING);
+
+        // Clear the focus on view to avoid unexpected highlight on background.
+        View tosAndUmaFragment =
+                mActivity.getSupportFragmentManager().getFragments().get(0).getView();
+        Assert.assertNotNull(tosAndUmaFragment);
+        TestThreadUtils.runOnUiThreadBlocking(tosAndUmaFragment::clearFocus);
+
+        renderWithPortraitAndLandscape(tosAndUmaFragment, "fre_tosanduma_loading");
+
+        setAppRestrictionsMockInitialized(false);
+        assertUIState(FragmentState.NO_POLICY);
+        renderWithPortraitAndLandscape(tosAndUmaFragment, "fre_tosanduma_nopolicy");
+    }
+
     /**
      * Launch chrome through custom tab and trigger first run.
      */
@@ -617,4 +647,35 @@
             }
         });
     }
+
+    private void renderWithPortraitAndLandscape(View tosAndUmaFragmentView, String testPrefix)
+            throws Exception {
+        mRenderTestRule.render(tosAndUmaFragmentView, testPrefix + "_portrait");
+
+        setDeviceOrientation(tosAndUmaFragmentView, Configuration.ORIENTATION_LANDSCAPE);
+        mRenderTestRule.render(tosAndUmaFragmentView, testPrefix + "_landscape");
+
+        setDeviceOrientation(tosAndUmaFragmentView, Configuration.ORIENTATION_PORTRAIT);
+        mRenderTestRule.render(tosAndUmaFragmentView, testPrefix + "_portrait");
+    }
+
+    private void setDeviceOrientation(View tosAndUmaFragmentView, int orientation) {
+        // TODO(https://crbug.com/1133789): This function is copied mostly copied from
+        // TabUiTestHelper#rotateDeviceToOrientation. Merge / move these two test functions if
+        // applicable.
+        if (mActivity.getResources().getConfiguration().orientation == orientation) return;
+        assertTrue(orientation == Configuration.ORIENTATION_LANDSCAPE
+                || orientation == Configuration.ORIENTATION_PORTRAIT);
+
+        boolean isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE;
+        mActivity.setRequestedOrientation(isLandscape ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+                                                      : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(
+                    mActivity.getResources().getConfiguration().orientation, is(orientation));
+            Criteria.checkThat(tosAndUmaFragmentView.getWidth() > tosAndUmaFragmentView.getHeight(),
+                    is(isLandscape));
+        });
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoNotificationServiceTest.java
index a80557d..ffec71e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoNotificationServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/IncognitoNotificationServiceTest.java
@@ -6,7 +6,6 @@
 
 import static org.junit.Assert.assertEquals;
 
-import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -29,6 +28,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.TabLaunchType;
@@ -190,7 +190,7 @@
     @MediumTest
     @Feature("Incognito")
     @TargetApi(Build.VERSION_CODES.M)
-    @SuppressLint("NewApi")
+    @MinAndroidSdkLevel(Build.VERSION_CODES.M)
     public void testCloseAllIncognitoNotificationIsDisplayed() {
         mActivityTestRule.startMainActivityOnBlankPage();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/OWNERS
new file mode 100644
index 0000000..409cdd8
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/OWNERS
@@ -0,0 +1,5 @@
+per-file *Leakage*=roagarwal@chromium.org
+per-file *IncognitoDataTestUtils*=roagarwal@chromium.org
+
+# TEAM: chrome-privacy-core@google.com
+# COMPONENT: Privacy>Incognito
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeIntentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeIntentTest.java
index 4025ce2a9..fe9c25f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeIntentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeIntentTest.java
@@ -148,7 +148,7 @@
                                   .getApplicationContext();
 
         Intent intent = new Intent(NotificationConstants.ACTION_CLICK_NOTIFICATION);
-        intent.setClass(context, NotificationService.Receiver.class);
+        intent.setClass(context, NotificationServiceImpl.Receiver.class);
 
         intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_ID, "42");
         intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_PROFILE_ID, "Default");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java
index 0aa38ed..fafad4c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omaha/RequestGeneratorTest.java
@@ -21,10 +21,10 @@
 
 import org.chromium.base.test.util.AdvancedMockContext;
 import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.identity.SettingsSecureBasedIdentificationGenerator;
-import org.chromium.chrome.browser.identity.UniqueIdentificationGenerator;
-import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
 import org.chromium.chrome.browser.signin.IdentityServicesProvider;
+import org.chromium.chrome.browser.uid.SettingsSecureBasedIdentificationGenerator;
+import org.chromium.chrome.browser.uid.UniqueIdentificationGenerator;
+import org.chromium.chrome.browser.uid.UniqueIdentificationGeneratorFactory;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.omaha.AttributeFinder;
 import org.chromium.chrome.test.omaha.MockRequestGenerator;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
index 4fb6cbd..2643058 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
@@ -15,8 +15,6 @@
 
 import static org.hamcrest.CoreMatchers.allOf;
 import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
@@ -25,7 +23,6 @@
 
 import android.os.Build;
 import android.view.View;
-import android.widget.Button;
 
 import androidx.test.filters.MediumTest;
 
@@ -404,7 +401,7 @@
         onView(withId(R.id.page_info_permissions_row)).perform(click());
         // Clear permissions in page info.
         onView(withText("Reset permissions")).perform(click());
-        onView(allOf(is(instanceOf(Button.class)), withText("Reset permissions"))).perform(click());
+        onView(withText("Reset")).perform(click());
         // Wait until the UI navigates back and check permissions are reset.
         onViewWaiting(allOf(withId(R.id.page_info_row_wrapper), isDisplayed()));
         // Make sure that the permission section is gone because there are no longer exceptions.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
index 3048bee..6e69add 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
@@ -23,11 +23,11 @@
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
-import org.chromium.chrome.browser.identity.UniqueIdentificationGenerator;
-import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory;
-import org.chromium.chrome.browser.identity.UuidBasedUniqueIdentificationGenerator;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.UnifiedConsentServiceBridge;
+import org.chromium.chrome.browser.uid.UniqueIdentificationGenerator;
+import org.chromium.chrome.browser.uid.UniqueIdentificationGeneratorFactory;
+import org.chromium.chrome.browser.uid.UuidBasedUniqueIdentificationGenerator;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
 import org.chromium.chrome.test.util.browser.signin.SigninTestUtil;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java b/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java
index 18a35b61..a5f1fe9b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java
@@ -25,7 +25,7 @@
 import org.junit.runner.Description;
 
 import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 
 import java.io.File;
 import java.io.FileWriter;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java
index f131f68..87b48d3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java
@@ -17,6 +17,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.Feature;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
@@ -72,11 +73,9 @@
     @Test
     @MediumTest
     @Feature({"Browser", "Main"})
-    // TODO(crbug.com/1134812): Remove the reliance on a network connection for these tests.
-    @Restriction({ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES,
-            Restriction.RESTRICTION_TYPE_INTERNET})
-    public void
-    testTranslateCompactInfoBarAppears() throws TimeoutException {
+    @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES)
+    @DisabledTest(message = "https://crbug.com/1130712")
+    public void testTranslateCompactInfoBarAppears() throws TimeoutException {
         mActivityTestRule.loadUrl(mTestServer.getURL(TRANSLATE_PAGE));
         mListener.addInfoBarAnimationFinished("InfoBar not opened.");
         InfoBar infoBar = mInfoBarContainer.getInfoBarsForTesting().get(0);
@@ -90,10 +89,9 @@
     @Test
     @MediumTest
     @Feature({"Browser", "Main"})
-    @Restriction({ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES,
-            Restriction.RESTRICTION_TYPE_INTERNET})
-    public void
-    testTranslateCompactInfoBarOverflowMenus() throws TimeoutException {
+    @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES)
+    @DisabledTest(message = "https://crbug.com/1130712")
+    public void testTranslateCompactInfoBarOverflowMenus() throws TimeoutException {
         mActivityTestRule.loadUrl(mTestServer.getURL(TRANSLATE_PAGE));
         mListener.addInfoBarAnimationFinished("InfoBar not opened.");
         TranslateCompactInfoBar infoBar =
@@ -114,10 +112,9 @@
     @Test
     @MediumTest
     @Feature({"Browser", "Main"})
-    @Restriction({ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES,
-            Restriction.RESTRICTION_TYPE_INTERNET})
-    public void
-    testTabMenuDismissedOnOrientationChange() throws Exception {
+    @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES)
+    @DisabledTest(message = "https://crbug.com/1130712")
+    public void testTabMenuDismissedOnOrientationChange() throws Exception {
         mActivityTestRule.loadUrl(mTestServer.getURL(TRANSLATE_PAGE));
         mListener.addInfoBarAnimationFinished("InfoBar not opened.");
         TranslateCompactInfoBar infoBar =
@@ -145,10 +142,9 @@
     @Test
     @MediumTest
     @Feature({"Browser", "Main"})
-    @Restriction({ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES,
-            Restriction.RESTRICTION_TYPE_INTERNET})
-    public void
-    testTranslateCompactInfoBarReopenOnTarget() throws TimeoutException {
+    @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES)
+    @DisabledTest(message = "https://crbug.com/1130712")
+    public void testTranslateCompactInfoBarReopenOnTarget() throws TimeoutException {
         mActivityTestRule.loadUrl(mTestServer.getURL(TRANSLATE_PAGE));
         mListener.addInfoBarAnimationFinished("InfoBar not opened.");
 
@@ -181,10 +177,9 @@
     @Test
     @MediumTest
     @Feature({"Browser", "Main"})
-    @Restriction({ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES,
-            Restriction.RESTRICTION_TYPE_INTERNET})
-    public void
-    testStartTranslateOnManualInitiation() throws TimeoutException {
+    @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES)
+    @DisabledTest(message = "https://crbug.com/1130712")
+    public void testStartTranslateOnManualInitiation() throws TimeoutException {
         // Load a page that won't trigger the translate recommendation.
         mActivityTestRule.loadUrl(mTestServer.getURL(NON_TRANSLATE_PAGE));
 
@@ -209,10 +204,9 @@
     @Test
     @MediumTest
     @Feature({"Browser", "Main"})
-    @Restriction({ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES,
-            Restriction.RESTRICTION_TYPE_INTERNET})
-    public void
-    testManualInitiationWithBarOpen() throws TimeoutException {
+    @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES)
+    @DisabledTest(message = "https://crbug.com/1130712")
+    public void testManualInitiationWithBarOpen() throws TimeoutException {
         mActivityTestRule.loadUrl(mTestServer.getURL(TRANSLATE_PAGE));
         mListener.addInfoBarAnimationFinished("InfoBar not opened.");
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateIntentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateIntentTest.java
index 79278f0..2dd274c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateIntentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateIntentTest.java
@@ -8,6 +8,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.os.Build.VERSION_CODES;
 
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
@@ -24,7 +25,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Restriction;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -135,10 +136,12 @@
 
     @Test
     @MediumTest
-    // TODO(crbug.com/1134812): Remove the reliance on a network connection for these tests.
-    @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
+    @DisableIf.
+    Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N,
+            message = "Consistently failing on Marshmallow https://crbug.com/1127786")
     @Features.DisableFeatures({ChromeFeatureList.TRANSLATE_INTENT})
-    public void testTranslateIntentDisabled() throws TimeoutException {
+    public void
+    testTranslateIntentDisabled() throws TimeoutException {
         final String url = sActivityTestRule.getTestServer().getURL(TRANSLATE_PAGE);
         // Load a page that triggers the translate recommendation.
         sActivityTestRule.loadUrl(url);
@@ -153,9 +156,12 @@
 
     @Test
     @MediumTest
-    @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
+    @DisableIf.
+    Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N,
+            message = "Consistently failing on Marshmallow https://crbug.com/1127786")
     @Features.EnableFeatures({ChromeFeatureList.TRANSLATE_INTENT})
-    public void testTranslateIntentOnTranslatePage() throws TimeoutException {
+    public void
+    testTranslateIntentOnTranslatePage() throws TimeoutException {
         final String url = sActivityTestRule.getTestServer().getURL(TRANSLATE_PAGE);
         // Load a page that triggers the translate recommendation.
         sActivityTestRule.loadUrl(url);
@@ -170,9 +176,12 @@
 
     @Test
     @MediumTest
-    @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
+    @DisableIf.
+    Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N,
+            message = "Consistently failing on Marshmallow https://crbug.com/1127786")
     @Features.EnableFeatures({ChromeFeatureList.TRANSLATE_INTENT})
-    public void testTranslateIntentOnNonTranslatePage() throws TimeoutException {
+    public void
+    testTranslateIntentOnNonTranslatePage() throws TimeoutException {
         final String url = sActivityTestRule.getTestServer().getURL(NON_TRANSLATE_PAGE);
         // Load a page that doesn't trigger the translate recommendation.
         sActivityTestRule.loadUrl(url);
@@ -189,10 +198,12 @@
 
     @Test
     @MediumTest
-    @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
+    @DisableIf.
+    Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N,
+            message = "Consistently failing on Marshmallow https://crbug.com/1127786")
     @Features.EnableFeatures({ChromeFeatureList.TRANSLATE_INTENT})
-    public void testTranslateIntentWithTargetLanguage()
-            throws TimeoutException, ExecutionException {
+    public void
+    testTranslateIntentWithTargetLanguage() throws TimeoutException, ExecutionException {
         final String url = sActivityTestRule.getTestServer().getURL(NON_TRANSLATE_PAGE);
         // Load a page that doesn't trigger the translate recommendation.
         sActivityTestRule.loadUrl(url);
@@ -218,9 +229,12 @@
 
     @Test
     @MediumTest
-    @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
+    @DisableIf.
+    Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N,
+            message = "Consistently failing on Marshmallow https://crbug.com/1127786")
     @Features.EnableFeatures({ChromeFeatureList.TRANSLATE_INTENT})
-    public void testTranslateIntentWithUnsupportedTargetLanguage() throws TimeoutException {
+    public void
+    testTranslateIntentWithUnsupportedTargetLanguage() throws TimeoutException {
         final String url = sActivityTestRule.getTestServer().getURL(NON_TRANSLATE_PAGE);
         // Load a page that doesn't trigger the translate recommendation.
         sActivityTestRule.loadUrl(url);
@@ -235,9 +249,12 @@
 
     @Test
     @MediumTest
-    @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
+    @DisableIf.
+    Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N,
+            message = "Consistently failing on Marshmallow https://crbug.com/1127786")
     @Features.EnableFeatures({ChromeFeatureList.TRANSLATE_INTENT})
-    public void testTranslateIntentOnIncognito() throws TimeoutException {
+    public void
+    testTranslateIntentOnIncognito() throws TimeoutException {
         final String url = sActivityTestRule.getTestServer().getURL(TRANSLATE_PAGE);
         // Load a page that triggers the translate recommendation.
         sActivityTestRule.loadUrlInNewTab(url, /*incognito=*/true);
@@ -256,9 +273,12 @@
 
     @Test
     @MediumTest
-    @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
+    @DisableIf.
+    Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N,
+            message = "Consistently failing on Marshmallow https://crbug.com/1127786")
     @Features.EnableFeatures({ChromeFeatureList.TRANSLATE_INTENT})
-    public void testTranslateIntentWithUrlMismatch() throws TimeoutException {
+    public void
+    testTranslateIntentWithUrlMismatch() throws TimeoutException {
         final String url = sActivityTestRule.getTestServer().getURL(TRANSLATE_PAGE);
         // Load a page that triggers the translate recommendation.
         sActivityTestRule.loadUrl(url);
@@ -273,9 +293,12 @@
 
     @Test
     @MediumTest
-    @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
+    @DisableIf.
+    Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N,
+            message = "Consistently failing on Marshmallow https://crbug.com/1127786")
     @Features.EnableFeatures({ChromeFeatureList.TRANSLATE_INTENT})
-    public void testTranslateIntentWithoutExpectedUrl() throws TimeoutException {
+    public void
+    testTranslateIntentWithoutExpectedUrl() throws TimeoutException {
         final String url = sActivityTestRule.getTestServer().getURL(TRANSLATE_PAGE);
         // Load a page that triggers the translate recommendation.
         sActivityTestRule.loadUrl(url);
@@ -290,9 +313,12 @@
 
     @Test
     @MediumTest
-    @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
+    @DisableIf.
+    Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N,
+            message = "Consistently failing on Marshmallow https://crbug.com/1127786")
     @Features.EnableFeatures({ChromeFeatureList.TRANSLATE_INTENT})
-    public void testTranslateIntentVerifyComponent() throws TimeoutException {
+    public void
+    testTranslateIntentVerifyComponent() throws TimeoutException {
         final String url = sActivityTestRule.getTestServer().getURL(TRANSLATE_PAGE);
         // Load a page that triggers the translate recommendation.
         sActivityTestRule.loadUrl(url);
@@ -313,9 +339,12 @@
 
     @Test
     @MediumTest
-    @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
+    @DisableIf.
+    Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N,
+            message = "Consistently failing on Marshmallow https://crbug.com/1127786")
     @Features.EnableFeatures({ChromeFeatureList.TRANSLATE_INTENT})
-    public void testTranslateIntentIncorrectComponent() throws TimeoutException {
+    public void
+    testTranslateIntentIncorrectComponent() throws TimeoutException {
         final String url = sActivityTestRule.getTestServer().getURL(TRANSLATE_PAGE);
         // Load a page that triggers the translate recommendation.
         sActivityTestRule.loadUrl(url);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayMediatorTest.java
index d23102b..d875eec 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayMediatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/toolbar/TopToolbarOverlayMediatorTest.java
@@ -20,7 +20,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
@@ -63,15 +62,10 @@
     @Captor
     private ArgumentCaptor<ActivityTabProvider.ActivityTabObserver> mActivityTabObserverCaptor;
 
-    private ObservableSupplierImpl<Boolean> mAndroidViewShownSupplier;
-
     @Before
     public void beforeTest() {
         MockitoAnnotations.initMocks(this);
 
-        mAndroidViewShownSupplier = new ObservableSupplierImpl<>();
-        mAndroidViewShownSupplier.set(true);
-
         TopToolbarOverlayMediator.setToolbarBackgroundColorForTesting(Color.RED);
         TopToolbarOverlayMediator.setUrlBarColorForTesting(Color.BLUE);
         TopToolbarOverlayMediator.setIsTabletForTesting(false);
@@ -88,7 +82,8 @@
                          .build();
 
         mMediator = new TopToolbarOverlayMediator(mModel, mContext, mLayoutManager,
-                (info) -> {}, mTabSupplier, mBrowserControlsProvider, mAndroidViewShownSupplier);
+                (info) -> {}, mTabSupplier, mBrowserControlsProvider);
+        mMediator.setIsAndroidViewVisible(true);
 
         // Ensure the observer is added to the initial tab.
         verify(mTabSupplier).addObserverAndTrigger(mActivityTabObserverCaptor.capture());
@@ -137,12 +132,12 @@
 
     @Test
     public void testShadowVisibility_androidViewForceHidden() {
-        mAndroidViewShownSupplier.set(true);
+        mMediator.setIsAndroidViewVisible(true);
 
         Assert.assertFalse(
                 "Shadow should be invisible.", mModel.get(TopToolbarOverlayProperties.SHOW_SHADOW));
 
-        mAndroidViewShownSupplier.set(false);
+        mMediator.setIsAndroidViewVisible(false);
 
         Assert.assertTrue(
                 "Shadow should be visible.", mModel.get(TopToolbarOverlayProperties.SHOW_SHADOW));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/content_capture/ContentCaptureHistoryDeletionObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/content_capture/ContentCaptureHistoryDeletionObserverTest.java
new file mode 100644
index 0000000..4f0a031
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/content_capture/ContentCaptureHistoryDeletionObserverTest.java
@@ -0,0 +1,92 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.content_capture;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.history.HistoryDeletionInfo;
+import org.chromium.components.content_capture.ContentCaptureController;
+
+/**
+ * Unit tests for the ContentCaptureHistoryDeletionObserver.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class ContentCaptureHistoryDeletionObserverTest {
+    @Mock
+    ContentCaptureController mContentCaptureController;
+    @Mock
+    HistoryDeletionInfo mHistoryDeletionInfo;
+
+    ContentCaptureHistoryDeletionObserver mContentCaptureHistoryDeletionObserver;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContentCaptureHistoryDeletionObserver =
+                new ContentCaptureHistoryDeletionObserver(() -> mContentCaptureController);
+    }
+
+    @Test
+    public void clearAllData_FromSpecificTimeRange() {
+        doReturn(false).when(mHistoryDeletionInfo).isTimeRangeForAllTime();
+        doReturn(true).when(mHistoryDeletionInfo).isTimeRangeValid();
+
+        mContentCaptureHistoryDeletionObserver.onURLsDeleted(mHistoryDeletionInfo);
+        verify(mContentCaptureController).clearAllContentCaptureData();
+    }
+
+    @Test
+    public void clearAllData_ForAllTime() {
+        doReturn(true).when(mHistoryDeletionInfo).isTimeRangeForAllTime();
+        doReturn(false).when(mHistoryDeletionInfo).isTimeRangeValid();
+
+        mContentCaptureHistoryDeletionObserver.onURLsDeleted(mHistoryDeletionInfo);
+        verify(mContentCaptureController).clearAllContentCaptureData();
+    }
+
+    @Test
+    public void clearAllData_ForSpecficURLs() {
+        doReturn(false).when(mHistoryDeletionInfo).isTimeRangeForAllTime();
+        doReturn(false).when(mHistoryDeletionInfo).isTimeRangeValid();
+        String[] urls = new String[] {"one", "two", "three"};
+        doReturn(urls).when(mHistoryDeletionInfo).getDeletedURLs();
+
+        mContentCaptureHistoryDeletionObserver.onURLsDeleted(mHistoryDeletionInfo);
+        verify(mContentCaptureController).clearContentCaptureDataForURLs(urls);
+    }
+
+    @Test
+    public void clearAllData_ThrowsRuntimeException() {
+        doThrow(RuntimeException.class)
+                .when(mContentCaptureController)
+                .clearContentCaptureDataForURLs(any());
+        doReturn(false).when(mHistoryDeletionInfo).isTimeRangeForAllTime();
+        doReturn(false).when(mHistoryDeletionInfo).isTimeRangeValid();
+        String[] urls = new String[] {"one", "two", "three"};
+        doReturn(urls).when(mHistoryDeletionInfo).getDeletedURLs();
+
+        try {
+            mContentCaptureHistoryDeletionObserver.onURLsDeleted(mHistoryDeletionInfo);
+            fail("Expected exception to be thrown.");
+        } catch (RuntimeException e) {
+            assertTrue(e.toString().contains("Deleted URLs length: " + urls.length));
+        }
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java
index f924e74c..ad7343e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotificationTest.java
@@ -33,11 +33,11 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.test.ShadowRecordHistogram;
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.search_engines.TemplateUrl;
 import org.chromium.components.search_engines.TemplateUrlService;
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 31dcb84..69f0b7d 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -5133,11 +5133,6 @@
      flag_descriptions::kEnableImplicitRootScrollerDescription, kOsAll,
      FEATURE_VALUE_TYPE(blink::features::kImplicitRootScroller)},
 
-    {"enable-cssom-view-scroll-coordinates",
-     flag_descriptions::kEnableCSSOMViewScrollCoordinatesName,
-     flag_descriptions::kEnableCSSOMViewScrollCoordinatesDescription, kOsAll,
-     FEATURE_VALUE_TYPE(blink::features::kCSSOMViewScrollCoordinates)},
-
     {"enable-text-fragment-anchor",
      flag_descriptions::kEnableTextFragmentAnchorName,
      flag_descriptions::kEnableTextFragmentAnchorDescription, kOsAll,
diff --git a/chrome/browser/android/history/history_deletion_info.cc b/chrome/browser/android/history/history_deletion_info.cc
index ff78d78..244b8c7 100644
--- a/chrome/browser/android/history/history_deletion_info.cc
+++ b/chrome/browser/android/history/history_deletion_info.cc
@@ -47,21 +47,6 @@
   return deletion_info->time_range().IsAllTime();
 }
 
-jlong JNI_HistoryDeletionInfo_GetTimeRangeBegin(
-    JNIEnv* env,
-    jlong history_deletion_info_ptr) {
-  history::DeletionInfo* deletion_info =
-      ToDeletionInfo(history_deletion_info_ptr);
-  return deletion_info->time_range().begin().ToJavaTime();
-}
-
-jlong JNI_HistoryDeletionInfo_GetTimeRangeEnd(JNIEnv* env,
-                                              jlong history_deletion_info_ptr) {
-  history::DeletionInfo* deletion_info =
-      ToDeletionInfo(history_deletion_info_ptr);
-  return deletion_info->time_range().end().ToJavaTime();
-}
-
 ScopedJavaLocalRef<jobject> CreateHistoryDeletionInfo(
     JNIEnv* env,
     const history::DeletionInfo* deletion_info) {
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc
index c5bd51f..45e80d78 100644
--- a/chrome/browser/chrome_browser_main_win.cc
+++ b/chrome/browser/chrome_browser_main_win.cc
@@ -52,6 +52,7 @@
 #include "chrome/browser/safe_browsing/chrome_cleaner/settings_resetter_win.h"
 #include "chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h"
 #include "chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_util_win.h"
+#include "chrome/browser/shell_integration_win.h"
 #include "chrome/browser/ui/simple_message_box.h"
 #include "chrome/browser/ui/uninstall_browser_prompt.h"
 #include "chrome/browser/web_applications/chrome_pwa_launcher/last_browser_file_util.h"
@@ -75,6 +76,7 @@
 #include "chrome/common/conflicts/module_watcher_win.h"
 #include "chrome/common/crash_keys.h"
 #include "chrome/common/env_vars.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/install_static/install_details.h"
@@ -87,7 +89,9 @@
 #include "components/crash/core/app/dump_hung_process_with_ptype.h"
 #include "components/crash/core/common/crash_key.h"
 #include "components/os_crypt/os_crypt.h"
+#include "components/prefs/pref_service.h"
 #include "components/version_info/channel.h"
+#include "components/version_info/version_info.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
@@ -488,6 +492,28 @@
                      std::move(pwa_launcher_paths)));
 }
 
+void MigratePinnedTaskBarShortcutsIfNeeded() {
+  // Update this number when users should go through a taskbar shortcut
+  // migration again. The last reason to do this was crrev.com/798174. @
+  // 86.0.4231.0.
+  //
+  // Note: If shortcut updates need to be done once after a future OS upgrade,
+  // that should be done by re-versioning Active Setup (see //chrome/installer
+  // and https://crbug.com/577697 for details).
+  const base::Version kLastVersionNeedingMigration({86, 0, 4231, 0});
+
+  PrefService* local_state = g_browser_process->local_state();
+  if (local_state) {
+    const base::Version last_version_migrated(
+        local_state->GetString(prefs::kShortcutMigrationVersion));
+    if (!last_version_migrated.IsValid() ||
+        last_version_migrated < kLastVersionNeedingMigration) {
+      shell_integration::win::MigrateTaskbarPins(base::BindOnce(
+          &PrefService::SetString, base::Unretained(local_state),
+          prefs::kShortcutMigrationVersion, version_info::GetVersionNumber()));
+    }
+  }
+}
 // This error message is not localized because we failed to load the
 // localization data files.
 const char kMissingLocaleDataTitle[] = "Missing File Error";
@@ -707,6 +733,12 @@
       FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
       base::BindOnce(&web_app::RecordPwaLauncherResult));
 
+  // Possibly migrate pinned taskbar shortcuts.
+  content::GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT,
+                                  base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})
+      ->PostTask(FROM_HERE,
+                 base::BindOnce(&MigratePinnedTaskBarShortcutsIfNeeded));
+
   base::ImportantFileWriterCleaner::GetInstance().Start();
 }
 
diff --git a/chrome/browser/chrome_browser_main_win_browsertest.cc b/chrome/browser/chrome_browser_main_win_browsertest.cc
new file mode 100644
index 0000000..c2b193e
--- /dev/null
+++ b/chrome/browser/chrome_browser_main_win_browsertest.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 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/chrome_browser_main_win.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/prefs/pref_service.h"
+#include "components/version_info/version_info.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/test_utils.h"
+
+using ChromeBrowserMainWinTest = InProcessBrowserTest;
+
+IN_PROC_BROWSER_TEST_F(ChromeBrowserMainWinTest, PRE_ShortcutsAreMigratedOnce) {
+  // Wait for all startup tasks to run.
+  content::RunAllTasksUntilIdle();
+
+  // Confirm that shortcuts were migrated.
+  const std::string last_version_migrated =
+      g_browser_process->local_state()->GetString(
+          prefs::kShortcutMigrationVersion);
+  EXPECT_EQ(last_version_migrated, version_info::GetVersionNumber());
+
+  // Set the version back as far as kLastVersionNeedingMigration and ensure it's
+  // not migrated again.
+  g_browser_process->local_state()->SetString(prefs::kShortcutMigrationVersion,
+                                              "86.0.4231.0");
+}
+
+IN_PROC_BROWSER_TEST_F(ChromeBrowserMainWinTest, ShortcutsAreMigratedOnce) {
+  content::RunAllTasksUntilIdle();
+
+  // Confirm that shortcuts weren't migrated when marked as having last been
+  // migrated in kLastVersionNeedingMigration+.
+  const std::string last_version_migrated =
+      g_browser_process->local_state()->GetString(
+          prefs::kShortcutMigrationVersion);
+  EXPECT_EQ(last_version_migrated, "86.0.4231.0");
+}
diff --git a/chrome/browser/chromeos/extensions/document_scan/document_scan_api.cc b/chrome/browser/chromeos/extensions/document_scan/document_scan_api.cc
index 0927d22..c7e5ff3 100644
--- a/chrome/browser/chromeos/extensions/document_scan/document_scan_api.cc
+++ b/chrome/browser/chromeos/extensions/document_scan/document_scan_api.cc
@@ -85,7 +85,8 @@
           base::BindOnce(&DocumentScanScanFunction::OnScanCompleted, this));
 }
 
-void DocumentScanScanFunction::OnPageReceived(std::string scanned_image) {
+void DocumentScanScanFunction::OnPageReceived(std::string scanned_image,
+                                              uint32_t /*page_number*/) {
   // Take only the first page of the scan.
   if (!scan_data_.has_value()) {
     scan_data_ = std::move(scanned_image);
diff --git a/chrome/browser/chromeos/extensions/document_scan/document_scan_api.h b/chrome/browser/chromeos/extensions/document_scan/document_scan_api.h
index f423596..c6e1b11b 100644
--- a/chrome/browser/chromeos/extensions/document_scan/document_scan_api.h
+++ b/chrome/browser/chromeos/extensions/document_scan/document_scan_api.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_DOCUMENT_SCAN_DOCUMENT_SCAN_API_H_
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_DOCUMENT_SCAN_DOCUMENT_SCAN_API_H_
 
+#include <cstdint>
 #include <memory>
 #include <string>
 #include <vector>
@@ -34,7 +35,7 @@
   friend class DocumentScanScanFunctionTest;
 
   void OnNamesReceived(std::vector<std::string> scanner_names);
-  void OnPageReceived(std::string scanned_image);
+  void OnPageReceived(std::string scanned_image, uint32_t /*page_number*/);
   void OnScanCompleted(bool success);
 
   base::Optional<std::string> scan_data_;
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index c5be3aa..f830ce7 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -2136,7 +2136,7 @@
 void UserSessionManager::DoBrowserLaunchInternal(Profile* profile,
                                                  LoginDisplayHost* login_host,
                                                  bool locale_pref_checked) {
-  if (browser_shutdown::IsTryingToQuit())
+  if (browser_shutdown::IsTryingToQuit() || chrome::IsAttemptingShutdown())
     return;
 
   if (!locale_pref_checked) {
@@ -2210,7 +2210,7 @@
 void UserSessionManager::RespectLocalePreferenceWrapper(
     Profile* profile,
     const base::Closure& callback) {
-  if (browser_shutdown::IsTryingToQuit())
+  if (browser_shutdown::IsTryingToQuit() || chrome::IsAttemptingShutdown())
     return;
 
   const user_manager::User* const user =
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index fd4ac7e..d0d56fd 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -1445,11 +1445,10 @@
 
   // Launch browser and delete login host controller.
   content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE,
-      base::BindOnce(&UserSessionManager::DoBrowserLaunch,
-                     base::Unretained(UserSessionManager::GetInstance()),
-                     ProfileManager::GetActiveUserProfile(),
-                     GetLoginDisplayHost()));
+      FROM_HERE, base::BindOnce(&UserSessionManager::DoBrowserLaunch,
+                                UserSessionManager::GetInstance()->AsWeakPtr(),
+                                ProfileManager::GetActiveUserProfile(),
+                                GetLoginDisplayHost()));
 }
 
 void WizardController::OnDeviceDisabledChecked(bool device_disabled) {
diff --git a/chrome/browser/chromeos/scanning/fake_lorgnette_scanner_manager.cc b/chrome/browser/chromeos/scanning/fake_lorgnette_scanner_manager.cc
index 2939cf3..39018988 100644
--- a/chrome/browser/chromeos/scanning/fake_lorgnette_scanner_manager.cc
+++ b/chrome/browser/chromeos/scanning/fake_lorgnette_scanner_manager.cc
@@ -36,7 +36,8 @@
                                        ScanCallback callback) {
   if (scan_data_.has_value()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(page_callback, scan_data_.value()));
+        FROM_HERE,
+        base::BindOnce(page_callback, scan_data_.value(), /*page_number=*/0));
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/chrome/browser/chromeos/scanning/lorgnette_scanner_manager.h b/chrome/browser/chromeos/scanning/lorgnette_scanner_manager.h
index c152484c..6d0dd94c 100644
--- a/chrome/browser/chromeos/scanning/lorgnette_scanner_manager.h
+++ b/chrome/browser/chromeos/scanning/lorgnette_scanner_manager.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_SCANNING_LORGNETTE_SCANNER_MANAGER_H_
 #define CHROME_BROWSER_CHROMEOS_SCANNING_LORGNETTE_SCANNER_MANAGER_H_
 
+#include <cstdint>
 #include <memory>
 #include <string>
 #include <vector>
@@ -27,7 +28,8 @@
       base::OnceCallback<void(std::vector<std::string> scanner_names)>;
   using GetScannerCapabilitiesCallback = base::OnceCallback<void(
       const base::Optional<lorgnette::ScannerCapabilities>& capabilities)>;
-  using PageCallback = base::RepeatingCallback<void(std::string scan_data)>;
+  using PageCallback = base::RepeatingCallback<void(std::string scan_data,
+                                                    uint32_t page_number)>;
   using ScanCallback = base::OnceCallback<void(bool success)>;
 
   ~LorgnetteScannerManager() override = default;
diff --git a/chrome/browser/chromeos/scanning/lorgnette_scanner_manager_unittest.cc b/chrome/browser/chromeos/scanning/lorgnette_scanner_manager_unittest.cc
index c975077..e6e1d8e 100644
--- a/chrome/browser/chromeos/scanning/lorgnette_scanner_manager_unittest.cc
+++ b/chrome/browser/chromeos/scanning/lorgnette_scanner_manager_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/scanning/lorgnette_scanner_manager.h"
 
+#include <cstdint>
 #include <memory>
 #include <string>
 #include <utility>
@@ -209,7 +210,9 @@
   }
 
   // Handles receiving a page from LorgnetteScannerManager::Scan().
-  void PageCallback(std::string page_data) { scan_data_.push_back(page_data); }
+  void PageCallback(std::string page_data, uint32_t /*page_number*/) {
+    scan_data_.push_back(page_data);
+  }
 
   // Handles completion of LorgnetteScannerManager::Scan().
   void ScanCallback(bool success) {
diff --git a/chrome/browser/chromeos/scanning/scan_service.cc b/chrome/browser/chromeos/scanning/scan_service.cc
index 3b2b641..d1d01bb 100644
--- a/chrome/browser/chromeos/scanning/scan_service.cc
+++ b/chrome/browser/chromeos/scanning/scan_service.cc
@@ -59,6 +59,7 @@
   if (scanner_name.empty())
     std::move(callback).Run(false);
 
+  base::Time::Now().UTCExplode(&start_time_);
   save_failed_ = false;
 
   // TODO(jschettler): Create a TypeConverter to convert from
@@ -118,13 +119,13 @@
       mojo::ConvertTo<mojo_ipc::ScannerCapabilitiesPtr>(capabilities.value()));
 }
 
-void ScanService::OnPageReceived(std::string scanned_image) {
-  // TODO(jschettler): Add page number to filename.
-  base::Time::Exploded time;
-  base::Time::Now().UTCExplode(&time);
+void ScanService::OnPageReceived(std::string scanned_image,
+                                 uint32_t page_number) {
+  // The |page_number| is 0-indexed.
   const std::string filename = base::StringPrintf(
-      "scan_%02d%02d%02d-%02d%02d%02d.png", time.year, time.month,
-      time.day_of_month, time.hour, time.minute, time.second);
+      "scan_%02d%02d%02d-%02d%02d%02d_page_%d.png", start_time_.year,
+      start_time_.month, start_time_.day_of_month, start_time_.hour,
+      start_time_.minute, start_time_.second, page_number + 1);
   const auto file_path = root_dir_.Append(kMyFilesPath).Append(filename);
   if (!base::WriteFile(file_path, scanned_image)) {
     LOG(ERROR) << "Failed to save scanned image: " << file_path.value().c_str();
diff --git a/chrome/browser/chromeos/scanning/scan_service.h b/chrome/browser/chromeos/scanning/scan_service.h
index 30f0acb..1fdd2bf7 100644
--- a/chrome/browser/chromeos/scanning/scan_service.h
+++ b/chrome/browser/chromeos/scanning/scan_service.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_SCANNING_SCAN_SERVICE_H_
 #define CHROME_BROWSER_CHROMEOS_SCANNING_SCAN_SERVICE_H_
 
+#include <cstdint>
 #include <string>
 #include <vector>
 
@@ -12,6 +13,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/time/time.h"
 #include "base/unguessable_token.h"
 #include "chromeos/components/scanning/mojom/scanning.mojom.h"
 #include "chromeos/dbus/lorgnette/lorgnette_service.pb.h"
@@ -65,7 +67,7 @@
 
   // Processes each |scanned_image| received after calling
   // LorgnetteScannerManager::Scan().
-  void OnPageReceived(std::string scanned_image);
+  void OnPageReceived(std::string scanned_image, uint32_t page_number);
 
   // Processes the final result of calling LorgnetteScannerManager::Scan().
   void OnScanCompleted(ScanCallback callback, bool success);
@@ -92,6 +94,9 @@
   // Indicates whether there was a failure to save scanned images.
   bool save_failed_;
 
+  // The time a scan was started. Used in filenames when saving scanned images.
+  base::Time::Exploded start_time_;
+
   base::WeakPtrFactory<ScanService> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 4330987..950cba5 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1375,11 +1375,6 @@
     "expiry_milestone": 85
   },
   {
-    "name": "enable-cssom-view-scroll-coordinates",
-    "owners": [ "cathiechen@igalia.com", "fwang@igalia.com" ],
-    "expiry_milestone": 87
-  },
-  {
     "name": "enable-data-reduction-proxy-server-experiment",
     "owners": [ "//components/data_reduction_proxy/OWNERS" ],
     // This flag is used for frequent manual testing and should not be removed.
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 3713c06..db4131e 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -752,16 +752,6 @@
     "scroller'. i.e. The one that gets special features like URL bar movement, "
     "overscroll glow, rotation anchoring, etc.";
 
-const char kEnableCSSOMViewScrollCoordinatesName[] =
-    "CSSOM View Scroll Coordinates";
-const char kEnableCSSOMViewScrollCoordinatesDescription[] =
-    "Enables CSSOM View Scroll Coordinates, this affects to box scroll "
-    "coordinates in scrollTop / scrollLeft / scrollTo' when ScrollOrigin isn't "
-    "at the left top corner. i.e. For leftwards overflow direction box "
-    "the X coordinate will start from 0 to negative value. For upwards box the "
-    "Y coordinate will start from 0 to negative value. And for other directions"
-    "(rightwards and downwards) the value will start from 0 to positive";
-
 const char kEnablePreviewsCoinFlipName[] = "Enable Previews Coin Flip";
 const char kEnablePreviewsCoinFlipDescription[] =
     "Enable coin flip experimentation of Previews.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index ab141170..db1a60d5 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -445,9 +445,6 @@
 extern const char kEnableImplicitRootScrollerName[];
 extern const char kEnableImplicitRootScrollerDescription[];
 
-extern const char kEnableCSSOMViewScrollCoordinatesName[];
-extern const char kEnableCSSOMViewScrollCoordinatesDescription[];
-
 extern const char kEnableLayoutNGName[];
 extern const char kEnableLayoutNGDescription[];
 
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
index 08a0d5f..1708f8d5 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
@@ -52,7 +52,7 @@
             put(ChromeFeatureList.CONDITIONAL_TAB_STRIP_ANDROID, false);
             put(ChromeFeatureList.HOMEPAGE_LOCATION_POLICY, false);
             put(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID, false);
-            put(ChromeFeatureList.SERVICE_MANAGER_FOR_DOWNLOAD, false);
+            put(ChromeFeatureList.SERVICE_MANAGER_FOR_DOWNLOAD, true);
             put(ChromeFeatureList.SERVICE_MANAGER_FOR_BACKGROUND_PREFETCH, true);
             put(ChromeFeatureList.COMMAND_LINE_ON_NON_ROOTED, false);
             put(ChromeFeatureList.DOWNLOADS_AUTO_RESUMPTION_NATIVE, true);
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
index b57a994..9d633b5 100644
--- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
+++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -166,6 +166,14 @@
   DCHECK(patch_level) << "Windows version too high!";
   base::UmaHistogramSparse("Windows.PatchLevel", patch_level);
 
+  int kernel32_patch = os_info.Kernel32VersionNumber().patch;
+  int kernel32_build = os_info.Kernel32VersionNumber().build;
+  int kernel32_patch_level = 0;
+  if (kernel32_patch < 65536 && kernel32_build < 65536)
+    kernel32_patch_level = MAKELONG(kernel32_patch, kernel32_build);
+  DCHECK(kernel32_patch_level) << "Windows kernel32.dll version too high!";
+  base::UmaHistogramSparse("Windows.PatchLevelKernel32", kernel32_patch_level);
+
   base::UmaHistogramBoolean("Windows.HasHighResolutionTimeTicks",
                             base::TimeTicks::IsHighResolution());
 
diff --git a/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc b/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc
index 820d7973..0e29e18 100644
--- a/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc
+++ b/chrome/browser/nearby_sharing/nearby_connections_manager_impl.cc
@@ -132,10 +132,10 @@
   }
 
   discovery_listener_ = listener;
-  // TODO(b/168659459): Inject kFastAdvertisementServiceUuid once BLE scanning
-  // actually uses it.
   nearby_connections_->StartDiscovery(
-      kServiceId, DiscoveryOptions::New(kStrategy),
+      kServiceId,
+      DiscoveryOptions::New(
+          kStrategy, device::BluetoothUUID(kFastAdvertisementServiceUuid)),
       endpoint_discovery_listener_.BindNewPipeAndPassRemote(),
       std::move(callback));
 }
diff --git a/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc b/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc
index be59aa9..207abe4 100644
--- a/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_connections_manager_impl_unittest.cc
@@ -145,6 +145,9 @@
                       NearbyConnectionsMojom::StartDiscoveryCallback callback) {
           EXPECT_EQ(kServiceId, service_id);
           EXPECT_EQ(kStrategy, options->strategy);
+          EXPECT_EQ(
+              device::BluetoothUUID("0000fef3-0000-1000-8000-00805f9b34fb"),
+              options->fast_advertisement_service_uuid);
 
           listener_remote.Bind(std::move(listener));
           std::move(callback).Run(Status::kSuccess);
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index 082cff3..61b3047 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -136,13 +136,13 @@
 // feature flag and policy. Next steps would be changing the feature value to
 // false after enough heads up and then removing the feature.
 bool IsAmbientAuthAllowedForProfile(Profile* profile) {
-  if (profile->IsRegularProfile())
+  if (profile->IsRegularProfile() && !profile->IsEphemeralGuestProfile())
     return true;
 
   // Non-primary OTR profiles are not used to create browser windows and are
   // only technical means for a task that does not need to leave state after
   // it's completed.
-  if (!profile->IsPrimaryOTRProfile())
+  if (profile->IsOffTheRecord() && !profile->IsPrimaryOTRProfile())
     return true;
 
   PrefService* local_state = g_browser_process->local_state();
@@ -154,7 +154,7 @@
       static_cast<net::AmbientAuthAllowedProfileTypes>(local_state->GetInteger(
           prefs::kAmbientAuthenticationInPrivateModesEnabled));
 
-  if (profile->IsGuestSession()) {
+  if (profile->IsGuestSession() || profile->IsEphemeralGuestProfile()) {
     return base::FeatureList::IsEnabled(
                features::kEnableAmbientAuthenticationInGuestSession) ||
            type == net::AmbientAuthAllowedProfileTypes::GUEST_AND_REGULAR ||
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
index f706d5b4..b325d08 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -979,14 +979,7 @@
   // as these numbers do not change for different visibility types.
   if (visibility != FrameData::FrameVisibility::kAnyVisibility)
     return;
-  ADS_HISTOGRAM("Bytes.FullPage.SameOrigin2", PAGE_BYTES_HISTOGRAM, visibility,
-                aggregate_frame_data_->same_origin_bytes());
-  if (aggregate_frame_data_->bytes()) {
-    ADS_HISTOGRAM("Bytes.FullPage.PercentSameOrigin2", UMA_HISTOGRAM_PERCENTAGE,
-                  visibility,
-                  aggregate_frame_data_->same_origin_bytes() * 100 /
-                      aggregate_frame_data_->bytes());
-  }
+
   ADS_HISTOGRAM("Bytes.MainFrame.Network", PAGE_BYTES_HISTOGRAM, visibility,
                 main_frame_data_->network_bytes());
   ADS_HISTOGRAM("Bytes.MainFrame.Total2", PAGE_BYTES_HISTOGRAM, visibility,
@@ -1097,17 +1090,11 @@
                   visibility, ad_frame_data.bytes());
     ADS_HISTOGRAM("Bytes.AdFrames.PerFrame.Network", PAGE_BYTES_HISTOGRAM,
                   visibility, ad_frame_data.network_bytes());
-    ADS_HISTOGRAM("Bytes.AdFrames.PerFrame.SameOrigin2", PAGE_BYTES_HISTOGRAM,
-                  visibility, ad_frame_data.same_origin_bytes());
     if (ad_frame_data.bytes() > 0) {
       ADS_HISTOGRAM(
           "Bytes.AdFrames.PerFrame.PercentNetwork2", UMA_HISTOGRAM_PERCENTAGE,
           visibility,
           ad_frame_data.network_bytes() * 100 / ad_frame_data.bytes());
-      ADS_HISTOGRAM(
-          "Bytes.AdFrames.PerFrame.PercentSameOrigin2",
-          UMA_HISTOGRAM_PERCENTAGE, visibility,
-          ad_frame_data.same_origin_bytes() * 100 / ad_frame_data.bytes());
     }
     ADS_HISTOGRAM("FrameCounts.AdFrames.PerFrame.OriginStatus",
                   UMA_HISTOGRAM_ENUMERATION, visibility,
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
index 9076e58..fea7c99 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -1098,43 +1098,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
-                       AdFrameSameOriginByteMetrics) {
-  base::HistogramTester histogram_tester;
-
-  // cross_site_iframe_factory loads URLs like:
-  // http://b.com:40919/cross_site_iframe_factory.html?b()
-  SetRulesetWithRules({subresource_filter::testing::CreateSuffixRule("b()))"),
-                       subresource_filter::testing::CreateSuffixRule("e())")});
-  const GURL main_url(embedded_test_server()->GetURL(
-      "a.com", "/cross_site_iframe_factory.html?a(b(c(),d(b())),e(e,e()))"));
-
-  auto waiter = CreatePageLoadMetricsTestWaiter();
-  ui_test_utils::NavigateToURL(browser(), main_url);
-
-  // One favicon resource and 2 resources for each frame.
-  waiter->AddMinimumCompleteResourcesExpectation(17);
-  waiter->Wait();
-
-  // Navigate away to force the histogram recording.
-  ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
-
-  // Verify that iframe e is only same origin.
-  histogram_tester.ExpectBucketCount(
-      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.PercentSameOrigin2", 100,
-      1);
-
-  // Verify that iframe b counts subframes as cross origin and a nested same
-  // origin subframe as same origin.
-  histogram_tester.ExpectBucketCount(
-      "PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame.PercentSameOrigin2", 50, 1);
-
-  // Verify that all iframe are treated as cross-origin to the page. Only 1/8 of
-  // resources are on origin a.com.
-  histogram_tester.ExpectBucketCount(
-      "PageLoad.Clients.Ads.Bytes.FullPage.PercentSameOrigin2", 12.5, 1);
-}
-
-IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverBrowserTest,
                        AdFrameRecordMediaStatusNotPlayed) {
   SetRulesetWithRules(
       {subresource_filter::testing::CreateSuffixRule("pixel.png")});
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
index 80c3f35..7dcdc33 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
@@ -69,7 +69,6 @@
     : root_frame_tree_node_id_(root_frame_tree_node_id),
       bytes_(0u),
       network_bytes_(0u),
-      same_origin_bytes_(0u),
       origin_status_(OriginStatus::kUnknown),
       creative_origin_status_(OriginStatus::kUnknown),
       frame_navigated_(false),
@@ -111,11 +110,8 @@
     const page_load_metrics::mojom::ResourceDataUpdatePtr& resource,
     int process_id,
     const page_load_metrics::ResourceTracker& resource_tracker) {
-  bool is_same_origin = origin_.IsSameOriginWith(resource->origin);
   bytes_ += resource->delta_bytes;
   network_bytes_ += resource->delta_bytes;
-  if (is_same_origin)
-    same_origin_bytes_ += resource->delta_bytes;
 
   content::GlobalRequestID global_id(process_id, resource->request_id);
   if (!resource_tracker.HasPreviousUpdateForResource(global_id))
@@ -125,8 +121,6 @@
   if (resource->is_complete &&
       resource->cache_type != page_load_metrics::mojom::CacheType::kNotCached) {
     bytes_ += resource->encoded_body_length;
-    if (is_same_origin)
-      same_origin_bytes_ += resource->encoded_body_length;
   }
 
   if (resource->reported_as_ad_resource) {
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h
index 8593f50..f1a8c3c 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h
@@ -243,8 +243,6 @@
 
   size_t network_bytes() const { return network_bytes_; }
 
-  size_t same_origin_bytes() const { return same_origin_bytes_; }
-
   size_t ad_bytes() const { return ad_bytes_; }
 
   size_t ad_network_bytes() const { return ad_network_bytes_; }
@@ -362,8 +360,6 @@
   size_t ad_bytes_ = 0u;
   size_t ad_network_bytes_ = 0u;
 
-  // The number of bytes that are same origin to the root ad frame.
-  size_t same_origin_bytes_;
   OriginStatus origin_status_;
   OriginStatus creative_origin_status_;
   bool frame_navigated_;
diff --git a/chrome/browser/payments/load_and_remove_iframe_with_many_payment_requests_browsertest.cc b/chrome/browser/payments/load_and_remove_iframe_with_many_payment_requests_browsertest.cc
index f170cea..b0c7d4f 100644
--- a/chrome/browser/payments/load_and_remove_iframe_with_many_payment_requests_browsertest.cc
+++ b/chrome/browser/payments/load_and_remove_iframe_with_many_payment_requests_browsertest.cc
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "build/build_config.h"
+#include "base/test/scoped_feature_list.h"
 #include "chrome/test/payments/payment_request_platform_browsertest_base.h"
+#include "components/payments/core/features.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -11,18 +12,21 @@
 namespace payments {
 namespace {
 
-// TODO(crbug.com/1129573): fix flakiness and reenable
-#if defined(OS_MAC)
-#define MAYBE_LoadAndRemoveIframeWithManyPaymentRequestsTest \
-  DISABLED_LoadAndRemoveIframeWithManyPaymentRequestsTest
-#else
-#define MAYBE_LoadAndRemoveIframeWithManyPaymentRequestsTest \
-  LoadAndRemoveIframeWithManyPaymentRequestsTest
-#endif
-
-class MAYBE_LoadAndRemoveIframeWithManyPaymentRequestsTest
+class LoadAndRemoveIframeWithManyPaymentRequestsTest
     : public PaymentRequestPlatformBrowserTestBase {
  public:
+  LoadAndRemoveIframeWithManyPaymentRequestsTest() {
+    // Enable the browser-side feature flag as it's disabled by default on
+    // non-origin trial platforms.
+    feature_list_.InitAndEnableFeature(features::kSecurePaymentConfirmation);
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    PaymentRequestPlatformBrowserTestBase::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
+  }
+
   void RunTest(const std::string& iframe_hostname) {
     NavigateTo("a.com", "/load_and_remove_iframe.html");
 
@@ -36,14 +40,16 @@
                                                "/create_many_requests.html")
                                       .spec())));
   }
+
+  base::test::ScopedFeatureList feature_list_;
 };
 
-IN_PROC_BROWSER_TEST_F(MAYBE_LoadAndRemoveIframeWithManyPaymentRequestsTest,
+IN_PROC_BROWSER_TEST_F(LoadAndRemoveIframeWithManyPaymentRequestsTest,
                        CrossOriginNoCrash) {
   RunTest(/*iframe_hostname=*/"b.com");
 }
 
-IN_PROC_BROWSER_TEST_F(MAYBE_LoadAndRemoveIframeWithManyPaymentRequestsTest,
+IN_PROC_BROWSER_TEST_F(LoadAndRemoveIframeWithManyPaymentRequestsTest,
                        SameOriginNoCrash) {
   RunTest(/*iframe_hostname=*/"a.com");
 }
diff --git a/chrome/browser/previews/defer_all_script_browsertest.cc b/chrome/browser/previews/defer_all_script_browsertest.cc
index 5e9a1a4e..6f26e522 100644
--- a/chrome/browser/previews/defer_all_script_browsertest.cc
+++ b/chrome/browser/previews/defer_all_script_browsertest.cc
@@ -242,6 +242,14 @@
       entry, UkmDeferEntry::kforce_deferred_scripts_mainframeName, 2);
   test_ukm_recorder.ExpectEntryMetric(
       entry, UkmDeferEntry::kforce_deferred_scripts_mainframe_externalName, 1);
+
+  // Opt out of the Preview page.
+  PreviewsUITabHelper::FromWebContents(
+      browser()->tab_strip_model()->GetActiveWebContents())
+      ->ReloadWithoutPreviews();
+
+  histogram_tester.ExpectBucketCount(
+      "Previews.OptOut.UserOptedOut.DeferAllScript", 1, 1);
 }
 
 // Test with an incognito browser.
diff --git a/chrome/browser/previews/previews_browsertest.cc b/chrome/browser/previews/previews_browsertest.cc
index f5a4e80..43b97e5 100644
--- a/chrome/browser/previews/previews_browsertest.cc
+++ b/chrome/browser/previews/previews_browsertest.cc
@@ -263,63 +263,8 @@
                          PreviewsNoScriptBrowserTest,
                          ::testing::Bool());
 
-// Loads a webpage that has both script and noscript tags and also requests
-// a script resource. Verifies that the noscript tag is evaluated and the
-// script resource is not loaded.
-IN_PROC_BROWSER_TEST_P(
-    PreviewsNoScriptBrowserTest,
-    DISABLE_ON_WIN_MAC_CHROMEOS_LINUX(NoScriptPreviewsEnabled)) {
-  GURL url = https_url();
 
-  // Whitelist NoScript for https_hint_setup_url()'s' host.
-  SetUpNoScriptWhitelist(https_hint_setup_url());
 
-  base::HistogramTester histogram_tester;
-  ui_test_utils::NavigateToURL(browser(), url);
-
-  // Verify loaded noscript tag triggered css resource but not js one.
-  EXPECT_TRUE(noscript_css_requested());
-  EXPECT_FALSE(noscript_js_requested());
-
-  // Verify info bar presented via histogram check.
-  RetryForHistogramUntilCountReached(&histogram_tester,
-                                     "Previews.PreviewShown.NoScript", 1);
-}
-
-IN_PROC_BROWSER_TEST_P(
-    PreviewsNoScriptBrowserTest,
-    DISABLE_ON_WIN_MAC_CHROMEOS(NoScriptPreviewsEnabled_Incognito)) {
-  GURL url = https_url();
-
-  // Whitelist NoScript for https_hint_setup_url()'s' host.
-  SetUpNoScriptWhitelist(https_hint_setup_url());
-
-  base::HistogramTester histogram_tester;
-  Browser* incognito = CreateIncognitoBrowser();
-  ASSERT_FALSE(PreviewsServiceFactory::GetForProfile(incognito->profile()));
-  ASSERT_TRUE(PreviewsServiceFactory::GetForProfile(browser()->profile()));
-
-  ui_test_utils::NavigateToURL(incognito, url);
-
-  // Verify JS was loaded indicating that NoScript preview was not triggered.
-  EXPECT_FALSE(noscript_css_requested());
-  EXPECT_TRUE(noscript_js_requested());
-}
-
-IN_PROC_BROWSER_TEST_P(
-    PreviewsNoScriptBrowserTest,
-    DISABLE_ON_WIN_MAC_CHROMEOS_LINUX(NoScriptPreviewsForHttp)) {
-  GURL url = http_url();
-
-  // Whitelist NoScript for http_hint_setup_url() host.
-  SetUpNoScriptWhitelist(http_hint_setup_url());
-
-  ui_test_utils::NavigateToURL(browser(), url);
-
-  // Verify loaded noscript tag triggered css resource but not js one.
-  EXPECT_TRUE(noscript_css_requested());
-  EXPECT_FALSE(noscript_js_requested());
-}
 
 IN_PROC_BROWSER_TEST_P(PreviewsNoScriptBrowserTest,
                        DISABLE_ON_WIN_MAC_CHROMEOS(
@@ -340,67 +285,7 @@
       "Previews.CacheControlNoTransform.BlockedPreview", 5 /* NoScript */, 1);
 }
 
-IN_PROC_BROWSER_TEST_P(PreviewsNoScriptBrowserTest,
-                       DISABLE_ON_WIN_MAC_CHROMEOS_LINUX(
-                           NoScriptPreviewsEnabledHttpRedirectToHttps)) {
-  GURL url = redirect_url();
 
-  // Whitelist NoScript for http_hint_setup_url() host.
-  SetUpNoScriptWhitelist(http_hint_setup_url());
-
-  base::HistogramTester histogram_tester;
-  ui_test_utils::NavigateToURL(browser(), url);
-
-  // Verify loaded noscript tag triggered css resource but not js one.
-  EXPECT_TRUE(noscript_css_requested());
-  EXPECT_FALSE(noscript_js_requested());
-
-  // Verify info bar presented via histogram check.
-  RetryForHistogramUntilCountReached(&histogram_tester,
-                                     "Previews.PreviewShown.NoScript", 1);
-}
-
-IN_PROC_BROWSER_TEST_P(
-    PreviewsNoScriptBrowserTest,
-    DISABLE_ON_WIN_MAC_CHROMEOS_LINUX(NoScriptPreviewsRecordsOptOut)) {
-  GURL url = redirect_url();
-
-  // Whitelist NoScript for http_hint_setup_url()'s' host.
-  SetUpNoScriptWhitelist(http_hint_setup_url());
-
-  base::HistogramTester histogram_tester;
-
-  // Navigate to a NoScript Preview page.
-  ui_test_utils::NavigateToURL(browser(), url);
-
-  // Terminate the previous page (non-opt out) and pull up a new NoScript page.
-  ui_test_utils::NavigateToURL(browser(), url);
-  histogram_tester.ExpectUniqueSample("Previews.OptOut.UserOptedOut.NoScript",
-                                      0, 1);
-
-  // Opt out of the NoScript Preview page.
-  PreviewsUITabHelper::FromWebContents(
-      browser()->tab_strip_model()->GetActiveWebContents())
-      ->ReloadWithoutPreviews();
-
-  histogram_tester.ExpectBucketCount("Previews.OptOut.UserOptedOut.NoScript", 1,
-                                     1);
-}
-
-IN_PROC_BROWSER_TEST_P(
-    PreviewsNoScriptBrowserTest,
-    DISABLE_ON_WIN_MAC_CHROMEOS_LINUX(NoScriptPreviewsEnabledByWhitelist)) {
-  GURL url = https_url();
-
-  // Whitelist NoScript for https_hint_setup_url()'s' host.
-  SetUpNoScriptWhitelist(https_hint_setup_url());
-
-  ui_test_utils::NavigateToURL(browser(), url);
-
-  // Verify loaded noscript tag triggered css resource but not js one.
-  EXPECT_TRUE(noscript_css_requested());
-  EXPECT_FALSE(noscript_js_requested());
-}
 
 IN_PROC_BROWSER_TEST_P(
     PreviewsNoScriptBrowserTest,
diff --git a/chrome/browser/previews/previews_test_util.h b/chrome/browser/previews/previews_test_util.h
index 85052f11..fd272cf6 100644
--- a/chrome/browser/previews/previews_test_util.h
+++ b/chrome/browser/previews/previews_test_util.h
@@ -42,14 +42,4 @@
 #define DISABLE_ON_WIN_MAC_CHROMEOS(x) x
 #endif
 
-// Previews InfoBar (which these tests trigger) does not work on Mac.
-// See https://crbug.com/782322 for details. Also occasional flakes on win7
-// (https://crbug.com/789542) and linux (https://crbug.com/1095566).
-#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_CHROMEOS) || \
-    defined(OS_LINUX)
-#define DISABLE_ON_WIN_MAC_CHROMEOS_LINUX(x) DISABLED_##x
-#else
-#define DISABLE_ON_WIN_MAC_CHROMEOS_LINUX(x) x
-#endif
-
 #endif  // CHROME_BROWSER_PREVIEWS_PREVIEWS_TEST_UTIL_H_
diff --git a/chrome/browser/resources/optimize_webui.py b/chrome/browser/resources/optimize_webui.py
index 00da924..ced44401 100755
--- a/chrome/browser/resources/optimize_webui.py
+++ b/chrome/browser/resources/optimize_webui.py
@@ -359,7 +359,7 @@
     # Pass the JS files through Uglify and write the output to its final
     # destination.
     for index, js_out_file in enumerate(args.js_out_files):
-      node.RunNode([node_modules.PathToUglify(),
+      node.RunNode([node_modules.PathToTerser(),
                     os.path.join(tmp_out_dir, js_out_file),
                     '--comments', '/Copyright|license|LICENSE|\<\/?if/',
                     '--output', os.path.join(out_path, js_out_file)])
diff --git a/chrome/browser/ui/ash/holding_space/holding_space_util.cc b/chrome/browser/ui/ash/holding_space/holding_space_util.cc
index fa97c04d..1d03b4d 100644
--- a/chrome/browser/ui/ash/holding_space/holding_space_util.cc
+++ b/chrome/browser/ui/ash/holding_space/holding_space_util.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/ash/holding_space/holding_space_util.h"
 
 #include "ash/public/cpp/file_icon_util.h"
+#include "ash/public/cpp/holding_space/holding_space_color_provider.h"
 #include "ash/public/cpp/holding_space/holding_space_constants.h"
 #include "ash/public/cpp/holding_space/holding_space_image.h"
 #include "base/barrier_closure.h"
@@ -39,12 +40,15 @@
       break;
   }
 
+  const SkColor color = HoldingSpaceColorProvider::Get()->GetFileIconColor();
+
   // NOTE: We superimpose the file type icon for `file_path` over a transparent
   // bitmap in order to center it within the placeholder image at a fixed size.
   SkBitmap bitmap;
   bitmap.allocN32Pixels(size.width(), size.height());
   return gfx::ImageSkiaOperations::CreateSuperimposedImage(
-      gfx::ImageSkia::CreateFrom1xBitmap(bitmap), GetIconForPath(file_path));
+      gfx::ImageSkia::CreateFrom1xBitmap(bitmap),
+      GetIconForPath(file_path, color));
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/cocoa/task_manager_mac.mm b/chrome/browser/ui/cocoa/task_manager_mac.mm
index b9d67711..f8824ce 100644
--- a/chrome/browser/ui/cocoa/task_manager_mac.mm
+++ b/chrome/browser/ui/cocoa/task_manager_mac.mm
@@ -287,9 +287,12 @@
       [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, 400, 200)]);
   [tableView setAllowsColumnReordering:NO];
   [tableView setAllowsMultipleSelection:YES];
+  // No autosaving, since column identifiers are IDS_ values which are not
+  // stable. TODO(avi): Would it be worth it to find stable identifiers so that
+  // we could use autosaving?
   [tableView setAutosaveTableColumns:NO];
   [tableView
-      setColumnAutoresizingStyle:NSTableViewSequentialColumnAutoresizingStyle];
+      setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle];
   [tableView setDoubleAction:@selector(tableWasDoubleClicked:)];
   [tableView setFocusRingType:NSFocusRingTypeNone];
   [tableView setIntercellSpacing:NSMakeSize(0, 0)];
@@ -308,14 +311,17 @@
   base::scoped_nsobject<NSTableColumn> column([[NSTableColumn alloc]
       initWithIdentifier:ColumnIdentifier(columnData.id)]);
 
+  NSTableHeaderCell* headerCell = [column.get() headerCell];
+  id dataCell = [column.get() dataCell];
+
   NSTextAlignment textAlignment = (columnData.align == ui::TableColumn::LEFT)
                                       ? NSLeftTextAlignment
                                       : NSRightTextAlignment;
 
-  [[column.get() headerCell]
-      setStringValue:l10n_util::GetNSStringWithFixup(columnData.id)];
-  [[column.get() headerCell] setAlignment:textAlignment];
-  [[column.get() dataCell] setAlignment:textAlignment];
+  NSString* columnTitle = l10n_util::GetNSStringWithFixup(columnData.id);
+  [headerCell setStringValue:columnTitle];
+  [headerCell setAlignment:textAlignment];
+  [dataCell setAlignment:textAlignment];
 
   const CGFloat smallSystemFontSize = [NSFont smallSystemFontSize];
   NSFont* font = nil;
@@ -325,7 +331,7 @@
   } else {
     font = [NSFont systemFontOfSize:smallSystemFontSize];
   }
-  [[column.get() dataCell] setFont:font];
+  [dataCell setFont:font];
 
   [column.get() setHidden:!columnData.default_visibility];
   [column.get() setEditable:NO];
@@ -337,8 +343,20 @@
   [column.get() setSortDescriptorPrototype:sortDescriptor.get()];
 
   [column.get() setMinWidth:columnData.min_width];
-  if (columnData.max_width > 0)
-    [column.get() setMaxWidth:columnData.max_width];
+  // If there is no specified max width, use a reasonable value of 1.5x the min
+  // width, but make sure that the max width is big enough to actually show the
+  // entire column title.
+  const int kTitleMargin = 40;  // Space for the arrow, etc.
+  int maxWidth = columnData.max_width;
+  if (maxWidth <= 0)
+    maxWidth = 3 * columnData.min_width / 2;
+  int columnTitleWidth =
+      [columnTitle
+          sizeWithAttributes:@{NSFontAttributeName : [headerCell font]}]
+          .width +
+      kTitleMargin;
+  maxWidth = std::max(maxWidth, columnTitleWidth);
+  [column.get() setMaxWidth:maxWidth];
   [column.get() setResizingMask:NSTableColumnAutoresizingMask |
                                 NSTableColumnUserResizingMask];
 
diff --git a/chrome/browser/ui/exclusive_access/flash_fullscreen_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/flash_fullscreen_interactive_browsertest.cc
deleted file mode 100644
index 19513680..0000000
--- a/chrome/browser/ui/exclusive_access/flash_fullscreen_interactive_browsertest.cc
+++ /dev/null
@@ -1,423 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/test/base/interactive_test_utils.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "chrome/test/ppapi/ppapi_test.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/test_utils.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-namespace {
-
-#if defined(OS_MAC)
-const bool kIsMacUI = true;
-#else
-const bool kIsMacUI = false;
-#endif
-
-// Runs the current MessageLoop until |condition| is true or timeout.
-bool RunLoopUntil(const base::Callback<bool()>& condition) {
-  const base::TimeTicks start_time = base::TimeTicks::Now();
-  while (!condition.Run()) {
-    const base::TimeTicks current_time = base::TimeTicks::Now();
-    if (current_time - start_time > base::TimeDelta::FromSeconds(10)) {
-      ADD_FAILURE() << "Condition not met within ten seconds.";
-      return false;
-    }
-
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
-        base::TimeDelta::FromMilliseconds(20));
-    content::RunMessageLoop();
-  }
-  return true;
-}
-
-}  // namespace
-
-// A BrowserTest that opens a test page that launches a simulated fullscreen
-// Flash plugin.  The plugin responds to mouse clicks and key presses by
-// changing color.  Once launched, the browser UI can be tested to confirm the
-// desired interactive behaviors.
-class FlashFullscreenInteractiveBrowserTest : public OutOfProcessPPAPITest {
- public:
-  FlashFullscreenInteractiveBrowserTest() {}
-  ~FlashFullscreenInteractiveBrowserTest() override {}
-
- protected:
-  content::WebContents* GetActiveWebContents() const {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
-  // A simple way to convince libcontent and the browser UI that a tab is being
-  // screen captured.  During tab capture, Flash fullscreen remains embedded
-  // within the tab content area of a non-fullscreened browser window.
-  void StartFakingTabCapture() {
-    GetActiveWebContents()->IncrementCapturerCount(gfx::Size(360, 240),
-                                                   /* stay_hidden */ false);
-  }
-
-  bool LaunchFlashFullscreen() {
-    // This navigates to a page that runs the simulated fullscreen Flash
-    // plugin.  It will block until the plugin has completed an attempt to enter
-    // Flash fullscreen mode.
-    OutOfProcessPPAPITest::RunTest("FlashFullscreenForBrowserUI");
-
-    if (::testing::Test::HasFailure()) {
-      ADD_FAILURE() << ("Failed to launch simulated fullscreen Flash plugin.  "
-                        "Interactive UI testing cannot proceed.");
-      return false;
-    }
-
-    EXPECT_TRUE(ObserveTabIsInFullscreen(true));
-
-    return !::testing::Test::HasFailure();
-  }
-
-  bool LaunchFlashFullscreenInSubframe() {
-    // Load a page with an <iframe> that points to the test case URL, which
-    // runs the simulated fullscreen Flash plugin.  In OOPIF modes, the frame
-    // will render in a separate process.  Block until the plugin has completed
-    // an attempt to enter Flash fullscreen mode.
-    GURL test_url = GetTestURL(*embedded_test_server(),
-                               "FlashFullscreenForBrowserUI", std::string());
-    GURL main_url("data:text/html,<iframe src='" + test_url.spec() +
-                  "'></iframe>");
-    OutOfProcessPPAPITest::RunTestURL(main_url);
-
-    if (::testing::Test::HasFailure()) {
-      ADD_FAILURE() << ("Failed to launch simulated fullscreen Flash plugin.  "
-                        "Interactive UI testing cannot proceed.");
-      return false;
-    }
-
-    EXPECT_TRUE(ObserveTabIsInFullscreen(true));
-
-    return !::testing::Test::HasFailure();
-  }
-
-  void UseAcceleratorToOpenNewTab() {
-    content::WebContents* const old_tab_contents = GetActiveWebContents();
-    EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
-        browser(), ui::VKEY_T, !kIsMacUI, false, false, kIsMacUI));
-    EXPECT_TRUE(RunLoopUntil(base::Bind(
-        &FlashFullscreenInteractiveBrowserTest::IsObservingActiveWebContents,
-        base::Unretained(this),
-        old_tab_contents,
-        false)));
-  }
-
-  void UseAcceleratorToSwitchToTab(int tab_index) {
-    content::WebContents* const old_tab_contents = GetActiveWebContents();
-    const ui::KeyboardCode key_code =
-        static_cast<ui::KeyboardCode>(ui::VKEY_1 + tab_index);
-    EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
-        browser(), key_code, !kIsMacUI, false, false, kIsMacUI));
-    EXPECT_TRUE(RunLoopUntil(base::Bind(
-        &FlashFullscreenInteractiveBrowserTest::IsObservingActiveWebContents,
-        base::Unretained(this),
-        old_tab_contents,
-        false)));
-  }
-
-  void PressEscape() {
-    EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
-        browser(), ui::VKEY_ESCAPE, false, false, false, false));
-  }
-
-  void PressSpacebar() {
-    EXPECT_TRUE(ui_test_utils::SendKeyPressSync(
-        browser(), ui::VKEY_SPACE, false, false, false, false));
-  }
-
-  void SpamSpacebar() {
-    for (int i = 0; i < 11; ++i)
-      PressSpacebar();
-  }
-
-  void ClickOnTabContainer() {
-    ui_test_utils::ClickOnView(browser(), VIEW_ID_TAB_CONTAINER);
-  }
-
-  void ClickOnOmnibox() {
-    ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
-  }
-
-  bool ObserveTabIsInFullscreen(bool expected_in_fullscreen) const {
-    if (!RunLoopUntil(base::Bind(
-            &FlashFullscreenInteractiveBrowserTest::IsObservingTabInFullscreen,
-            base::Unretained(this),
-            GetActiveWebContents(),
-            expected_in_fullscreen)))
-      return false;
-
-    if (expected_in_fullscreen) {
-      if (!GetActiveWebContents()->GetFullscreenRenderWidgetHostView()) {
-        ADD_FAILURE()
-            << "WebContents should have a fullscreen RenderWidgetHostView.";
-        return false;
-      }
-      EXPECT_EQ(GetActiveWebContents()->IsBeingCaptured(),
-                !browser()
-                     ->exclusive_access_manager()
-                     ->fullscreen_controller()
-                     ->IsWindowFullscreenForTabOrPending());
-    }
-
-    return true;
-  }
-
-  bool ObserveFlashHasFocus(content::WebContents* contents,
-                            bool expected_to_have_focus) const {
-    if (!RunLoopUntil(base::Bind(
-            &FlashFullscreenInteractiveBrowserTest::IsObservingFlashHasFocus,
-            base::Unretained(this),
-            contents,
-            expected_to_have_focus)))
-      return false;
-
-    if (expected_to_have_focus) {
-      content::RenderWidgetHostView* const web_page_view =
-          contents->GetRenderWidgetHostView();
-      EXPECT_FALSE(web_page_view && web_page_view->HasFocus())
-          << "Both RenderWidgetHostViews cannot have focus at the same time.";
-
-      if (contents == GetActiveWebContents())
-        EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(),
-                                                 VIEW_ID_TAB_CONTAINER));
-    }
-
-    return true;
-  }
-
-  bool ObserveFlashFillColor(SkColor expected_color) const {
-    return RunLoopUntil(base::Bind(
-        &FlashFullscreenInteractiveBrowserTest::IsObservingFlashFillColor,
-        base::Unretained(this),
-        expected_color));
-  }
-
- private:
-  bool IsObservingTabInFullscreen(content::WebContents* contents,
-                                  bool expected_in_fullscreen) const {
-    return expected_in_fullscreen ==
-           browser()
-               ->exclusive_access_manager()
-               ->fullscreen_controller()
-               ->IsFullscreenForTabOrPending(contents);
-  }
-
-  bool IsObservingFlashHasFocus(content::WebContents* contents,
-                                bool expected_to_have_focus) const {
-    content::RenderWidgetHostView* const flash_fs_view =
-        contents->GetFullscreenRenderWidgetHostView();
-    const bool flash_has_focus = flash_fs_view && flash_fs_view->HasFocus();
-    return flash_has_focus == expected_to_have_focus;
-  }
-
-  bool IsObservingActiveWebContents(content::WebContents* contents,
-                                    bool expected_active_contents) const {
-    return (contents == GetActiveWebContents()) == expected_active_contents;
-  }
-
-  bool IsObservingFlashFillColor(SkColor expected_color) const {
-    content::RenderWidgetHostView* const flash_fs_view =
-        GetActiveWebContents()->GetFullscreenRenderWidgetHostView();
-    if (!flash_fs_view) {
-      ADD_FAILURE() << "Flash fullscreen RenderWidgetHostView is gone.";
-      return false;
-    }
-
-    // When a widget is first shown, it can take some time before it is ready
-    // for copying from its backing store.  This is a transient condition, and
-    // so it is not being treated as a test failure.
-    if (!flash_fs_view->IsSurfaceAvailableForCopy())
-      return false;
-
-    // Copy and examine the upper-left pixel of the widget and compare it to the
-    // |expected_color|.
-    bool is_expected_color = false;
-    base::RunLoop run_loop;
-    flash_fs_view->CopyFromSurface(
-        gfx::Rect(0, 0, 1, 1), gfx::Size(1, 1),
-        base::BindOnce(
-            &FlashFullscreenInteractiveBrowserTest::CheckBitmapForFillColor,
-            expected_color, &is_expected_color, run_loop.QuitClosure()));
-    run_loop.Run();
-
-    return is_expected_color;
-  }
-
-  static void CheckBitmapForFillColor(SkColor expected_color,
-                                      bool* is_expected_color,
-                                      const base::Closure& done_cb,
-                                      const SkBitmap& bitmap) {
-    if (!bitmap.drawsNothing())
-      *is_expected_color = (bitmap.getColor(0, 0) == expected_color);
-    done_cb.Run();
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(FlashFullscreenInteractiveBrowserTest);
-};
-
-// Tests that launching and exiting fullscreen-within-tab works.
-IN_PROC_BROWSER_TEST_F(FlashFullscreenInteractiveBrowserTest,
-                       FullscreenWithinTab_EscapeKeyExitsFullscreen) {
-  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  StartFakingTabCapture();
-  ASSERT_TRUE(LaunchFlashFullscreen());
-  content::WebContents* const first_tab_contents = GetActiveWebContents();
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
-  PressEscape();
-  EXPECT_TRUE(ObserveTabIsInFullscreen(false));
-}
-
-IN_PROC_BROWSER_TEST_F(FlashFullscreenInteractiveBrowserTest,
-                       FullscreenFromSubframe) {
-  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  StartFakingTabCapture();
-  ASSERT_TRUE(LaunchFlashFullscreenInSubframe());
-  content::WebContents* const first_tab_contents = GetActiveWebContents();
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
-  PressEscape();
-  EXPECT_TRUE(ObserveTabIsInFullscreen(false));
-}
-
-// This tests that browser UI focus behavior is correct when switching between
-// tabs; particularly, that that focus between the omnibox and tab contents is
-// stored/restored correctly.  Mouse and keyboard events are used to confirm
-// that the widget the UI thinks is focused is the one that responds to these
-// input events.
-//
-// Flaky, see http://crbug.com/444476
-IN_PROC_BROWSER_TEST_F(FlashFullscreenInteractiveBrowserTest,
-                       DISABLED_FullscreenWithinTab_FocusWhenSwitchingTabs) {
-  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  StartFakingTabCapture();
-  ASSERT_TRUE(LaunchFlashFullscreen());
-
-  // Upon entering fullscreen, the Flash widget should have focus and be filled
-  // with green.
-  content::WebContents* const first_tab_contents = GetActiveWebContents();
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorGREEN));
-
-  // Pressing the spacebar on the keyboard should change the fill color to red
-  // to indicate the plugin truly does have the keyboard focus.  Clicking on the
-  // view should change the fill color to blue.
-  PressSpacebar();
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorRED));
-  ClickOnTabContainer();
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
-
-  // Launch a new tab.  The Flash widget should have lost focus.
-  UseAcceleratorToOpenNewTab();
-  content::WebContents* const second_tab_contents = GetActiveWebContents();
-  ASSERT_NE(first_tab_contents, second_tab_contents);
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
-  ClickOnOmnibox();
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
-  SpamSpacebar();
-
-  // Switch back to first tab.  The plugin should not have responded to the key
-  // presses above (while the omnibox was focused), and should regain focus only
-  // now.  Poke it with key and mouse events to confirm.
-  UseAcceleratorToSwitchToTab(0);
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
-  PressSpacebar();
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorRED));
-  ClickOnTabContainer();
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
-
-  // Click on the omnibox while still in the first tab, and the Flash widget
-  // should lose focus.  Key presses should not affect the color of the Flash
-  // widget.
-  ClickOnOmnibox();
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
-  SpamSpacebar();
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
-
-  // Switch to the second tab, click on the web page content, and then go back
-  // to the first tab.  Focus should have been restored to the omnibox when
-  // going back to the first tab, and so key presses should not change the color
-  // of the Flash widget.
-  UseAcceleratorToSwitchToTab(1);
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
-  ClickOnTabContainer();
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
-  UseAcceleratorToSwitchToTab(0);
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, false));
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
-  SpamSpacebar();
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
-
-  // Clicking on the Flash widget should give it focus again.
-  ClickOnTabContainer();
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorRED));
-  PressSpacebar();
-  ASSERT_TRUE(ObserveFlashFillColor(SK_ColorBLUE));
-
-  // Test that the Escape key is handled as an exit fullscreen command while the
-  // Flash widget has the focus.
-  EXPECT_TRUE(ObserveFlashHasFocus(first_tab_contents, true));
-  PressEscape();
-  EXPECT_TRUE(ObserveTabIsInFullscreen(false));
-}
-
-// Tests that a fullscreen flash plugin can lock the mouse, and that it'll be
-// unlocked when the plugin exits fullscreen.
-// Flaky on Linux. See https://crbug.com/706148.
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
-#define MAYBE_Fullscreen_LockMouse DISABLED_Fullscreen_LockMouse
-#else
-#define MAYBE_Fullscreen_LockMouse Fullscreen_LockMouse
-#endif
-IN_PROC_BROWSER_TEST_F(FlashFullscreenInteractiveBrowserTest,
-                       MAYBE_Fullscreen_LockMouse) {
-  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
-  StartFakingTabCapture();
-  ASSERT_TRUE(LaunchFlashFullscreen());
-  content::WebContents* web_contents = GetActiveWebContents();
-  EXPECT_TRUE(ObserveFlashHasFocus(web_contents, true));
-
-  // Try to lock the mouse.
-  content::RenderWidgetHostView* fullscreen_view =
-      web_contents->GetFullscreenRenderWidgetHostView();
-  content::RenderWidgetHost* fullscreen_widget =
-      fullscreen_view->GetRenderWidgetHost();
-  content::RequestMouseLock(fullscreen_widget, /*from_user_gesture=*/true,
-                            /*privileged=*/true, /*unadjusted_movement=*/false);
-
-  // Make sure that the fullscreen widget got the mouse lock.
-  EXPECT_TRUE(fullscreen_view->IsMouseLocked());
-  EXPECT_EQ(fullscreen_widget, content::GetMouseLockWidget(web_contents));
-
-  PressEscape();
-  EXPECT_TRUE(ObserveTabIsInFullscreen(false));
-
-  // Mouse should be unlocked.
-  EXPECT_EQ(nullptr, content::GetMouseLockWidget(web_contents));
-}
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc
index 76df263..79993c6 100644
--- a/chrome/browser/ui/hats/hats_service.cc
+++ b/chrome/browser/ui/hats/hats_service.cc
@@ -62,6 +62,9 @@
 constexpr base::TimeDelta kMinimumTimeBetweenSurveyStarts =
     base::TimeDelta::FromDays(60);
 
+constexpr base::TimeDelta kMinimumTimeBetweenAnySurveyStarts =
+    base::TimeDelta::FromDays(7);
+
 constexpr base::TimeDelta kMinimumTimeBetweenSurveyChecks =
     base::TimeDelta::FromDays(1);
 
@@ -72,6 +75,9 @@
 // The valid keys and value types for this dictionary are as follows:
 // [trigger].last_major_version        ---> Integer
 // [trigger].last_survey_started_time  ---> Time
+// [trigger].is_survey_full            ---> Bool
+// [trigger].last_survey_check_time    ---> Time
+// any_last_survey_started_time        ---> Time
 
 std::string GetMajorVersionPath(const std::string& trigger) {
   return trigger + ".last_major_version";
@@ -89,6 +95,8 @@
   return trigger + ".last_survey_check_time";
 }
 
+constexpr char kAnyLastSurveyStartedTimePath[] = "any_last_survey_started_time";
+
 }  // namespace
 
 HatsService::SurveyMetadata::SurveyMetadata() = default;
@@ -214,6 +222,8 @@
                         version_info::GetVersion().components()[0]);
   pref_data->SetPath(GetLastSurveyStartedTime(trigger),
                      util::TimeToValue(base::Time::Now()));
+  pref_data->SetPath(kAnyLastSurveyStartedTimePath,
+                     util::TimeToValue(base::Time::Now()));
 }
 
 void HatsService::HatsNextDialogClosed() {
@@ -246,6 +256,14 @@
     pref_data->RemovePath(GetLastSurveyStartedTime(trigger));
   }
 
+  if (metadata.any_last_survey_started_time.has_value()) {
+    pref_data->SetPath(
+        kAnyLastSurveyStartedTimePath,
+        util::TimeToValue(*metadata.any_last_survey_started_time));
+  } else {
+    pref_data->RemovePath(kAnyLastSurveyStartedTimePath);
+  }
+
   if (metadata.is_survey_full.has_value()) {
     pref_data->SetBoolPath(GetIsSurveyFull(trigger), *metadata.is_survey_full);
   } else {
@@ -276,6 +294,11 @@
   if (last_survey_started_time.has_value())
     metadata->last_survey_started_time = last_survey_started_time;
 
+  base::Optional<base::Time> any_last_survey_started_time =
+      util::ValueToTime(pref_data->FindPath(kAnyLastSurveyStartedTimePath));
+  if (any_last_survey_started_time.has_value())
+    metadata->any_last_survey_started_time = any_last_survey_started_time;
+
   base::Optional<bool> is_survey_full =
       pref_data->FindBoolPath(GetIsSurveyFull(trigger));
   if (is_survey_full.has_value())
@@ -409,6 +432,21 @@
     }
   }
 
+  // The time any survey was started will always be equal or more recent than
+  // the time a particular survey was started, so it is checked afterwards to
+  // improve UMA logging.
+  base::Optional<base::Time> last_any_started_time =
+      util::ValueToTime(pref_data->FindPath(kAnyLastSurveyStartedTimePath));
+  if (last_any_started_time.has_value()) {
+    base::TimeDelta elapsed_time_any_started = now - *last_any_started_time;
+    if (elapsed_time_any_started < kMinimumTimeBetweenAnySurveyStarts) {
+      UMA_HISTOGRAM_ENUMERATION(
+          kHatsShouldShowSurveyReasonHistogram,
+          ShouldShowSurveyReasons::kNoAnyLastSurveyTooRecent);
+      return false;
+    }
+  }
+
   auto probability_ = survey_configs_by_triggers_.at(trigger).probability_;
   bool should_show_survey = base::RandDouble() < probability_;
   if (!should_show_survey) {
diff --git a/chrome/browser/ui/hats/hats_service.h b/chrome/browser/ui/hats/hats_service.h
index 8cdfc72..bae175c 100644
--- a/chrome/browser/ui/hats/hats_service.h
+++ b/chrome/browser/ui/hats/hats_service.h
@@ -62,10 +62,14 @@
     SurveyMetadata();
     ~SurveyMetadata();
 
+    // Trigger specific metadata.
     base::Optional<int> last_major_version;
     base::Optional<base::Time> last_survey_started_time;
     base::Optional<bool> is_survey_full;
     base::Optional<base::Time> last_survey_check_time;
+
+    // Metadata affecting all triggers.
+    base::Optional<base::Time> any_last_survey_started_time;
   };
 
   class DelayedSurveyTask : public content::WebContentsObserver {
@@ -119,7 +123,8 @@
     kNoSurveyUnreachable = 12,
     kNoSurveyOverCapacity = 13,
     kNoSurveyAlreadyInProgress = 14,
-    kMaxValue = kNoSurveyAlreadyInProgress,
+    kNoAnyLastSurveyTooRecent = 15,
+    kMaxValue = kNoAnyLastSurveyTooRecent,
   };
 
   ~HatsService() override;
diff --git a/chrome/browser/ui/hats/hats_service_browsertest.cc b/chrome/browser/ui/hats/hats_service_browsertest.cc
index 89176da8..b0a192d3 100644
--- a/chrome/browser/ui/hats/hats_service_browsertest.cc
+++ b/chrome/browser/ui/hats/hats_service_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/metrics/user_metrics.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -311,6 +312,20 @@
   EXPECT_FALSE(HatsBubbleShown());
 }
 
+IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
+                       SurveyStartedBeforeElapsedTimeBetweenAnySurveys) {
+  SetMetricsConsent(true);
+  base::HistogramTester histogram_tester;
+  HatsService::SurveyMetadata metadata;
+  metadata.any_last_survey_started_time = base::Time::Now();
+  GetHatsService()->SetSurveyMetadataForTesting(metadata);
+  GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSatisfaction);
+  EXPECT_FALSE(HatsBubbleShown());
+  histogram_tester.ExpectUniqueSample(
+      kHatsShouldShowSurveyReasonHistogram,
+      HatsService::ShouldShowSurveyReasons::kNoAnyLastSurveyTooRecent, 1);
+}
+
 IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, ProfileTooYoungToShow) {
   SetMetricsConsent(true);
   // Set creation time to only 15 days.
diff --git a/chrome/browser/ui/managed_ui.cc b/chrome/browser/ui/managed_ui.cc
index 5c803f9..bdbb289d 100644
--- a/chrome/browser/ui/managed_ui.cc
+++ b/chrome/browser/ui/managed_ui.cc
@@ -12,7 +12,10 @@
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "ui/chromeos/devicetype_utils.h"
 #endif
 
@@ -33,48 +36,50 @@
 }
 
 base::string16 GetManagedUiMenuItemLabel(Profile* profile) {
-  std::string management_domain =
-      ManagementUIHandler::GetAccountDomain(profile);
+  std::string account_manager = ManagementUIHandler::GetAccountManager(profile);
 
   int string_id = IDS_MANAGED;
   std::vector<base::string16> replacements;
-  if (!management_domain.empty()) {
+  if (!account_manager.empty()) {
     string_id = IDS_MANAGED_BY;
-    replacements.push_back(base::UTF8ToUTF16(management_domain));
+    replacements.push_back(base::UTF8ToUTF16(account_manager));
   }
 
   return l10n_util::GetStringFUTF16(string_id, replacements, nullptr);
 }
 
 base::string16 GetManagedUiWebUILabel(Profile* profile) {
-  std::string management_domain =
-      ManagementUIHandler::GetAccountDomain(profile);
+  std::string account_manager = ManagementUIHandler::GetAccountManager(profile);
 
   int string_id = IDS_MANAGED_WITH_HYPERLINK;
 
   std::vector<base::string16> replacements;
   replacements.push_back(base::UTF8ToUTF16(chrome::kChromeUIManagementURL));
-  if (!management_domain.empty()) {
+  if (!account_manager.empty()) {
     string_id = IDS_MANAGED_BY_WITH_HYPERLINK;
-    replacements.push_back(base::UTF8ToUTF16(management_domain));
+    replacements.push_back(base::UTF8ToUTF16(account_manager));
   }
 
   return l10n_util::GetStringFUTF16(string_id, replacements, nullptr);
 }
 
 #if defined(OS_CHROMEOS)
-base::string16 GetDeviceManagedUiWebUILabel(Profile* profile) {
-  std::string management_domain =
-      ManagementUIHandler::GetAccountDomain(profile);
+base::string16 GetDeviceManagedUiWebUILabel() {
+  policy::BrowserPolicyConnectorChromeOS* connector =
+      g_browser_process->platform_part()->browser_policy_connector_chromeos();
+  const std::string device_manager =
+      connector->IsActiveDirectoryManaged()
+          ? connector->GetRealm()
+          : connector->GetEnterpriseDomainManager();
 
   int string_id = IDS_DEVICE_MANAGED_WITH_HYPERLINK;
 
   std::vector<base::string16> replacements;
   replacements.push_back(base::UTF8ToUTF16(chrome::kChromeUIManagementURL));
   replacements.push_back(ui::GetChromeOSDeviceName());
-  if (!management_domain.empty()) {
+  if (!device_manager.empty()) {
     string_id = IDS_DEVICE_MANAGED_BY_WITH_HYPERLINK;
-    replacements.push_back(base::UTF8ToUTF16(management_domain));
+    replacements.push_back(base::UTF8ToUTF16(device_manager));
   }
 
   return l10n_util::GetStringFUTF16(string_id, replacements, nullptr);
diff --git a/chrome/browser/ui/managed_ui.h b/chrome/browser/ui/managed_ui.h
index 7943559..f4a85cbd 100644
--- a/chrome/browser/ui/managed_ui.h
+++ b/chrome/browser/ui/managed_ui.h
@@ -33,7 +33,7 @@
 #if defined(OS_CHROMEOS)
 // The label for the WebUI footnote for Managed UI indicating that the device
 // is mananged. These strings contain HTML for an <a> element.
-base::string16 GetDeviceManagedUiWebUILabel(Profile* profile);
+base::string16 GetDeviceManagedUiWebUILabel();
 #endif
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/managed_ui_browsertest.cc b/chrome/browser/ui/managed_ui_browsertest.cc
index 5b2a80b5..dd6e188a 100644
--- a/chrome/browser/ui/managed_ui_browsertest.cc
+++ b/chrome/browser/ui/managed_ui_browsertest.cc
@@ -16,6 +16,10 @@
 #include "content/public/test/browser_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#endif
+
 class ManagedUiTest : public InProcessBrowserTest {
  public:
   ManagedUiTest() = default;
@@ -87,14 +91,14 @@
           "Your <a href=\"chrome://management\">browser is managed</a> by "
           "example.com"),
       chrome::GetManagedUiWebUILabel(profile_with_domain.get()));
+}
+
 #if defined(OS_CHROMEOS)
-  EXPECT_EQ(base::ASCIIToUTF16("Your <a target=\"_blank\" "
-                               "href=\"chrome://management\">Chrome device is "
-                               "managed</a> by your organization"),
-            chrome::GetDeviceManagedUiWebUILabel(profile.get()));
+using ManagedUiTestCros = policy::DevicePolicyCrosBrowserTest;
+IN_PROC_BROWSER_TEST_F(ManagedUiTestCros, GetManagedUiWebUILabel) {
   EXPECT_EQ(base::ASCIIToUTF16("Your <a target=\"_blank\" "
                                "href=\"chrome://management\">Chrome device is "
                                "managed</a> by example.com"),
-            chrome::GetDeviceManagedUiWebUILabel(profile_with_domain.get()));
-#endif
+            chrome::GetDeviceManagedUiWebUILabel());
 }
+#endif
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index 6c256b8..ac307fd5 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -67,7 +67,6 @@
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/policy/policy_constants.h"
 #include "components/prefs/pref_service.h"
-#include "components/version_info/version_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
@@ -1189,34 +1188,6 @@
 
 #endif  // !defined(OS_CHROMEOS)
 
-#if defined(OS_WIN)
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest,
-                       PRE_ShortcutsAreMigratedOnce) {
-  content::RunAllTasksUntilIdle();
-
-  // Confirm that shortcuts were migrated.
-  const std::string last_version_migrated =
-      g_browser_process->local_state()->GetString(
-          prefs::kShortcutMigrationVersion);
-  EXPECT_EQ(last_version_migrated, version_info::GetVersionNumber());
-
-  // Set the version back as far as kLastVersionNeedingMigration and ensure it's
-  // not migrated again.
-  g_browser_process->local_state()->SetString(prefs::kShortcutMigrationVersion,
-                                              "86.0.4231.0");
-}
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorTest, ShortcutsAreMigratedOnce) {
-  content::RunAllTasksUntilIdle();
-
-  // Confirm that shortcuts weren't migrated when marked as having last been
-  // migrated in kLastVersionNeedingMigration+.
-  const std::string last_version_migrated =
-      g_browser_process->local_state()->GetString(
-          prefs::kShortcutMigrationVersion);
-  EXPECT_EQ(last_version_migrated, "86.0.4231.0");
-}
-#endif  // defined(OS_WIN)
-
 class StartupBrowserCreatorExtensionsCheckupExperimentTest
     : public extensions::ExtensionBrowserTest {
  public:
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 393a018..87cd846 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -15,7 +15,6 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/values.h"
-#include "base/version.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
@@ -59,7 +58,6 @@
 #include "chrome/common/url_constants.h"
 #include "components/prefs/pref_service.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
-#include "components/version_info/version_info.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/dom_storage_context.h"
 #include "content/public/browser/storage_partition.h"
@@ -79,7 +77,6 @@
 #include "chrome/browser/win/conflicts/incompatible_applications_updater.h"
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #include "chrome/browser/notifications/notification_platform_bridge_win.h"
-#include "chrome/browser/shell_integration_win.h"
 #include "chrome/browser/ui/startup/credential_provider_signin_dialog_win.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #endif  // defined(OS_WIN)
@@ -297,32 +294,6 @@
       MaybeToggleFullscreen(browser);
   }
 
-#if defined(OS_WIN)
-  if (process_startup) {
-    // Update this number when users should go through a taskbar shortcut
-    // migration again. The last reason to do this was crrev.com/2285399 @
-    // 86.0.4231.0.
-    //
-    // Note: If shortcut updates need to be done once after a future OS upgrade,
-    // that should be done by re-versioning Active Setup (see //chrome/installer
-    // and http://crbug.com/577697 for details).
-    const base::Version kLastVersionNeedingMigration({86U, 0U, 4231U, 0U});
-
-    PrefService* local_state = g_browser_process->local_state();
-    if (local_state) {
-      const base::Version last_version_migrated(
-          local_state->GetString(prefs::kShortcutMigrationVersion));
-      if (!last_version_migrated.IsValid() ||
-          last_version_migrated < kLastVersionNeedingMigration) {
-        shell_integration::win::MigrateTaskbarPins(base::BindOnce(
-            &PrefService::SetString, base::Unretained(local_state),
-            prefs::kShortcutMigrationVersion,
-            version_info::GetVersionNumber()));
-      }
-    }
-  }
-#endif  // defined(OS_WIN)
-
   return true;
 }
 
diff --git a/chrome/browser/ui/task_manager/task_manager_columns.h b/chrome/browser/ui/task_manager/task_manager_columns.h
index 30c5669..833a9091 100644
--- a/chrome/browser/ui/task_manager/task_manager_columns.h
+++ b/chrome/browser/ui/task_manager/task_manager_columns.h
@@ -27,7 +27,7 @@
   float percent;
 
   // min and max widths used for Mac's implementation and are ignored on Views.
-  // If |max_width| is -1, it is unset.
+  // If |max_width| is -1, a value of 1.5 * |min_width| will be used.
   int min_width;
   int max_width;
 
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
index fae120b..ff0d6eea 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -1163,7 +1163,8 @@
     }
 
     scroll_view_ = new views::ScrollView();
-    scroll_view_->SetHideHorizontalScrollBar(true);
+    scroll_view_->SetHorizontalScrollBarMode(
+        views::ScrollView::ScrollBarMode::kDisabled);
     body_container_ = scroll_view_->SetContents(std::move(body_container));
     scroll_view_->SetDrawOverflowIndicator(false);
     scroll_view_->ClipHeightTo(0, body_container_->GetPreferredSize().height());
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc
index 98b4fe8..7da8f5a3 100644
--- a/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc
+++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_dialog_view.cc
@@ -160,7 +160,8 @@
   }
 
   auto card_list_scroll_view = std::make_unique<views::ScrollView>();
-  card_list_scroll_view->SetHideHorizontalScrollBar(true);
+  card_list_scroll_view->SetHorizontalScrollBarMode(
+      views::ScrollView::ScrollBarMode::kDisabled);
   card_list_scroll_view->SetContents(std::move(card_list_view));
   card_list_scroll_view->SetDrawOverflowIndicator(false);
   constexpr int kCardListScrollViewHeight = 140;
diff --git a/chrome/browser/ui/views/commander_frontend_views.cc b/chrome/browser/ui/views/commander_frontend_views.cc
index 7eac887..a832c6d 100644
--- a/chrome/browser/ui/views/commander_frontend_views.cc
+++ b/chrome/browser/ui/views/commander_frontend_views.cc
@@ -101,7 +101,7 @@
   web_view_->LoadInitialURL(GURL(chrome::kChromeUICommanderURL));
   CommanderUI* controller = static_cast<CommanderUI*>(
       web_view_->GetWebContents()->GetWebUI()->GetController());
-  controller->handler()->set_delegate(this);
+  controller->handler()->PrepareToShow(this);
 
   web_view_ptr_ = widget_->SetContentsView(std::move(web_view_));
 
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
index 7c2006a..33361e37 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -126,7 +126,8 @@
         screen_scroll_view->ClipHeightTo(
             kGenericScreenStyle.item_size.height(),
             kGenericScreenStyle.item_size.height() * 2);
-        screen_scroll_view->SetHideHorizontalScrollBar(true);
+        screen_scroll_view->SetHorizontalScrollBarMode(
+            views::ScrollView::ScrollBarMode::kDisabled);
 
         panes.push_back(
             std::make_pair(screen_title_text, std::move(screen_scroll_view)));
@@ -156,7 +157,8 @@
 
         window_scroll_view->ClipHeightTo(kWindowStyle.item_size.height(),
                                          kWindowStyle.item_size.height() * 2);
-        window_scroll_view->SetHideHorizontalScrollBar(true);
+        window_scroll_view->SetHorizontalScrollBarMode(
+            views::ScrollView::ScrollBarMode::kDisabled);
 
         panes.push_back(
             std::make_pair(window_title_text, std::move(window_scroll_view)));
diff --git a/chrome/browser/ui/views/extensions/extension_install_blocked_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_blocked_dialog_view.cc
index 6201252..2b97a6c 100644
--- a/chrome/browser/ui/views/extensions/extension_install_blocked_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_blocked_dialog_view.cc
@@ -121,7 +121,8 @@
   header_label->SizeToFit(content_width);
 
   auto* scroll_view = AddChildView(std::make_unique<views::ScrollView>());
-  scroll_view->SetHideHorizontalScrollBar(true);
+  scroll_view->SetHorizontalScrollBarMode(
+      views::ScrollView::ScrollBarMode::kDisabled);
   scroll_view->SetContents(std::move(extension_info_container));
   scroll_view->ClipHeightTo(
       0, provider->GetDistanceMetric(
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
index b8d244c1..081b19d 100644
--- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -520,7 +520,8 @@
   }
 
   scroll_view_ = new views::ScrollView();
-  scroll_view_->SetHideHorizontalScrollBar(true);
+  scroll_view_->SetHorizontalScrollBarMode(
+      views::ScrollView::ScrollBarMode::kDisabled);
   scroll_view_->SetContents(std::move(extension_info_container));
   scroll_view_->ClipHeightTo(
       0, provider->GetDistanceMetric(
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_view.cc
index 719846c..f9fcc3f 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view.cc
@@ -132,7 +132,8 @@
   auto scroll_view = std::make_unique<views::ScrollView>();
   scroll_view->ClipHeightTo(0, kMaxExtensionButtonsHeightDp);
   scroll_view->SetDrawOverflowIndicator(false);
-  scroll_view->SetHideHorizontalScrollBar(true);
+  scroll_view->SetHorizontalScrollBarMode(
+      views::ScrollView::ScrollBarMode::kDisabled);
   scroll_view->SetContents(std::move(extension_buttons));
   AddChildView(std::move(scroll_view));
 
diff --git a/chrome/browser/ui/views/frame/browser_root_view.cc b/chrome/browser/ui/views/frame/browser_root_view.cc
index f64e2a94..88fa7da 100644
--- a/chrome/browser/ui/views/frame/browser_root_view.cc
+++ b/chrome/browser/ui/views/frame/browser_root_view.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
@@ -259,7 +260,13 @@
 }
 
 bool BrowserRootView::OnMouseWheel(const ui::MouseWheelEvent& event) {
-  if (browser_defaults::kScrollEventChangesTab) {
+  // TODO(dfried): See if it's possible to move this logic deeper into the view
+  // hierarchy - ideally to TabStripRegionView.
+
+  // Scroll-event-changes-tab is incompatible with scrolling tabstrip, so
+  // disable it if the latter feature is enabled.
+  if (browser_defaults::kScrollEventChangesTab &&
+      !base::FeatureList::IsEnabled(features::kScrollableTabStrip)) {
     // Switch to the left/right tab if the wheel-scroll happens over the
     // tabstrip, or the empty space beside the tabstrip.
     views::View* hit_view = GetEventHandlerForPoint(event.location());
diff --git a/chrome/browser/ui/views/frame/tab_strip_region_view.cc b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
index 54dbdfa..0ca3c12c 100644
--- a/chrome/browser/ui/views/frame/tab_strip_region_view.cc
+++ b/chrome/browser/ui/views/frame/tab_strip_region_view.cc
@@ -31,7 +31,8 @@
         AddChildView(std::make_unique<views::ScrollView>(
             views::ScrollView::ScrollWithLayers::kEnabled));
     tab_strip_scroll_container->SetBackgroundColor(base::nullopt);
-    tab_strip_scroll_container->SetHideHorizontalScrollBar(true);
+    tab_strip_scroll_container->SetHorizontalScrollBarMode(
+        views::ScrollView::ScrollBarMode::kDisabled);
     tab_strip_container_ = tab_strip_scroll_container;
     tab_strip_scroll_container->SetContents(std::move(tab_strip));
   } else {
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
index a937b193..bd42178 100644
--- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
@@ -253,7 +253,8 @@
   scroll_ = layout->AddView(DisplayDynamicBorderForHiddenContents()
                                 ? std::make_unique<BorderedScrollView>()
                                 : std::make_unique<views::ScrollView>());
-  scroll_->SetHideHorizontalScrollBar(true);
+  scroll_->SetHorizontalScrollBarMode(
+      views::ScrollView::ScrollBarMode::kDisabled);
   pane_ = scroll_->SetContents(std::make_unique<views::View>());
   views::GridLayout* pane_layout =
       pane_->SetLayoutManager(std::make_unique<views::GridLayout>());
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
index bac3c572..0f950b7a 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
@@ -913,7 +913,8 @@
 
   // Create a scroll view to hold the components.
   auto scroll_view = std::make_unique<views::ScrollView>();
-  scroll_view->SetHideHorizontalScrollBar(true);
+  scroll_view->SetHorizontalScrollBarMode(
+      views::ScrollView::ScrollBarMode::kDisabled);
   // TODO(https://crbug.com/871762): it's a workaround for the crash.
   scroll_view->SetDrawOverflowIndicator(false);
   scroll_view->ClipHeightTo(0, GetMaxHeight());
diff --git a/chrome/browser/ui/views/supervised_user/parent_permission_dialog_view.cc b/chrome/browser/ui/views/supervised_user/parent_permission_dialog_view.cc
index fd9495e1..d66915d 100644
--- a/chrome/browser/ui/views/supervised_user/parent_permission_dialog_view.cc
+++ b/chrome/browser/ui/views/supervised_user/parent_permission_dialog_view.cc
@@ -460,7 +460,8 @@
 
     // Add section container to an enclosing scroll view.
     auto scroll_view = std::make_unique<views::ScrollView>();
-    scroll_view->SetHideHorizontalScrollBar(true);
+    scroll_view->SetHorizontalScrollBarMode(
+        views::ScrollView::ScrollBarMode::kDisabled);
     scroll_view->SetContents(std::move(install_permissions_section_container));
     scroll_view->ClipHeightTo(
         0, provider->GetDistanceMetric(
diff --git a/chrome/browser/ui/webui/commander/commander_handler.cc b/chrome/browser/ui/webui/commander/commander_handler.cc
index 6b6173e..c6932ad6 100644
--- a/chrome/browser/ui/webui/commander/commander_handler.cc
+++ b/chrome/browser/ui/webui/commander/commander_handler.cc
@@ -8,24 +8,42 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/commander/commander_view_model.h"
 
-const char CommanderHandler::Delegate::kKey[] =
-    "CommanderHandler::Delegate::kKey";
+namespace {
+// Message handler keys.
+constexpr char kTextChangedMessage[] = "textChanged";
+constexpr char kOptionSelectedMessage[] = "optionSelected";
+constexpr char kDismissMessage[] = "dismiss";
+constexpr char kHeightChangedMessage[] = "heightChanged";
+// WebUI event keys.
+constexpr char kViewModelUpdatedEvent[] = "view-model-updated";
+constexpr char kInitializeEvent[] = "initialize";
+// View model dictionary keys
+constexpr char kActionKey[] = "action";
+constexpr char kResultSetIdKey[] = "result_set_id";
+constexpr char kTitleKey[] = "title";
+constexpr char kEntityKey[] = "entity";
+constexpr char kAnnotationKey[] = "annotations";
+constexpr char kMatchedRangesKey[] = "matched_ranges";
+constexpr char kOptionsKey[] = "options";
+}  // namespace
+
 CommanderHandler::CommanderHandler() = default;
 CommanderHandler::~CommanderHandler() = default;
 
 void CommanderHandler::RegisterMessages() {
   web_ui()->RegisterMessageCallback(
-      "textChanged", base::BindRepeating(&CommanderHandler::HandleTextChanged,
-                                         base::Unretained(this)));
+      kTextChangedMessage,
+      base::BindRepeating(&CommanderHandler::HandleTextChanged,
+                          base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
-      "optionSelected",
+      kOptionSelectedMessage,
       base::BindRepeating(&CommanderHandler::HandleOptionSelected,
                           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
-      "dismiss", base::BindRepeating(&CommanderHandler::HandleDismiss,
-                                     base::Unretained(this)));
+      kDismissMessage, base::BindRepeating(&CommanderHandler::HandleDismiss,
+                                           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
-      "heightChanged",
+      kHeightChangedMessage,
       base::BindRepeating(&CommanderHandler::HandleHeightChanged,
                           base::Unretained(this)));
 }
@@ -73,17 +91,37 @@
     commander::CommanderViewModel view_model) {
   if (view_model.action ==
       commander::CommanderViewModel::Action::kDisplayResults) {
-    base::Value list(base::Value::Type::LIST);
+    base::DictionaryValue vm;
+    vm.SetIntKey(kActionKey, view_model.action);
+    vm.SetIntKey(kResultSetIdKey, view_model.result_set_id);
+    base::ListValue option_list;
     for (commander::CommandItemViewModel& item : view_model.items) {
-      // TODO(lgrey): This is temporary, just so we can display something.
-      // We will also need to pass on the result set id, and match ranges for
-      // each item.
-      list.Append(item.title);
+      base::DictionaryValue option;
+      option.SetStringKey(kTitleKey, item.title);
+      option.SetIntKey(kEntityKey, item.entity_type);
+      if (!item.annotation.empty())
+        option.SetStringKey(kAnnotationKey, item.annotation);
+      base::ListValue ranges;
+      for (const gfx::Range& range : item.matched_ranges) {
+        base::ListValue range_value;
+        range_value.Append(static_cast<int>(range.start()));
+        range_value.Append(static_cast<int>(range.end()));
+        ranges.Append(std::move(range_value));
+      }
+      option.SetKey(kMatchedRangesKey, std::move(ranges));
+      option_list.Append(std::move(option));
     }
-    FireWebUIListener("view-model-updated", list);
+    vm.SetKey(kOptionsKey, std::move(option_list));
+    FireWebUIListener(kViewModelUpdatedEvent, vm);
   } else {
     DCHECK_EQ(view_model.action,
               commander::CommanderViewModel::Action::kPrompt);
     // TODO(lgrey): Handle kPrompt. kDismiss is handled higher up the stack.
   }
 }
+
+void CommanderHandler::PrepareToShow(Delegate* delegate) {
+  delegate_ = delegate;
+  if (IsJavascriptAllowed())
+    FireWebUIListener(kInitializeEvent);
+}
diff --git a/chrome/browser/ui/webui/commander/commander_handler.h b/chrome/browser/ui/webui/commander/commander_handler.h
index ce89400..cfd70d8 100644
--- a/chrome/browser/ui/webui/commander/commander_handler.h
+++ b/chrome/browser/ui/webui/commander/commander_handler.h
@@ -17,9 +17,6 @@
   // browser-side commander system.
   class Delegate {
    public:
-    // The key under which the delegate is expected to be stashed in the
-    // containing web contents.
-    static const char kKey[];
     // Called when the text is changed in the WebUI interface.
     virtual void OnTextChanged(const base::string16& text) = 0;
     // Called when an option is selected (clicked or enter pressed) in the WebUI
@@ -39,7 +36,9 @@
   // Called when a new view model should be displayed.
   void ViewModelUpdated(commander::CommanderViewModel view_model);
 
-  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+  // Called to reinitialize the UI (clear input, remove results, etc.) and
+  // attach the delegate.
+  void PrepareToShow(Delegate* delegate);
 
   // WebUIMessageHandler overrides.
   void RegisterMessages() override;
diff --git a/chrome/browser/ui/webui/commander/commander_ui_browsertest.cc b/chrome/browser/ui/webui/commander/commander_ui_browsertest.cc
index 79922b9..275e082 100644
--- a/chrome/browser/ui/webui/commander/commander_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/commander/commander_ui_browsertest.cc
@@ -38,7 +38,7 @@
         ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
     CommanderUI* controller =
         static_cast<CommanderUI*>(contents_->GetWebUI()->GetController());
-    controller->handler()->set_delegate(this);
+    controller->handler()->PrepareToShow(this);
 
     ASSERT_TRUE(content::WaitForLoadStop(contents_.get()));
     EXPECT_EQ(contents_->GetLastCommittedURL().host(),
@@ -122,16 +122,47 @@
 TEST(CommanderHandlerTest, ViewModelPassed) {
   content::TestWebUI test_web_ui;
   auto handler = std::make_unique<TestCommanderHandler>(&test_web_ui);
+
   commander::CommanderViewModel vm;
   vm.action = commander::CommanderViewModel::Action::kDisplayResults;
   base::string16 item_title = base::ASCIIToUTF16("Test item");
-  std::vector<gfx::Range> item_ranges;
+  std::vector<gfx::Range> item_ranges = {gfx::Range(0, 4)};
   vm.items.emplace_back(item_title, item_ranges);
+  vm.result_set_id = 42;
+
   handler->AllowJavascriptForTesting();
   handler->ViewModelUpdated(std::move(vm));
   const content::TestWebUI::CallData& call_data =
       *test_web_ui.call_data().back();
   EXPECT_EQ("cr.webUIListenerCallback", call_data.function_name());
   EXPECT_EQ("view-model-updated", call_data.arg1()->GetString());
-  EXPECT_EQ("Test item", call_data.arg2()->GetList()[0].GetString());
+
+  const base::Value* arg = call_data.arg2();
+  EXPECT_EQ(
+      "Test item",
+      arg->FindPath("options")->GetList()[0].FindPath("title")->GetString());
+  EXPECT_EQ(0, arg->FindPath("options")
+                   ->GetList()[0]
+                   .FindPath("matched_ranges")
+                   ->GetList()[0]
+                   .GetList()[0]
+                   .GetInt());
+  EXPECT_EQ(4, arg->FindPath("options")
+                   ->GetList()[0]
+                   .FindPath("matched_ranges")
+                   ->GetList()[0]
+                   .GetList()[1]
+                   .GetInt());
+  EXPECT_EQ(42, arg->FindPath("result_set_id")->GetInt());
+}
+
+TEST(CommanderHandlerTest, Initialize) {
+  content::TestWebUI test_web_ui;
+  auto handler = std::make_unique<TestCommanderHandler>(&test_web_ui);
+  handler->AllowJavascriptForTesting();
+  handler->PrepareToShow(nullptr);
+  const content::TestWebUI::CallData& call_data =
+      *test_web_ui.call_data().back();
+  EXPECT_EQ("cr.webUIListenerCallback", call_data.function_name());
+  EXPECT_EQ("initialize", call_data.arg1()->GetString());
 }
diff --git a/chrome/browser/ui/webui/managed_ui_handler.cc b/chrome/browser/ui/webui/managed_ui_handler.cc
index 3d4e6125b..cee8309 100644
--- a/chrome/browser/ui/webui/managed_ui_handler.cc
+++ b/chrome/browser/ui/webui/managed_ui_handler.cc
@@ -114,7 +114,7 @@
                  base::Value(chrome::GetManagedUiWebUILabel(profile_)));
 #if defined(OS_CHROMEOS)
   update->SetKey("deviceManagedByOrg",
-                 base::Value(chrome::GetDeviceManagedUiWebUILabel(profile_)));
+                 base::Value(chrome::GetDeviceManagedUiWebUILabel()));
 #endif
   update->SetKey("isManaged", base::Value(managed_));
   return update;
diff --git a/chrome/browser/ui/webui/management_ui.cc b/chrome/browser/ui/webui/management_ui.cc
index c3214cf..7db259e 100644
--- a/chrome/browser/ui/webui/management_ui.cc
+++ b/chrome/browser/ui/webui/management_ui.cc
@@ -171,32 +171,32 @@
                                       l10n_util::GetStringUTF16(device_type));
   }
 
-  std::string display_domain = connector->GetEnterpriseDisplayDomain();
+  std::string account_manager = connector->GetEnterpriseDomainManager();
 
-  if (display_domain.empty())
-    display_domain = connector->GetRealm();
-  if (display_domain.empty())
-    display_domain = ManagementUIHandler::GetAccountDomain(profile);
-  if (display_domain.empty()) {
+  if (account_manager.empty())
+    account_manager = connector->GetRealm();
+  if (account_manager.empty())
+    account_manager = ManagementUIHandler::GetAccountManager(profile);
+  if (account_manager.empty()) {
     return l10n_util::GetStringFUTF16(IDS_MANAGEMENT_SUBTITLE_MANAGED,
                                       l10n_util::GetStringUTF16(device_type));
   }
   return l10n_util::GetStringFUTF16(IDS_MANAGEMENT_SUBTITLE_MANAGED_BY,
                                     l10n_util::GetStringUTF16(device_type),
-                                    base::UTF8ToUTF16(display_domain));
+                                    base::UTF8ToUTF16(account_manager));
 #else   // defined(OS_CHROMEOS)
-  const auto management_domain = ManagementUIHandler::GetAccountDomain(profile);
+  const auto account_manager = ManagementUIHandler::GetAccountManager(profile);
   const auto managed =
       profile->GetProfilePolicyConnector()->IsManaged() ||
       g_browser_process->browser_policy_connector()->HasMachineLevelPolicies();
-  if (management_domain.empty()) {
+  if (account_manager.empty()) {
     return l10n_util::GetStringUTF16(managed
                                          ? IDS_MANAGEMENT_SUBTITLE
                                          : IDS_MANAGEMENT_NOT_MANAGED_SUBTITLE);
   }
   if (managed) {
     return l10n_util::GetStringFUTF16(IDS_MANAGEMENT_SUBTITLE_MANAGED_BY,
-                                      base::UTF8ToUTF16(management_domain));
+                                      base::UTF8ToUTF16(account_manager));
   }
   return l10n_util::GetStringUTF16(IDS_MANAGEMENT_NOT_MANAGED_SUBTITLE);
 #endif  // defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/management_ui_handler.cc b/chrome/browser/ui/webui/management_ui_handler.cc
index bb23c5a..7add4bb 100644
--- a/chrome/browser/ui/webui/management_ui_handler.cc
+++ b/chrome/browser/ui/webui/management_ui_handler.cc
@@ -325,9 +325,7 @@
 
 }  // namespace
 
-// TODO(raleksandov) Move to util class or smth similar.
-// static
-std::string ManagementUIHandler::GetAccountDomain(Profile* profile) {
+std::string GetAccountDomain(Profile* profile) {
   if (!IsProfileManaged(profile))
     return std::string();
   auto username = profile->GetProfileUserName();
@@ -652,7 +650,7 @@
   response->SetStringPath(
       "eolMessage",
       l10n_util::GetStringFUTF16(IDS_MANAGEMENT_UPDATE_REQUIRED_EOL_MESSAGE,
-                                 base::UTF8ToUTF16(GetDeviceDomain()),
+                                 base::UTF8ToUTF16(GetDeviceManager()),
                                  ui::GetChromeOSDeviceName()));
   std::string eol_admin_message;
   chromeos::CrosSettings::Get()->GetString(
@@ -694,13 +692,13 @@
 base::Value ManagementUIHandler::GetContextualManagedData(Profile* profile) {
   base::Value response(base::Value::Type::DICTIONARY);
 #if defined(OS_CHROMEOS)
-  std::string management_domain = GetDeviceDomain();
-  if (management_domain.empty())
-    management_domain = GetAccountDomain(profile);
+  std::string enterprise_manager = GetDeviceManager();
+  if (enterprise_manager.empty())
+    enterprise_manager = GetAccountManager(profile);
   AddUpdateRequiredEolInfo(&response);
   AddProxyServerPrivacyDisclosure(&response);
 #else
-  std::string management_domain = GetAccountDomain(profile);
+  std::string enterprise_manager = GetAccountManager(profile);
 
   response.SetStringPath(
       "browserManagementNotice",
@@ -710,7 +708,7 @@
           base::UTF8ToUTF16(chrome::kManagedUiLearnMoreUrl)));
 #endif
 
-  if (management_domain.empty()) {
+  if (enterprise_manager.empty()) {
     response.SetStringPath(
         "extensionReportingTitle",
         l10n_util::GetStringUTF16(IDS_MANAGEMENT_EXTENSIONS_INSTALLED));
@@ -736,14 +734,14 @@
     response.SetStringPath(
         "extensionReportingTitle",
         l10n_util::GetStringFUTF16(IDS_MANAGEMENT_EXTENSIONS_INSTALLED_BY,
-                                   base::UTF8ToUTF16(management_domain)));
+                                   base::UTF8ToUTF16(enterprise_manager)));
 
 #if !defined(OS_CHROMEOS)
     response.SetStringPath(
         "pageSubtitle",
         managed_()
             ? l10n_util::GetStringFUTF16(IDS_MANAGEMENT_SUBTITLE_MANAGED_BY,
-                                         base::UTF8ToUTF16(management_domain))
+                                         base::UTF8ToUTF16(enterprise_manager))
             : l10n_util::GetStringUTF16(IDS_MANAGEMENT_NOT_MANAGED_SUBTITLE));
 #else
     const auto device_type = ui::GetChromeOSDeviceTypeResourceId();
@@ -752,7 +750,7 @@
         managed_()
             ? l10n_util::GetStringFUTF16(IDS_MANAGEMENT_SUBTITLE_MANAGED_BY,
                                          l10n_util::GetStringUTF16(device_type),
-                                         base::UTF8ToUTF16(management_domain))
+                                         base::UTF8ToUTF16(enterprise_manager))
             : l10n_util::GetStringFUTF16(
                   IDS_MANAGEMENT_NOT_MANAGED_SUBTITLE,
                   l10n_util::GetStringUTF16(device_type)));
@@ -825,21 +823,21 @@
   }
 
 #if defined(OS_CHROMEOS)
-  std::string management_domain = GetDeviceDomain();
-  if (management_domain.empty())
-    management_domain = GetAccountDomain(profile);
+  std::string enterprise_manager = GetDeviceManager();
+  if (enterprise_manager.empty())
+    enterprise_manager = GetAccountManager(profile);
 #else
-  std::string management_domain = GetAccountDomain(profile);
+  std::string enterprise_manager = GetAccountManager(profile);
 #endif  // defined(OS_CHROMEOS)
 
   base::Value result(base::Value::Type::DICTIONARY);
   result.SetStringKey("description",
-                      management_domain.empty()
+                      enterprise_manager.empty()
                           ? l10n_util::GetStringUTF16(
                                 IDS_MANAGEMENT_THREAT_PROTECTION_DESCRIPTION)
                           : l10n_util::GetStringFUTF16(
                                 IDS_MANAGEMENT_THREAT_PROTECTION_DESCRIPTION_BY,
-                                base::UTF8ToUTF16(management_domain)));
+                                base::UTF8ToUTF16(enterprise_manager)));
   result.SetKey("info", std::move(info));
   return result;
 }
@@ -891,39 +889,39 @@
     base::Value* status,
     bool device_managed,
     bool account_managed,
-    const std::string& device_domain,
-    const std::string& account_domain) {
+    const std::string& device_manager,
+    const std::string& account_manager) {
   if (device_managed && account_managed &&
-      (account_domain.empty() || account_domain == device_domain)) {
+      (account_manager.empty() || account_manager == device_manager)) {
     status->SetKey(kOverview, base::Value(l10n_util::GetStringFUTF16(
                                   IDS_MANAGEMENT_DEVICE_AND_ACCOUNT_MANAGED_BY,
-                                  base::UTF8ToUTF16(device_domain))));
+                                  base::UTF8ToUTF16(device_manager))));
 
     return;
   }
 
-  if (account_managed && !account_domain.empty()) {
+  if (account_managed && !account_manager.empty()) {
     status->SetKey(kOverview, base::Value(l10n_util::GetStringFUTF16(
                                   IDS_MANAGEMENT_ACCOUNT_MANAGED_BY,
-                                  base::UTF8ToUTF16(account_domain))));
+                                  base::UTF8ToUTF16(account_manager))));
   }
 
-  if (account_managed && device_managed && !account_domain.empty() &&
-      account_domain != device_domain) {
+  if (account_managed && device_managed && !account_manager.empty() &&
+      account_manager != device_manager) {
     status->SetKey(kOverview,
                    base::Value(l10n_util::GetStringFUTF16(
                        IDS_MANAGEMENT_DEVICE_MANAGED_BY_ACCOUNT_MANAGED_BY,
-                       base::UTF8ToUTF16(device_domain),
-                       base::UTF8ToUTF16(account_domain))));
+                       base::UTF8ToUTF16(device_manager),
+                       base::UTF8ToUTF16(account_manager))));
   }
 }
 
-const std::string ManagementUIHandler::GetDeviceDomain() const {
+const std::string ManagementUIHandler::GetDeviceManager() const {
   std::string device_domain;
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   if (device_managed_)
-    device_domain = connector->GetEnterpriseDisplayDomain();
+    device_domain = connector->GetEnterpriseDomainManager();
   if (device_domain.empty() && connector->IsActiveDirectoryManaged())
     device_domain = connector->GetRealm();
   return device_domain;
@@ -942,7 +940,7 @@
                                   IDS_MANAGEMENT_DEVICE_NOT_MANAGED)));
     return;
   }
-  std::string account_domain = GetAccountDomain(profile);
+  std::string account_manager = GetAccountManager(profile);
   auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
   auto* primary_profile =
       primary_user
@@ -952,13 +950,13 @@
       primary_profile ? IsProfileManaged(primary_profile) : false;
 
   if (primary_user_managed)
-    account_domain = GetAccountDomain(primary_profile);
+    account_manager = GetAccountManager(primary_profile);
 
-  std::string device_domain = GetDeviceDomain();
+  std::string device_manager = GetDeviceManager();
 
   AddStatusOverviewManagedDeviceAndAccount(
       status, device_managed_, account_managed_ || primary_user_managed,
-      device_domain, account_domain);
+      device_manager, account_manager);
 #endif  // defined(OS_CHROMEOS)
 }
 
diff --git a/chrome/browser/ui/webui/management_ui_handler.h b/chrome/browser/ui/webui/management_ui_handler.h
index d45c33d..67baebf 100644
--- a/chrome/browser/ui/webui/management_ui_handler.h
+++ b/chrome/browser/ui/webui/management_ui_handler.h
@@ -120,10 +120,6 @@
   void SetAccountManagedForTesting(bool managed) { account_managed_ = managed; }
   void SetDeviceManagedForTesting(bool managed) { device_managed_ = managed; }
 
-  // This will return the domain (ie foo.com) that manages |profile|. If
-  // unmanaged, an empty string is returned.
-  static std::string GetAccountDomain(Profile* profile);
-
   // This returns the entity that manages this |profile|. For standard dasher
   // domains, this will be a domain name (ie foo.com). For FlexOrgs, this will
   // be the email address of the admin of the FlexOrg (ie user@foo.com). If
@@ -149,7 +145,7 @@
 
 #if defined(OS_CHROMEOS)
   // Protected for testing.
-  virtual const std::string GetDeviceDomain() const;
+  virtual const std::string GetDeviceManager() const;
   virtual const policy::DeviceCloudPolicyManagerChromeOS*
   GetDeviceCloudPolicyManager() const;
   void AddDeviceReportingInfo(base::Value* report_sources,
diff --git a/chrome/browser/ui/webui/management_ui_handler_unittest.cc b/chrome/browser/ui/webui/management_ui_handler_unittest.cc
index a5f0f1bf..e75c078 100644
--- a/chrome/browser/ui/webui/management_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/management_ui_handler_unittest.cc
@@ -239,7 +239,7 @@
     return report_sources;
   }
 
-  const std::string GetDeviceDomain() const override { return device_domain; }
+  const std::string GetDeviceManager() const override { return device_domain; }
   void SetDeviceDomain(const std::string& domain) { device_domain = domain; }
 #endif  // defined(OS_CHROMEOS)
 
@@ -1270,20 +1270,6 @@
   EXPECT_EQ(expected_info, *threat_protection_info->FindListKey("info"));
 }
 
-TEST_F(ManagementUIHandlerTests, GetAccountDomain) {
-  TestingProfile::Builder builder_unmanaged_user;
-  builder_unmanaged_user.SetProfileName(kUser);
-  builder_unmanaged_user.OverridePolicyConnectorIsManagedForTesting(false);
-  auto unmanaged_user = builder_unmanaged_user.Build();
-  EXPECT_EQ("", handler_.GetAccountDomain(unmanaged_user.get()));
-
-  TestingProfile::Builder builder_managed_user;
-  builder_managed_user.SetProfileName(kUser);
-  builder_managed_user.OverridePolicyConnectorIsManagedForTesting(true);
-  auto managed_user = builder_managed_user.Build();
-  EXPECT_EQ(kDomain, handler_.GetAccountDomain(managed_user.get()));
-}
-
 TEST_F(ManagementUIHandlerTests, GetAccountManager) {
   TestingProfile::Builder builder_managed_user;
   builder_managed_user.SetProfileName(kUser);
diff --git a/chrome/browser/uid/OWNERS b/chrome/browser/uid/OWNERS
new file mode 100644
index 0000000..354d5ae
--- /dev/null
+++ b/chrome/browser/uid/OWNERS
@@ -0,0 +1,4 @@
+file://components/signin/OWNERS
+
+# TEAM: chrome-signin@chromium.org
+# COMPONENT: Services>SignIn
diff --git a/chrome/browser/uid/android/BUILD.gn b/chrome/browser/uid/android/BUILD.gn
new file mode 100644
index 0000000..632c1fc
--- /dev/null
+++ b/chrome/browser/uid/android/BUILD.gn
@@ -0,0 +1,41 @@
+# Copyright 2020 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("//build/config/android/rules.gni")
+
+android_library("java") {
+  sources = [
+    "java/src/org/chromium/chrome/browser/uid/SettingsSecureBasedIdentificationGenerator.java",
+    "java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGenerator.java",
+    "java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactory.java",
+    "java/src/org/chromium/chrome/browser/uid/UuidBasedUniqueIdentificationGenerator.java",
+  ]
+  deps = [
+    "//chrome/browser/preferences:java",
+    "//chrome/browser/util:java",
+    "//third_party/android_deps:androidx_annotation_annotation_java",
+  ]
+}
+
+android_library("javatests") {
+  testonly = true
+  sources = [
+    "javatests/src/org/chromium/chrome/browser/uid/SettingsSecureBasedIdentificationGeneratorTest.java",
+    "javatests/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactoryTest.java",
+    "javatests/src/org/chromium/chrome/browser/uid/UuidBasedUniqueIdentificationGeneratorTest.java",
+  ]
+  deps = [
+    ":java",
+    "//base:base_java",
+    "//base:base_java_test_support",
+    "//base/test:test_support_java",
+    "//chrome/browser/preferences:java",
+    "//chrome/browser/util:java",
+    "//chrome/test/android:chrome_java_test_support",
+    "//third_party/android_deps:androidx_annotation_annotation_java",
+    "//third_party/android_deps:androidx_test_runner_java",
+    "//third_party/android_support_test_runner:runner_java",
+    "//third_party/junit:junit",
+  ]
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/identity/SettingsSecureBasedIdentificationGenerator.java b/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/SettingsSecureBasedIdentificationGenerator.java
similarity index 90%
rename from chrome/android/java/src/org/chromium/chrome/browser/identity/SettingsSecureBasedIdentificationGenerator.java
rename to chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/SettingsSecureBasedIdentificationGenerator.java
index 6b932ee..83cfa14 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/identity/SettingsSecureBasedIdentificationGenerator.java
+++ b/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/SettingsSecureBasedIdentificationGenerator.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.identity;
+package org.chromium.chrome.browser.uid;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
@@ -35,8 +35,7 @@
             return "";
         }
 
-        String md5Hash = HashUtil.getMd5Hash(
-                new HashUtil.Params(androidId).withSalt(salt));
+        String md5Hash = HashUtil.getMd5Hash(new HashUtil.Params(androidId).withSalt(salt));
         return md5Hash == null ? "" : md5Hash;
     }
 
diff --git a/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGenerator.java b/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGenerator.java
new file mode 100644
index 0000000..866d2c6c
--- /dev/null
+++ b/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGenerator.java
@@ -0,0 +1,23 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.uid;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Interface used for uniquely identifying an installation of Chrome. To get an instance you should
+ * use {@link UniqueIdentificationGeneratorFactory}.
+ */
+public interface UniqueIdentificationGenerator {
+    /**
+     * Creates a string that uniquely identifies this installation.
+     * <p/>
+     * If there is an error in generating the string, an empty string must be returned, not null.
+     *
+     * @param salt the salt to use for the unique ID.
+     * @return a unique ID. On failure to generate, it must return the empty string.
+     */
+    String getUniqueId(@Nullable String salt);
+}
diff --git a/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactory.java b/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactory.java
new file mode 100644
index 0000000..a175042
--- /dev/null
+++ b/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactory.java
@@ -0,0 +1,67 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.uid;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Factory for setting and retrieving instances of {@link UniqueIdentificationGenerator}s.
+ * <p/>
+ * A generator must always be set for a generator type before it is asked for. A generator type
+ * is any string you want to use for your generator. It is typically defined as a public static
+ * field in the generator itself.
+ */
+public final class UniqueIdentificationGeneratorFactory {
+    private static final Object LOCK = new Object();
+    private static final Map<String, UniqueIdentificationGenerator> GENERATOR_MAP =
+            new HashMap<String, UniqueIdentificationGenerator>();
+
+    private UniqueIdentificationGeneratorFactory() {}
+
+    /**
+     * Returns a UniqueIdentificationGenerator if it exists, else throws IllegalArgumentException.
+     *
+     * @param generatorType the generator type you want
+     * @return a unique ID generator
+     */
+    public static UniqueIdentificationGenerator getInstance(String generatorType) {
+        synchronized (LOCK) {
+            if (!GENERATOR_MAP.containsKey(generatorType)) {
+                throw new IllegalArgumentException("Unknown generator type " + generatorType);
+            }
+            return GENERATOR_MAP.get(generatorType);
+        }
+    }
+
+    /**
+     * During startup of the application, and before any calls to
+     * {@link #getInstance(String)} you must add all supported generators
+     * to this factory.
+     *
+     * @param generatorType the type of generator this is. Must be a unique string.
+     * @param gen           the generator.
+     * @param force         if set to true, will override any existing generator for this type. Else
+     *                      discards calls where a generator exists.
+     */
+    public static void registerGenerator(
+            String generatorType, UniqueIdentificationGenerator gen, boolean force) {
+        synchronized (LOCK) {
+            if (GENERATOR_MAP.containsKey(generatorType) && !force) {
+                return;
+            }
+            GENERATOR_MAP.put(generatorType, gen);
+        }
+    }
+
+    @VisibleForTesting
+    public static void clearGeneratorMapForTest() {
+        synchronized (LOCK) {
+            GENERATOR_MAP.clear();
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGenerator.java b/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UuidBasedUniqueIdentificationGenerator.java
similarity index 96%
rename from chrome/android/java/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGenerator.java
rename to chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UuidBasedUniqueIdentificationGenerator.java
index f0039d8..aed9cdb2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGenerator.java
+++ b/chrome/browser/uid/android/java/src/org/chromium/chrome/browser/uid/UuidBasedUniqueIdentificationGenerator.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.identity;
+package org.chromium.chrome.browser.uid;
 
 import android.content.Context;
 
@@ -40,7 +40,6 @@
         // Store the field so we ensure we always return the same unique ID.
         preferences.writeString(mPreferenceKey, uniqueId);
         return uniqueId;
-
     }
 
     @VisibleForTesting
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/identity/SettingsSecureBasedIdentificationGeneratorTest.java b/chrome/browser/uid/android/javatests/src/org/chromium/chrome/browser/uid/SettingsSecureBasedIdentificationGeneratorTest.java
similarity index 95%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/identity/SettingsSecureBasedIdentificationGeneratorTest.java
rename to chrome/browser/uid/android/javatests/src/org/chromium/chrome/browser/uid/SettingsSecureBasedIdentificationGeneratorTest.java
index c2be4e3..45ac7caf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/identity/SettingsSecureBasedIdentificationGeneratorTest.java
+++ b/chrome/browser/uid/android/javatests/src/org/chromium/chrome/browser/uid/SettingsSecureBasedIdentificationGeneratorTest.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.identity;
+package org.chromium.chrome.browser.uid;
 
 import androidx.test.filters.SmallTest;
 
@@ -15,6 +15,7 @@
 import org.chromium.chrome.browser.util.HashUtil;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 
+/** Unit tests for {@link SettingsSecureBasedIdentificationGenerator}. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 public class SettingsSecureBasedIdentificationGeneratorTest {
     private static final String FLAG_ANDROID_ID = "android_id";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactoryTest.java b/chrome/browser/uid/android/javatests/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactoryTest.java
similarity index 95%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactoryTest.java
rename to chrome/browser/uid/android/javatests/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactoryTest.java
index 1a33622..609d9f9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/identity/UniqueIdentificationGeneratorFactoryTest.java
+++ b/chrome/browser/uid/android/javatests/src/org/chromium/chrome/browser/uid/UniqueIdentificationGeneratorFactoryTest.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.identity;
+package org.chromium.chrome.browser.uid;
 
 import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
@@ -14,6 +14,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 
+/** Unit tests for {@link UniqueIdentificationGeneratorFactory}. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 public class UniqueIdentificationGeneratorFactoryTest {
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGeneratorTest.java b/chrome/browser/uid/android/javatests/src/org/chromium/chrome/browser/uid/UuidBasedUniqueIdentificationGeneratorTest.java
similarity index 96%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGeneratorTest.java
rename to chrome/browser/uid/android/javatests/src/org/chromium/chrome/browser/uid/UuidBasedUniqueIdentificationGeneratorTest.java
index c230beae..492e6fc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGeneratorTest.java
+++ b/chrome/browser/uid/android/javatests/src/org/chromium/chrome/browser/uid/UuidBasedUniqueIdentificationGeneratorTest.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.identity;
+package org.chromium.chrome.browser.uid;
 
 import android.support.test.InstrumentationRegistry;
 
@@ -18,6 +18,7 @@
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 
+/** Unit tests for {@link UuidBasedUniqueIdentificationGenerator}. */
 @RunWith(ChromeJUnit4ClassRunner.class)
 public class UuidBasedUniqueIdentificationGeneratorTest {
     private static final String FLAG_UUID = "uuid";
diff --git a/chrome/common/profiler/thread_profiler_platform_configuration.cc b/chrome/common/profiler/thread_profiler_platform_configuration.cc
index d37ae07c..35e6d35 100644
--- a/chrome/common/profiler/thread_profiler_platform_configuration.cc
+++ b/chrome/common/profiler/thread_profiler_platform_configuration.cc
@@ -192,13 +192,6 @@
   if (browser_test_mode_enabled())
     return DefaultPlatformConfiguration::GetChildProcessEnableFraction(process);
 
-  // Enable just on renderer process for now. Enabling for 40% of renderer
-  // processes samples roughly one renderer process on average for every Chrome
-  // execution, based on early channel data in the
-  // Memory.RenderProcessHost.Count.InitializedAndNotDead histogram.
-  if (process == metrics::CallStackProfileParams::RENDERER_PROCESS)
-    return 0.4;
-
   // TODO(https://crbug.com/1004855): Enable for all the default processes.
   return 0.0;
 }
@@ -206,23 +199,15 @@
 bool AndroidPlatformConfiguration::IsEnabledForThread(
     metrics::CallStackProfileParams::Process process,
     metrics::CallStackProfileParams::Thread thread) const {
-  // Enable on renderer process main thread in production, for now.
-  if (process == metrics::CallStackProfileParams::RENDERER_PROCESS &&
-      thread == metrics::CallStackProfileParams::MAIN_THREAD) {
-    return true;
-  }
-
-  // Otherwise enable in dedicated ThreadProfiler browser tests.
+  // Disable for all supported threads pending launch. Enable only for browser
+  // tests.
   return browser_test_mode_enabled();
 }
 
 bool AndroidPlatformConfiguration::IsSupportedForChannel(
     base::Optional<version_info::Channel> release_channel) const {
-  // Enable on canary, for now.
-  if (release_channel && *release_channel == version_info::Channel::CANARY)
-    return true;
-
-  // Otherwise enable in dedicated ThreadProfiler browser tests.
+  // On Android profiling is only enabled in its own dedicated browser tests
+  // in local builds and the CQ.
   // TODO(https://crbug.com/1004855): Enable across all browser tests.
   return browser_test_mode_enabled();
 }
diff --git a/chrome/common/profiler/thread_profiler_platform_configuration_unittest.cc b/chrome/common/profiler/thread_profiler_platform_configuration_unittest.cc
index f741215..5e51a51 100644
--- a/chrome/common/profiler/thread_profiler_platform_configuration_unittest.cc
+++ b/chrome/common/profiler/thread_profiler_platform_configuration_unittest.cc
@@ -72,7 +72,7 @@
   EXPECT_FALSE(config()->IsSupported(base::nullopt));
 #elif defined(OS_ANDROID)
   EXPECT_FALSE(config()->IsSupported(version_info::Channel::UNKNOWN));
-  EXPECT_TRUE(config()->IsSupported(version_info::Channel::CANARY));
+  EXPECT_FALSE(config()->IsSupported(version_info::Channel::CANARY));
   EXPECT_FALSE(config()->IsSupported(version_info::Channel::DEV));
   EXPECT_FALSE(config()->IsSupported(version_info::Channel::BETA));
   EXPECT_FALSE(config()->IsSupported(version_info::Channel::STABLE));
@@ -126,15 +126,14 @@
 
 MAYBE_PLATFORM_CONFIG_TEST_F(ThreadProfilerPlatformConfigurationTest,
                              GetEnableRates) {
+  // Note: death tests aren't supported on Android. Otherwise this test would
+  // check that all inputs result in CHECKs.
+#if !defined(OS_ANDROID)
   using RelativePopulations =
       ThreadProfilerPlatformConfiguration::RelativePopulations;
+  EXPECT_CHECK_DEATH(config()->GetEnableRates(version_info::Channel::UNKNOWN));
   EXPECT_EQ((RelativePopulations{80, 20}),
             config()->GetEnableRates(version_info::Channel::CANARY));
-#if defined(OS_ANDROID)
-  // Note: death tests aren't supported on Android. Otherwise this test would
-  // check that the other inputs result in CHECKs.
-#else
-  EXPECT_CHECK_DEATH(config()->GetEnableRates(version_info::Channel::UNKNOWN));
   EXPECT_EQ((RelativePopulations{80, 20}),
             config()->GetEnableRates(version_info::Channel::DEV));
   EXPECT_CHECK_DEATH(config()->GetEnableRates(version_info::Channel::BETA));
@@ -150,7 +149,7 @@
 #if defined(OS_ANDROID)
   EXPECT_EQ(0.0, config()->GetChildProcessEnableFraction(
                      metrics::CallStackProfileParams::GPU_PROCESS));
-  EXPECT_EQ(0.4, config()->GetChildProcessEnableFraction(
+  EXPECT_EQ(0.0, config()->GetChildProcessEnableFraction(
                      metrics::CallStackProfileParams::RENDERER_PROCESS));
   EXPECT_EQ(0.0, config()->GetChildProcessEnableFraction(
                      metrics::CallStackProfileParams::NETWORK_SERVICE_PROCESS));
@@ -192,7 +191,7 @@
       metrics::CallStackProfileParams::GPU_PROCESS,
       metrics::CallStackProfileParams::COMPOSITOR_THREAD));
 
-  EXPECT_TRUE(config()->IsEnabledForThread(
+  EXPECT_FALSE(config()->IsEnabledForThread(
       metrics::CallStackProfileParams::RENDERER_PROCESS,
       metrics::CallStackProfileParams::MAIN_THREAD));
   EXPECT_FALSE(config()->IsEnabledForThread(
diff --git a/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc b/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc
index d590cde..fe9f2be 100644
--- a/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc
+++ b/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc
@@ -16,28 +16,12 @@
     content::RendererPpapiHost* host,
     PP_Instance instance,
     PP_Resource resource)
-    : ResourceHost(host->GetPpapiHost(), instance, resource),
-      renderer_ppapi_host_(host) {}
+    : ResourceHost(host->GetPpapiHost(), instance, resource) {}
 
 PepperFlashFullscreenHost::~PepperFlashFullscreenHost() {}
 
 int32_t PepperFlashFullscreenHost::OnResourceMessageReceived(
     const IPC::Message& msg,
     ppapi::host::HostMessageContext* context) {
-  PPAPI_BEGIN_MESSAGE_MAP(PepperFlashFullscreenHost, msg)
-    PPAPI_DISPATCH_HOST_RESOURCE_CALL(
-      PpapiHostMsg_FlashFullscreen_SetFullscreen,
-      OnSetFullscreen)
-  PPAPI_END_MESSAGE_MAP()
-  return PP_ERROR_FAILED;
-}
-
-int32_t PepperFlashFullscreenHost::OnSetFullscreen(
-    ppapi::host::HostMessageContext* context,
-    bool fullscreen) {
-  content::PepperPluginInstance* plugin_instance =
-      renderer_ppapi_host_->GetPluginInstance(pp_instance());
-  if (plugin_instance && plugin_instance->FlashSetFullscreen(fullscreen, true))
-    return PP_OK;
   return PP_ERROR_FAILED;
 }
diff --git a/chrome/renderer/pepper/pepper_flash_fullscreen_host.h b/chrome/renderer/pepper/pepper_flash_fullscreen_host.h
index 1cd5b39..867cea7 100644
--- a/chrome/renderer/pepper/pepper_flash_fullscreen_host.h
+++ b/chrome/renderer/pepper/pepper_flash_fullscreen_host.h
@@ -27,12 +27,6 @@
       ppapi::host::HostMessageContext* context) override;
 
  private:
-  int32_t OnSetFullscreen(ppapi::host::HostMessageContext* context,
-                          bool fullscreen);
-
-  // Non-owning pointer.
-  content::RendererPpapiHost* renderer_ppapi_host_;
-
   DISALLOW_COPY_AND_ASSIGN(PepperFlashFullscreenHost);
 };
 
diff --git a/chrome/services/sharing/nearby/nearby_connections.cc b/chrome/services/sharing/nearby/nearby_connections.cc
index 0007c57..e644842 100644
--- a/chrome/services/sharing/nearby/nearby_connections.cc
+++ b/chrome/services/sharing/nearby/nearby_connections.cc
@@ -185,7 +185,9 @@
     mojo::PendingRemote<mojom::EndpointDiscoveryListener> listener,
     StartDiscoveryCallback callback) {
   ConnectionOptions connection_options{
-      .strategy = StrategyFromMojom(options->strategy)};
+      .strategy = StrategyFromMojom(options->strategy),
+      .fast_advertisement_service_uuid =
+          options->fast_advertisement_service_uuid.canonical_value()};
   mojo::SharedRemote<mojom::EndpointDiscoveryListener> remote(
       std::move(listener));
   DiscoveryListener discovery_listener{
diff --git a/chrome/services/sharing/nearby/nearby_connections_unittest.cc b/chrome/services/sharing/nearby/nearby_connections_unittest.cc
index e701f90..4dbaa88 100644
--- a/chrome/services/sharing/nearby/nearby_connections_unittest.cc
+++ b/chrome/services/sharing/nearby/nearby_connections_unittest.cc
@@ -211,6 +211,8 @@
           client_proxy = client;
           EXPECT_EQ(kServiceId, service_id);
           EXPECT_EQ(Strategy::kP2pPointToPoint, options.strategy);
+          EXPECT_EQ(kFastAdvertisementServiceUuid,
+                    options.fast_advertisement_service_uuid);
           client->StartedDiscovery(service_id, options.strategy, listener,
                                    /*mediums=*/{});
           return Status{Status::kAlreadyDiscovering};
@@ -219,7 +221,9 @@
     base::RunLoop start_discovery_run_loop;
     nearby_connections_->StartDiscovery(
         kServiceId,
-        mojom::DiscoveryOptions::New(mojom::Strategy::kP2pPointToPoint),
+        mojom::DiscoveryOptions::New(
+            mojom::Strategy::kP2pPointToPoint,
+            device::BluetoothUUID(kFastAdvertisementServiceUuid)),
         fake_discovery_listener.receiver.BindNewPipeAndPassRemote(),
         base::BindLambdaForTesting([&](mojom::Status status) {
           EXPECT_EQ(mojom::Status::kAlreadyDiscovering, status);
diff --git a/chrome/services/sharing/public/mojom/nearby_connections_types.mojom b/chrome/services/sharing/public/mojom/nearby_connections_types.mojom
index 8718fb1..9f6bb2b 100644
--- a/chrome/services/sharing/public/mojom/nearby_connections_types.mojom
+++ b/chrome/services/sharing/public/mojom/nearby_connections_types.mojom
@@ -148,6 +148,8 @@
   // The strategy to use for discovering. Must match the strategy used in
   // AdvertisingOptions in order to see advertisements.
   Strategy strategy;
+  // The fast advertisement service id to scan for in BLE.
+  bluetooth.mojom.UUID fast_advertisement_service_uuid;
 };
 
 // Options for a call to NearbyConnections::RequestConnection().
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8ee3464..dd010a6 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2369,13 +2369,13 @@
         "../browser/chromeos/extensions/wallpaper_manager_browsertest.cc",
         "../browser/chromeos/extensions/wallpaper_private_apitest.cc",
         "../browser/chromeos/file_manager/audio_player_browsertest.cc",
+        "../browser/chromeos/file_manager/browser_test_devtools_listener.cc",
+        "../browser/chromeos/file_manager/browser_test_devtools_listener.h",
         "../browser/chromeos/file_manager/external_filesystem_apitest.cc",
         "../browser/chromeos/file_manager/file_manager_base_jstest.cc",
         "../browser/chromeos/file_manager/file_manager_browsertest.cc",
         "../browser/chromeos/file_manager/file_manager_browsertest_base.cc",
         "../browser/chromeos/file_manager/file_manager_browsertest_base.h",
-        "../browser/chromeos/file_manager/browser_test_devtools_listener.cc",
-        "../browser/chromeos/file_manager/browser_test_devtools_listener.h",
         "../browser/chromeos/file_manager/file_manager_jstest.cc",
         "../browser/chromeos/file_manager/file_manager_jstest_base.cc",
         "../browser/chromeos/file_manager/file_manager_jstest_base.h",
@@ -2881,6 +2881,7 @@
     }
     if (is_win) {
       sources += [
+        "../browser/chrome_browser_main_win_browsertest.cc",
         "../browser/printing/pdf_to_emf_converter_browsertest.cc",
         "../browser/spellchecker/spell_check_host_chrome_impl_win_browsertest.cc",
         "../browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc",
@@ -6201,7 +6202,6 @@
       "../browser/ui/cocoa/apps/quit_with_apps_controller_mac_interactive_uitest.mm",
       "../browser/ui/cocoa/status_bubble_mac_interactive_uitest.mm",
       "../browser/ui/cocoa/tab_contents/web_contents_view_mac_interactive_uitest.mm",
-      "../browser/ui/exclusive_access/flash_fullscreen_interactive_browsertest.cc",
       "../browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc",
       "../browser/ui/exclusive_access/fullscreen_controller_state_interactive_browsertest.cc",
       "../browser/ui/exclusive_access/fullscreen_interactive_browsertest.cc",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index 7bdec0a..a315416 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -277,6 +277,7 @@
     "//chrome/browser/ui/android/favicon:java",
     "//chrome/browser/ui/messages/android:java",
     "//chrome/browser/util:java",
+    "//chrome/browser/version:java",
     "//components/bookmarks/common/android:bookmarks_java",
     "//components/browser_ui/notifications/android:test_support_java",
     "//components/browser_ui/widget/android:java",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java
index a51dd03..19c937f 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java
@@ -20,7 +20,7 @@
 import org.chromium.base.StrictModeContext;
 import org.chromium.base.test.util.RestrictionSkipCheck;
 import org.chromium.base.test.util.SkipCheck;
-import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.version.ChromeVersionInfo;
 import org.chromium.chrome.test.util.ChromeRestriction;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.policy.test.annotations.Policies;
diff --git a/chrome/updater/util.h b/chrome/updater/util.h
index fa34992..b84eae05 100644
--- a/chrome/updater/util.h
+++ b/chrome/updater/util.h
@@ -56,13 +56,11 @@
 
 // Provides a way to safely convert numeric types to enumerated values.
 // To use this facility, the enum definition must be annotated with traits to
-// specify the range of the enum values. Due to how the specialization of
-// class template work in C++, the |EnumTraits| specialization must be
-// defined in the |updater| namespace. That means that traits for enum types
-// defined inside other scopes, such as nested classes or other namespaces
-// may not work if the traits type is define inside the that scope instead of
-// the |updater| namespace where the primary template is defined.
-
+// specify the range of the enum values. Due to how specialization of class
+// templates works in C++14, the |EnumTraits| specialization of the primary
+// template must be defined inside the |updater| namespace, where the
+// primary template is defined. Traits for enum types defined inside
+// other scopes, such as nested classes or other namespaces, may not work.
 //
 // enum class MyEnum {
 //   kVal1 = -1,
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 3d92acb..b6350df 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-13510.0.0
\ No newline at end of file
+13511.0.0
\ No newline at end of file
diff --git a/chromeos/components/diagnostics_ui/resources/battery_status_card.html b/chromeos/components/diagnostics_ui/resources/battery_status_card.html
index f607659..583cbbd7 100644
--- a/chromeos/components/diagnostics_ui/resources/battery_status_card.html
+++ b/chromeos/components/diagnostics_ui/resources/battery_status_card.html
@@ -3,6 +3,11 @@
 
 <diagnostics-card>
   <div id="cardTitle" slot="title">[[i18n('batteryTitle')]]</div>
+  <!-- TODO(joonbug): Localize once strings are confirmed -->
+  <percent-bar-chart slot="left-panel" title="Remaining charge"
+    value="[[batteryChargeStatus_.charge_now_milliamp_hours]]"
+    max="[[batteryChargeStatus_.charge_full_now_milliamp_hours]]">
+  </percent-bar-chart>
   <data-point slot="body" id="currentNow"
     value="[[batteryChargeStatus_.current_now_milliamps]]">
   </data-point>
@@ -24,9 +29,4 @@
   <data-point slot="body" id="cycleCount"
     value="[[batteryHealth_.cycle_count]]">
   </data-point>
-  <!-- TODO(joonbug): Localize once strings are confirmed -->
-  <percent-bar-chart slot="body" title="Remaining charge"
-    value="[[batteryChargeStatus_.charge_now_milliamp_hours]]"
-    max="[[batteryChargeStatus_.charge_full_now_milliamp_hours]]">
-  </percent-bar-chart>
 </diagnostics-card>
diff --git a/chromeos/components/diagnostics_ui/resources/memory_card.html b/chromeos/components/diagnostics_ui/resources/memory_card.html
index ad4c17d..c0bdd42 100644
--- a/chromeos/components/diagnostics_ui/resources/memory_card.html
+++ b/chromeos/components/diagnostics_ui/resources/memory_card.html
@@ -3,15 +3,15 @@
 
 <diagnostics-card>
   <div id="cardTitle" slot="title">[[i18n('memoryTitle')]]</div>
+  <!-- TODO(joonbug): Localize once strings are confirmed -->
+  <percent-bar-chart slot="left-panel" title="Used memory"
+    value="[[getTotalUsedMemory_(memoryUsage_)]]"
+    max="[[memoryUsage_.total_memory_kib]]">
+  </percent-bar-chart>
   <data-point slot="body" id="memoryTotal"
     value="[[memoryUsage_.total_memory_kib]]">
   </data-point>
   <data-point slot="body" id="memoryAvailable"
     value="[[memoryUsage_.available_memory_kib]]">
   </data-point>
-  <!-- TODO(joonbug): Localize once strings are confirmed -->
-  <percent-bar-chart slot="body" title="Used memory"
-    value="[[getTotalUsedMemory_(memoryUsage_)]]"
-    max="[[memoryUsage_.total_memory_kib]]">
-  </percent-bar-chart>
 </diagnostics-card>
diff --git a/chromeos/components/phonehub/fake_do_not_disturb_controller.cc b/chromeos/components/phonehub/fake_do_not_disturb_controller.cc
index bfe586c0..b1bb3fc 100644
--- a/chromeos/components/phonehub/fake_do_not_disturb_controller.cc
+++ b/chromeos/components/phonehub/fake_do_not_disturb_controller.cc
@@ -25,7 +25,13 @@
 }
 
 void FakeDoNotDisturbController::RequestNewDoNotDisturbState(bool enabled) {
-  SetDoNotDisturbStateInternal(enabled);
+  if (!should_request_fail_)
+    SetDoNotDisturbStateInternal(enabled);
+}
+
+void FakeDoNotDisturbController::SetShouldRequestFail(
+    bool should_request_fail) {
+  should_request_fail_ = should_request_fail;
 }
 
 }  // namespace phonehub
diff --git a/chromeos/components/phonehub/fake_do_not_disturb_controller.h b/chromeos/components/phonehub/fake_do_not_disturb_controller.h
index 6d9de37..1a252938e 100644
--- a/chromeos/components/phonehub/fake_do_not_disturb_controller.h
+++ b/chromeos/components/phonehub/fake_do_not_disturb_controller.h
@@ -20,8 +20,14 @@
   void SetDoNotDisturbStateInternal(bool is_dnd_enabled) override;
   void RequestNewDoNotDisturbState(bool enabled) override;
 
+  void SetShouldRequestFail(bool should_request_fail);
+
  private:
   bool is_dnd_enabled_ = false;
+
+  // Indicates if the connection to the phone is working correctly. If it is
+  // true, there is a problem and the phone cannot change its state.
+  bool should_request_fail_ = false;
 };
 
 }  // namespace phonehub
diff --git a/chromeos/dbus/fake_lorgnette_manager_client.cc b/chromeos/dbus/fake_lorgnette_manager_client.cc
index 52dcd811..af1b968 100644
--- a/chromeos/dbus/fake_lorgnette_manager_client.cc
+++ b/chromeos/dbus/fake_lorgnette_manager_client.cc
@@ -37,9 +37,10 @@
     const std::string& device_name,
     const lorgnette::ScanSettings& settings,
     VoidDBusMethodCallback completion_callback,
-    base::RepeatingCallback<void(std::string)> page_callback,
+    base::RepeatingCallback<void(std::string, uint32_t)> page_callback,
     base::RepeatingCallback<void(int)> progress_callback) {
   if (scan_response_.has_value()) {
+    uint32_t page_number = 0;
     for (const std::string& page_data : scan_response_.value()) {
       // Simulate progress reporting for the scan job.
       if (progress_callback) {
@@ -50,7 +51,7 @@
       }
 
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::BindOnce(page_callback, page_data));
+          FROM_HERE, base::BindOnce(page_callback, page_data, ++page_number));
     }
   }
 
diff --git a/chromeos/dbus/fake_lorgnette_manager_client.h b/chromeos/dbus/fake_lorgnette_manager_client.h
index 5977a8a0..c074597 100644
--- a/chromeos/dbus/fake_lorgnette_manager_client.h
+++ b/chromeos/dbus/fake_lorgnette_manager_client.h
@@ -5,6 +5,7 @@
 #ifndef CHROMEOS_DBUS_FAKE_LORGNETTE_MANAGER_CLIENT_H_
 #define CHROMEOS_DBUS_FAKE_LORGNETTE_MANAGER_CLIENT_H_
 
+#include <cstdint>
 #include <string>
 #include <vector>
 
@@ -30,11 +31,12 @@
   void GetScannerCapabilities(
       const std::string& device_name,
       DBusMethodCallback<lorgnette::ScannerCapabilities> callback) override;
-  void StartScan(const std::string& device_name,
-                 const lorgnette::ScanSettings& settings,
-                 VoidDBusMethodCallback completion_callback,
-                 base::RepeatingCallback<void(std::string)> page_callback,
-                 base::RepeatingCallback<void(int)> progress_callback) override;
+  void StartScan(
+      const std::string& device_name,
+      const lorgnette::ScanSettings& settings,
+      VoidDBusMethodCallback completion_callback,
+      base::RepeatingCallback<void(std::string, uint32_t)> page_callback,
+      base::RepeatingCallback<void(int)> progress_callback) override;
 
   // Sets the response returned by ListScanners().
   void SetListScannersResponse(
diff --git a/chromeos/dbus/lorgnette_manager_client.cc b/chromeos/dbus/lorgnette_manager_client.cc
index f49a3fe..e8fdca06 100644
--- a/chromeos/dbus/lorgnette_manager_client.cc
+++ b/chromeos/dbus/lorgnette_manager_client.cc
@@ -70,7 +70,7 @@
       const std::string& device_name,
       const lorgnette::ScanSettings& settings,
       VoidDBusMethodCallback completion_callback,
-      base::RepeatingCallback<void(std::string)> page_callback,
+      base::RepeatingCallback<void(std::string, uint32_t)> page_callback,
       base::RepeatingCallback<void(int)> progress_callback) override {
     lorgnette::StartScanRequest request;
     request.set_device_name(device_name);
@@ -185,7 +185,7 @@
   struct ScanJobState {
     VoidDBusMethodCallback completion_callback;
     base::RepeatingCallback<void(int)> progress_callback;
-    base::RepeatingCallback<void(std::string)> page_callback;
+    base::RepeatingCallback<void(std::string, uint32_t)> page_callback;
     std::unique_ptr<ScanDataReader> scan_data_reader;
   };
 
@@ -267,6 +267,7 @@
 
   // Called when scan data read is completed.
   void OnScanDataCompleted(const std::string& uuid,
+                           uint32_t page_number,
                            bool more_pages,
                            base::Optional<std::string> data) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -284,7 +285,7 @@
       return;
     }
 
-    state.page_callback.Run(std::move(data.value()));
+    state.page_callback.Run(std::move(data.value()), page_number);
 
     if (more_pages) {
       GetNextImage(uuid);
@@ -375,10 +376,10 @@
       VLOG(1) << "Scan job " << signal_proto.scan_uuid() << " page "
               << signal_proto.page() << " completed successfully";
       ScanDataReader* reader = state.scan_data_reader.get();
-      reader->Wait(
-          base::BindOnce(&LorgnetteManagerClientImpl::OnScanDataCompleted,
-                         weak_ptr_factory_.GetWeakPtr(),
-                         signal_proto.scan_uuid(), signal_proto.more_pages()));
+      reader->Wait(base::BindOnce(
+          &LorgnetteManagerClientImpl::OnScanDataCompleted,
+          weak_ptr_factory_.GetWeakPtr(), signal_proto.scan_uuid(),
+          signal_proto.page(), signal_proto.more_pages()));
     } else if (signal_proto.state() == lorgnette::SCAN_STATE_COMPLETED) {
       VLOG(1) << "Scan job " << signal_proto.scan_uuid()
               << " completed successfully";
diff --git a/chromeos/dbus/lorgnette_manager_client.h b/chromeos/dbus/lorgnette_manager_client.h
index 3e6fc2ae..6d78917 100644
--- a/chromeos/dbus/lorgnette_manager_client.h
+++ b/chromeos/dbus/lorgnette_manager_client.h
@@ -5,6 +5,7 @@
 #ifndef CHROMEOS_DBUS_LORGNETTE_MANAGER_CLIENT_H_
 #define CHROMEOS_DBUS_LORGNETTE_MANAGER_CLIENT_H_
 
+#include <cstdint>
 #include <map>
 #include <memory>
 #include <string>
@@ -43,9 +44,9 @@
       DBusMethodCallback<lorgnette::ScannerCapabilities> callback) = 0;
 
   // Request a scanned image using lorgnette's StartScan API. As each page is
-  // completed, calls |page_callback| with a string containing the image data.
-  // Calls |completion_callback| when the scan has completed. Image data will
-  // be stored in the .png format.
+  // completed, calls |page_callback| with the page number and a string
+  // containing the image data. Calls |completion_callback| when the scan has
+  // completed. Image data will be stored in the .png format.
   //
   // If |progress_callback| is provided, it will be called as scan progress
   // increases. The progress will be passed as a value from 0-100.
@@ -53,7 +54,7 @@
       const std::string& device_name,
       const lorgnette::ScanSettings& settings,
       VoidDBusMethodCallback completion_callback,
-      base::RepeatingCallback<void(std::string)> page_callback,
+      base::RepeatingCallback<void(std::string, uint32_t)> page_callback,
       base::RepeatingCallback<void(int)> progress_callback) = 0;
 
   // Factory function, creates a new instance and returns ownership.
diff --git a/chromeos/profiles/airmont.afdo.newest.txt b/chromeos/profiles/airmont.afdo.newest.txt
index adbd799..6f0e92e 100644
--- a/chromeos/profiles/airmont.afdo.newest.txt
+++ b/chromeos/profiles/airmont.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-airmont-87-4265.0-1601286022-benchmark-87.0.4280.7-r1-redacted.afdo.xz
+chromeos-chrome-amd64-airmont-87-4265.0-1601895675-benchmark-87.0.4280.7-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/broadwell.afdo.newest.txt b/chromeos/profiles/broadwell.afdo.newest.txt
index 85bcbe1..42597249 100644
--- a/chromeos/profiles/broadwell.afdo.newest.txt
+++ b/chromeos/profiles/broadwell.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-broadwell-87-4258.0-1601290734-benchmark-87.0.4280.7-r1-redacted.afdo.xz
+chromeos-chrome-amd64-broadwell-87-4265.0-1601892862-benchmark-87.0.4280.7-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/silvermont.afdo.newest.txt b/chromeos/profiles/silvermont.afdo.newest.txt
index e676c08..b2f1cfd 100644
--- a/chromeos/profiles/silvermont.afdo.newest.txt
+++ b/chromeos/profiles/silvermont.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-silvermont-87-4265.0-1601289755-benchmark-87.0.4280.7-r1-redacted.afdo.xz
+chromeos-chrome-amd64-silvermont-87-4265.0-1601890590-benchmark-87.0.4280.7-r1-redacted.afdo.xz
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index be64d5f3..1f49b84 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -24,6 +24,13 @@
 const base::Feature kAutofillAddressEnhancementVotes{
     "kAutofillAddressEnhancementVotes", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// TODO(crbug.com/1135188): Remove this feature flag after the explicit save
+// prompts for address profiles is complete.
+// When enabled, a save prompt will be shown to user upon form submission before
+// storing any detected address profile.
+const base::Feature kAutofillAddressProfileSavePrompt{
+    "kAutofillAddressProfileSavePrompt", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // By default, AutofillAgent and, if |kAutofillProbableFormSubmissionInBrowser|
 // is enabled, also ContentAutofillDriver omit duplicate form submissions, even
 // though the form's data may have changed substantially. If enabled, the
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 6fd7f20..d29a713 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -22,6 +22,7 @@
 
 // All features in alphabetical order.
 extern const base::Feature kAutofillAddressEnhancementVotes;
+extern const base::Feature kAutofillAddressProfileSavePrompt;
 extern const base::Feature kAutofillAllowDuplicateFormSubmissions;
 extern const base::Feature kAutofillAllowHtmlTypeCountryCodesWithFullNames;
 extern const base::Feature kAutofillAllowNonHttpActivation;
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
index 9dd0a7f..544cce98 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleWebsiteSettings.java
@@ -1038,12 +1038,12 @@
         int confirmationResId = mHideNonPermissionPreferences
                 ? R.string.page_info_permissions_reset_confirmation
                 : R.string.website_reset_confirmation;
-        preference.setTitle(titleResId);
+        int buttonResId = mHideNonPermissionPreferences ? R.string.reset : titleResId;
         // Handle the Clear & Reset preference click by showing a confirmation.
         new AlertDialog.Builder(getActivity(), R.style.Theme_Chromium_AlertDialog)
                 .setTitle(titleResId)
                 .setMessage(confirmationResId)
-                .setPositiveButton(titleResId,
+                .setPositiveButton(buttonResId,
                         (dialog, which) -> {
                             if (mHideNonPermissionPreferences) {
                                 mSiteDataCleaner.resetPermissions(
diff --git a/components/page_info/android/java/res/layout/page_info_container.xml b/components/page_info/android/java/res/layout/page_info_container.xml
index 04a505a..f97a0ef 100644
--- a/components/page_info/android/java/res/layout/page_info_container.xml
+++ b/components/page_info/android/java/res/layout/page_info_container.xml
@@ -14,28 +14,38 @@
     android:background="@color/sheet_bg_color"
     android:orientation="vertical">
 
-    <TextView
-        android:id="@+id/page_info_truncated_url"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"
-        android:layout_marginVertical="16dp"
-        android:ellipsize="end"
-        android:lineSpacingExtra="6dp"
-        android:textAlignment="center"
-        android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
-
-    <view
-        android:id="@+id/page_info_url"
-        class="org.chromium.components.page_info.PageInfoView$ElidedUrlTextView"
+    <LinearLayout
+        android:id="@+id/page_info_url_wrapper"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:ellipsize="end"
-        android:lineSpacingExtra="6dp"
-        android:paddingVertical="16dp"
-        android:textAlignment="center"
-        android:textAppearance="@style/TextAppearance.TextLarge.Primary"
-        android:visibility="gone" />
+        android:minHeight="48dp"
+        android:gravity="center"
+        android:paddingVertical="@dimen/page_info_popup_padding_vertical"
+        android:paddingHorizontal="@dimen/page_info_popup_padding_sides">
+
+        <org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables
+            android:id="@+id/page_info_truncated_url"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:drawablePadding="@dimen/page_info_popup_button_padding_sides"
+            android:includeFontPadding="false"
+            android:lineSpacingExtra="6dp"
+            android:textAppearance="@style/TextAppearance.TextLarge.Primary"
+            app:drawableHeight="@dimen/page_info_favicon_size"
+            app:drawableWidth="@dimen/page_info_favicon_size" />
+
+        <view
+            android:id="@+id/page_info_url"
+            class="org.chromium.components.page_info.PageInfoView$ElidedUrlTextView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:includeFontPadding="false"
+            android:lineSpacingExtra="6dp"
+            android:textAlignment="center"
+            android:textAppearance="@style/TextAppearance.TextLarge.Primary"
+            android:visibility="gone" />
+    </LinearLayout>
 
     <LinearLayout
         android:id="@+id/page_info_wrapper"
@@ -49,7 +59,7 @@
             android:layout_height="wrap_content"
             android:gravity="center_vertical"
             android:orientation="horizontal"
-            android:paddingHorizontal="16dp">
+            android:paddingHorizontal="@dimen/page_info_popup_padding_sides">
 
             <org.chromium.ui.widget.ChromeImageButton
                 android:id="@+id/subpage_back_button"
@@ -67,7 +77,7 @@
                 android:id="@+id/page_info_subpage_title"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_marginVertical="12dp"
+                android:layout_marginVertical="@dimen/page_info_popup_padding_vertical"
                 android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
         </LinearLayout>
 
diff --git a/components/page_info/android/java/res/layout/page_info_row.xml b/components/page_info/android/java/res/layout/page_info_row.xml
index a1cf416..25cb7c8 100644
--- a/components/page_info/android/java/res/layout/page_info_row.xml
+++ b/components/page_info/android/java/res/layout/page_info_row.xml
@@ -14,9 +14,9 @@
     android:layout_height="wrap_content"
     android:background="?attr/selectableItemBackground"
     android:paddingHorizontal="@dimen/page_info_popup_padding_sides"
-    android:paddingVertical="12dp">
+    android:paddingVertical="@dimen/page_info_popup_padding_vertical">
 
-    <ImageView
+    <org.chromium.ui.widget.ChromeImageView
         android:id="@+id/page_info_row_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/components/page_info/android/java/res/layout/page_info_v2.xml b/components/page_info/android/java/res/layout/page_info_v2.xml
index 8fdf5d1..a6c6e98 100644
--- a/components/page_info/android/java/res/layout/page_info_v2.xml
+++ b/components/page_info/android/java/res/layout/page_info_v2.xml
@@ -12,7 +12,7 @@
     android:layout_height="match_parent"
     android:background="@color/sheet_bg_color"
     android:orientation="vertical"
-    android:layout_marginBottom="8dp">
+    android:paddingBottom="8dp">
 
     <LinearLayout
         android:id="@+id/page_info_row_wrapper"
@@ -50,7 +50,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginHorizontal="@dimen/page_info_popup_padding_sides"
-        android:layout_marginTop="12dp"
+        android:layout_marginTop="@dimen/page_info_popup_padding_vertical"
         android:textAppearance="@style/TextAppearance.TextLarge.Primary"
         android:text="@string/page_info_preview_message"
         android:visibility="gone" />
@@ -59,7 +59,7 @@
         android:id="@+id/page_info_preview_load_original"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginVertical="12dp"
+        android:layout_marginVertical="@dimen/page_info_popup_padding_vertical"
         android:layout_marginHorizontal="@dimen/page_info_popup_padding_sides"
         android:textAppearance="@style/TextAppearance.TextLarge.Primary"
         android:visibility="gone" />
@@ -68,7 +68,7 @@
         android:id="@+id/page_info_lite_mode_https_image_compression_message"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginVertical="12dp"
+        android:layout_marginVertical="@dimen/page_info_popup_padding_vertical"
         android:layout_marginHorizontal="@dimen/page_info_popup_padding_sides"
         android:text="@string/page_info_lite_mode_https_image_compression"
         android:textAppearance="@style/TextAppearance.TextMedium.Primary"
diff --git a/components/page_info/android/java/res/values/dimens.xml b/components/page_info/android/java/res/values/dimens.xml
index 691979b..e42de84 100644
--- a/components/page_info/android/java/res/values/dimens.xml
+++ b/components/page_info/android/java/res/values/dimens.xml
@@ -11,6 +11,7 @@
 
     <!-- Page Info Popup Dimensions -->
     <dimen name="page_info_popup_padding_sides">16dp</dimen>
+    <dimen name="page_info_popup_padding_vertical">12dp</dimen>
     <dimen name="page_info_popup_button_padding_sides">8dp</dimen>
     <dimen name="page_info_popup_permission_icon_size">24dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java
index d9d3f64..7aa99ea 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoConnectionController.java
@@ -8,7 +8,10 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import androidx.annotation.ColorRes;
+
 import org.chromium.components.omnibox.SecurityStatusIcon;
+import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.components.security_state.SecurityStateModel;
 import org.chromium.content_public.browser.WebContents;
 
@@ -57,17 +60,37 @@
         mInfoView.onDismiss();
     }
 
+    private static @ColorRes int getSecurityIconColor(
+            @ConnectionSecurityLevel int securityLevel, boolean showDangerTriangleForWarningLevel) {
+        switch (securityLevel) {
+            case ConnectionSecurityLevel.DANGEROUS:
+                return R.color.default_text_color_error;
+            case ConnectionSecurityLevel.WARNING:
+                return showDangerTriangleForWarningLevel ? R.color.default_text_color_error : 0;
+            case ConnectionSecurityLevel.NONE:
+            case ConnectionSecurityLevel.SECURE_WITH_POLICY_INSTALLED_CERT:
+            case ConnectionSecurityLevel.SECURE:
+                return 0;
+            default:
+                assert false;
+                return 0;
+        }
+    }
+
     public void setConnectionInfo(PageInfoView.ConnectionInfoParams params) {
         PageInfoRowView.ViewParams rowParams = new PageInfoRowView.ViewParams();
         mTitle = params.summary != null ? params.summary.toString() : null;
         rowParams.title = mTitle;
-        rowParams.subtitle = params.message != null ? params.message.toString() : null;
+        rowParams.subtitle = params.message;
         rowParams.visible = rowParams.title != null || rowParams.subtitle != null;
         int securityLevel = SecurityStateModel.getSecurityLevelForWebContents(mWebContents);
-        rowParams.iconResId = SecurityStatusIcon.getSecurityIconResource(securityLevel,
-                SecurityStateModel.shouldShowDangerTriangleForWarningLevel(),
-                /*isSmallDevice=*/false,
-                /*skipIconForNeutralState=*/false);
+        boolean showTriangleForWarning =
+                SecurityStateModel.shouldShowDangerTriangleForWarningLevel();
+        rowParams.iconResId =
+                SecurityStatusIcon.getSecurityIconResource(securityLevel, showTriangleForWarning,
+                        /*isSmallDevice=*/false,
+                        /*skipIconForNeutralState=*/false);
+        rowParams.iconTint = getSecurityIconColor(securityLevel, showTriangleForWarning);
         if (params.clickCallback != null) rowParams.clickCallback = this::launchSubpage;
         mRowView.setParams(rowParams);
     }
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java
index bcd1657f..3efe1e6 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoContainer.java
@@ -69,14 +69,14 @@
         mTruncatedUrlTitle = findViewById(R.id.page_info_truncated_url);
         mTruncatedUrlTitle.setText(params.truncatedUrl);
 
+        View urlWrapper = findViewById(R.id.page_info_url_wrapper);
+        urlWrapper.setVisibility(params.urlTitleShown ? VISIBLE : GONE);
+
         ChromeImageButton backButton = findViewById(R.id.subpage_back_button);
         backButton.setOnClickListener(v -> params.backButtonClickCallback.run());
     }
 
     private void initializeUrlView(View view, Params params) {
-        if (!params.urlTitleShown) {
-            view.setVisibility(GONE);
-        }
         if (params.urlTitleClickCallback != null) {
             view.setOnClickListener(v -> { params.urlTitleClickCallback.run(); });
         }
@@ -94,12 +94,6 @@
     }
 
     public void setFavicon(Drawable favicon) {
-        int padding =
-                getResources().getDimensionPixelSize(R.dimen.page_info_popup_button_padding_sides);
-        int size = getResources().getDimensionPixelSize(R.dimen.page_info_favicon_size);
-
-        favicon.setBounds(0, 0, size, size);
-        mTruncatedUrlTitle.setCompoundDrawablePadding(padding);
         mTruncatedUrlTitle.setCompoundDrawablesRelative(favicon, null, null, null);
     }
 
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
index 600b8cc..6bc0b018 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoController.java
@@ -413,7 +413,7 @@
             messageBuilder.append(details);
         }
 
-        if (!mIsV2Enabled && isConnectionDetailsLinkVisible()) {
+        if (isConnectionDetailsLinkVisible() && messageBuilder.length() > 0) {
             messageBuilder.append(" ");
             SpannableString detailsText =
                     new SpannableString(mContext.getString(R.string.details_link));
diff --git a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoRowView.java b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoRowView.java
index 5797a3a..0344628 100644
--- a/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoRowView.java
+++ b/components/page_info/android/java/src/org/chromium/components/page_info/PageInfoRowView.java
@@ -5,16 +5,20 @@
 package org.chromium.components.page_info;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.ColorRes;
 import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.ui.widget.ChromeImageView;
+
 /**
  * View showing an icon, title and subtitle for a page info row.
  */
@@ -23,12 +27,13 @@
     public static class ViewParams {
         public boolean visible;
         public @DrawableRes int iconResId;
-        public String title;
-        public String subtitle;
+        public @ColorRes int iconTint;
+        public CharSequence title;
+        public CharSequence subtitle;
         public Runnable clickCallback;
     }
 
-    private final ImageView mIcon;
+    private final ChromeImageView mIcon;
     private final TextView mTitle;
     private final TextView mSubtitle;
 
@@ -43,6 +48,10 @@
     public void setParams(ViewParams params) {
         setVisibility(params.visible ? VISIBLE : GONE);
         mIcon.setImageResource(params.iconResId);
+        ApiCompatibilityUtils.setImageTintList(mIcon,
+                ColorStateList.valueOf(getResources().getColor(
+                        params.iconTint != 0 ? params.iconTint : R.color.default_icon_color)));
+
         mTitle.setText(params.title);
         mTitle.setVisibility(params.title != null ? VISIBLE : GONE);
         updateSubtitle(params.subtitle);
@@ -53,7 +62,7 @@
         }
     }
 
-    public void updateSubtitle(String subtitle) {
+    public void updateSubtitle(CharSequence subtitle) {
         mSubtitle.setText(subtitle);
         mSubtitle.setVisibility(subtitle != null ? VISIBLE : GONE);
     }
diff --git a/components/test/data/payments/create_many_requests.js b/components/test/data/payments/create_many_requests.js
index 90f2240..7ff435f 100644
--- a/components/test/data/payments/create_many_requests.js
+++ b/components/test/data/payments/create_many_requests.js
@@ -17,6 +17,6 @@
   total: {label: 'Total', amount: {currency: 'USD', value: '55.00'}},
 };
 
-for (let i = 0; i < 0x1000; i++) {
+for (let i = 0; i < 0x400; i++) {
   new PaymentRequest(supportedInstruments, details);
 }
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc
index 53957212..5cb13e5b 100644
--- a/components/viz/common/features.cc
+++ b/components/viz/common/features.cc
@@ -111,14 +111,6 @@
   if (IsUsingVizForWebView())
     return true;
 
-#if defined(OS_ANDROID)
-  // https://crbug.com/1126490 Mali-400 with <= 512 MB is currently broken.
-  // Must be checked after IsUsingVizForWebView because it requires
-  // SkiaRenderer.
-  if (base::SysInfo::AmountOfPhysicalMemoryMB() <= 512)
-    return false;
-#endif
-
   return base::FeatureList::IsEnabled(kUseSkiaRenderer) ||
          base::FeatureList::IsEnabled(kVulkan);
 }
diff --git a/components/viz/service/display_embedder/skia_output_device_gl.cc b/components/viz/service/display_embedder/skia_output_device_gl.cc
index 9e4ce61..3dd38d85 100644
--- a/components/viz/service/display_embedder/skia_output_device_gl.cc
+++ b/components/viz/service/display_embedder/skia_output_device_gl.cc
@@ -125,8 +125,22 @@
   }
   CHECK_GL_ERROR();
 
-  auto color_type =
-      (alpha_bits > 0) ? kRGBA_8888_SkColorType : kRGB_888x_SkColorType;
+  auto color_type = kRGBA_8888_SkColorType;
+
+  if (!alpha_bits) {
+    color_type = gl_surface_->GetFormat().GetBufferSize() == 16
+                     ? kRGB_565_SkColorType
+                     : kRGB_888x_SkColorType;
+    // Skia disables RGBx on some GPUs, fallback to RGBA if it's the
+    // case. This doesn't change framebuffer itself, as we already allocated it,
+    // but will change any temporary buffer Skia needs to allocate.
+    if (!context_state_->gr_context()
+             ->defaultBackendFormat(color_type, GrRenderable::kYes)
+             .isValid()) {
+      color_type = kRGBA_8888_SkColorType;
+    }
+  }
+
   capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] =
       color_type;
   capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBX_8888)] =
@@ -175,6 +189,9 @@
     case kRGB_888x_SkColorType:
       framebuffer_info.fFormat = GL_RGB8;
       break;
+    case kRGB_565_SkColorType:
+      framebuffer_info.fFormat = GL_RGB565;
+      break;
     case kRGBA_F16_SkColorType:
       framebuffer_info.fFormat = GL_RGBA16F;
       break;
diff --git a/content/browser/accessibility/accessibility_ipc_error_browsertest.cc b/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
index 75ed16d1..1dff9e7 100644
--- a/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
+++ b/content/browser/accessibility/accessibility_ipc_error_browsertest.cc
@@ -186,7 +186,7 @@
   bad_accessibility_event.updates[0].root_id = 1;
   bad_accessibility_event.updates[0].nodes.resize(1);
   bad_accessibility_event.updates[0].nodes[0].id = 1;
-  bad_accessibility_event.updates[0].nodes[0].child_ids.push_back(2);
+  bad_accessibility_event.updates[0].nodes[0].child_ids.push_back(999);
 
   for (int iteration = 0; iteration < max_iterations; iteration++) {
     // Make sure the manager has been created.
diff --git a/content/browser/renderer_host/overscroll_controller.cc b/content/browser/renderer_host/overscroll_controller.cc
index 112ec65..616f9d2 100644
--- a/content/browser/renderer_host/overscroll_controller.cc
+++ b/content/browser/renderer_host/overscroll_controller.cc
@@ -175,6 +175,10 @@
 
   // In overscrolling state, consume scroll-update and fling-start events when
   // they do not contribute to overscroll in order to prevent content scroll.
+  // TODO(bokan): This needs to account for behavior_ somehow since if the page
+  // declares that it doesn't want an overscroll effect, we should allow
+  // sending the scroll update events to generate DOM overscroll events.
+  // https://crbug.com/1112183.
   return scroll_state_ == ScrollState::OVERSCROLLING &&
          (event.GetType() == blink::WebInputEvent::Type::kGestureScrollUpdate ||
           event.GetType() == blink::WebInputEvent::Type::kGestureFlingStart);
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index f1ac18ef..bc353236 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -290,6 +290,7 @@
   ui::AXTreeID GetAXTreeID() override;
   SiteInstanceImpl* GetSiteInstance() override;
   RenderProcessHost* GetProcess() override;
+  GlobalFrameRoutingId GetGlobalFrameRoutingId() override;
   RenderWidgetHostView* GetView() override;
   RenderFrameHostImpl* GetParent() override;
   RenderFrameHostImpl* GetMainFrame() override;
@@ -664,8 +665,6 @@
   // typically mean that the frame has been detached from the frame tree.
   virtual RenderWidgetHostImpl* GetRenderWidgetHost();
 
-  GlobalFrameRoutingId GetGlobalFrameRoutingId();
-
   media::MediaMetricsProvider::RecordAggregateWatchTimeCallback
   GetRecordAggregateWatchTimeCallback();
 
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 4512f3f..e21c226 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -60,6 +60,7 @@
 #include "device/fido/fido_types.h"
 #include "device/fido/hid/fake_hid_impl_for_testing.h"
 #include "device/fido/mock_fido_device.h"
+#include "device/fido/pin.h"
 #include "device/fido/public_key.h"
 #include "device/fido/test_callback_receiver.h"
 #include "device/fido/virtual_fido_device_factory.h"
@@ -3644,8 +3645,11 @@
     kUsePIN,
   };
 
-  void ConfigureVirtualDevice(bool pin_uv_auth_token, int support_level) {
+  void ConfigureVirtualDevice(device::PINUVAuthProtocol pin_protocol,
+                              bool pin_uv_auth_token,
+                              int support_level) {
     device::VirtualCtap2Device::Config config;
+    config.pin_protocol = pin_protocol;
     config.pin_uv_auth_token_support = pin_uv_auth_token;
     config.ctap2_versions = {device::Ctap2Version::kCtap2_0,
                              device::Ctap2Version::kCtap2_1};
@@ -3738,57 +3742,65 @@
       test_client_.supports_pin = ui_support;
 
       for (int support_level = 0; support_level <= 2; support_level++) {
-        SCOPED_TRACE(kPINSupportDescription[support_level]);
-        ConfigureVirtualDevice(pin_uv_auth_token, support_level);
+        for (const auto pin_protocol :
+             {device::PINUVAuthProtocol::kV1, device::PINUVAuthProtocol::kV2}) {
+          SCOPED_TRACE(testing::Message()
+                       << "support_level="
+                       << kPINSupportDescription[support_level]
+                       << ", pin_protocol=" << static_cast<int>(pin_protocol));
+          ConfigureVirtualDevice(pin_protocol, pin_uv_auth_token,
+                                 support_level);
 
-        for (int uv_level = 0; uv_level <= 2; uv_level++) {
-          SCOPED_TRACE(kUVDescription[uv_level]);
+          for (int uv_level = 0; uv_level <= 2; uv_level++) {
+            SCOPED_TRACE(kUVDescription[uv_level]);
 
-          switch (expected[support_level][uv_level]) {
-            case kNoPIN:
-            case kFailure:
-              // There shouldn't be any PIN prompts.
-              test_client_.expected.clear();
-              break;
+            switch (expected[support_level][uv_level]) {
+              case kNoPIN:
+              case kFailure:
+                // There shouldn't be any PIN prompts.
+                test_client_.expected.clear();
+                break;
 
-            case kSetPIN:
-              // A single PIN prompt to set a PIN is expected.
-              test_client_.expected = {{base::nullopt, kTestPIN}};
-              break;
+              case kSetPIN:
+                // A single PIN prompt to set a PIN is expected.
+                test_client_.expected = {{base::nullopt, kTestPIN}};
+                break;
 
-            case kUsePIN:
-              // A single PIN prompt to get the PIN is expected.
-              test_client_.expected = {{8, kTestPIN}};
-              break;
+              case kUsePIN:
+                // A single PIN prompt to get the PIN is expected.
+                test_client_.expected = {{8, kTestPIN}};
+                break;
 
-            default:
-              NOTREACHED();
-          }
+              default:
+                NOTREACHED();
+            }
 
-          MakeCredentialResult result = AuthenticatorMakeCredential(
-              make_credential_options(kUVLevel[uv_level]));
+            MakeCredentialResult result = AuthenticatorMakeCredential(
+                make_credential_options(kUVLevel[uv_level]));
 
-          switch (expected[support_level][uv_level]) {
-            case kFailure:
-              EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, result.status);
-              break;
+            switch (expected[support_level][uv_level]) {
+              case kFailure:
+                EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR,
+                          result.status);
+                break;
 
-            case kNoPIN:
-              EXPECT_EQ(AuthenticatorStatus::SUCCESS, result.status);
-              EXPECT_EQ("", virtual_device_factory_->mutable_state()->pin);
-              EXPECT_FALSE(HasUV(result.response));
-              break;
+              case kNoPIN:
+                EXPECT_EQ(AuthenticatorStatus::SUCCESS, result.status);
+                EXPECT_EQ("", virtual_device_factory_->mutable_state()->pin);
+                EXPECT_FALSE(HasUV(result.response));
+                break;
 
-            case kSetPIN:
-            case kUsePIN:
-              EXPECT_EQ(AuthenticatorStatus::SUCCESS, result.status);
-              EXPECT_EQ(kTestPIN,
-                        virtual_device_factory_->mutable_state()->pin);
-              EXPECT_TRUE(HasUV(result.response));
-              break;
+              case kSetPIN:
+              case kUsePIN:
+                EXPECT_EQ(AuthenticatorStatus::SUCCESS, result.status);
+                EXPECT_EQ(kTestPIN,
+                          virtual_device_factory_->mutable_state()->pin);
+                EXPECT_TRUE(HasUV(result.response));
+                break;
 
-            default:
-              NOTREACHED();
+              default:
+                NOTREACHED();
+            }
           }
         }
       }
@@ -3873,49 +3885,58 @@
 
       for (int support_level = 0; support_level <= 2; support_level++) {
         SCOPED_TRACE(kPINSupportDescription[support_level]);
-        ConfigureVirtualDevice(pin_uv_auth_token, support_level);
+        for (const auto pin_protocol :
+             {device::PINUVAuthProtocol::kV1, device::PINUVAuthProtocol::kV2}) {
+          SCOPED_TRACE(testing::Message()
+                       << "support_level="
+                       << kPINSupportDescription[support_level]
+                       << ", pin_protocol=" << static_cast<int>(pin_protocol));
+          ConfigureVirtualDevice(pin_protocol, pin_uv_auth_token,
+                                 support_level);
 
-        for (int uv_level = 0; uv_level <= 2; uv_level++) {
-          SCOPED_TRACE(kUVDescription[uv_level]);
+          for (int uv_level = 0; uv_level <= 2; uv_level++) {
+            SCOPED_TRACE(kUVDescription[uv_level]);
 
-          switch (expected[support_level][uv_level]) {
-            case kNoPIN:
-            case kFailure:
-              // No PIN prompts are expected.
-              test_client_.expected.clear();
-              break;
+            switch (expected[support_level][uv_level]) {
+              case kNoPIN:
+              case kFailure:
+                // No PIN prompts are expected.
+                test_client_.expected.clear();
+                break;
 
-            case kUsePIN:
-              // A single prompt to get the PIN is expected.
-              test_client_.expected = {{8, kTestPIN}};
-              break;
+              case kUsePIN:
+                // A single prompt to get the PIN is expected.
+                test_client_.expected = {{8, kTestPIN}};
+                break;
 
-            default:
-              NOTREACHED();
-          }
+              default:
+                NOTREACHED();
+            }
 
-          GetAssertionResult result = AuthenticatorGetAssertion(
-              get_credential_options(kUVLevel[uv_level]));
+            GetAssertionResult result = AuthenticatorGetAssertion(
+                get_credential_options(kUVLevel[uv_level]));
 
-          switch (expected[support_level][uv_level]) {
-            case kFailure:
-              EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, result.status);
-              break;
+            switch (expected[support_level][uv_level]) {
+              case kFailure:
+                EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR,
+                          result.status);
+                break;
 
-            case kNoPIN:
-              EXPECT_EQ(AuthenticatorStatus::SUCCESS, result.status);
-              EXPECT_FALSE(HasUV(result.response));
-              break;
+              case kNoPIN:
+                EXPECT_EQ(AuthenticatorStatus::SUCCESS, result.status);
+                EXPECT_FALSE(HasUV(result.response));
+                break;
 
-            case kUsePIN:
-              EXPECT_EQ(AuthenticatorStatus::SUCCESS, result.status);
-              EXPECT_EQ(kTestPIN,
-                        virtual_device_factory_->mutable_state()->pin);
-              EXPECT_TRUE(HasUV(result.response));
-              break;
+              case kUsePIN:
+                EXPECT_EQ(AuthenticatorStatus::SUCCESS, result.status);
+                EXPECT_EQ(kTestPIN,
+                          virtual_device_factory_->mutable_state()->pin);
+                EXPECT_TRUE(HasUV(result.response));
+                break;
 
-            default:
-              NOTREACHED();
+              default:
+                NOTREACHED();
+            }
           }
         }
       }
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index ff3e49c..9d93c4f 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -261,8 +261,6 @@
     {wf::EnableAutoplayIgnoresWebAudio, media::kAutoplayIgnoreWebAudio},
     {wf::EnablePortals, blink::features::kPortals, kSetOnlyIfOverridden},
     {wf::EnableImplicitRootScroller, blink::features::kImplicitRootScroller},
-    {wf::EnableCSSOMViewScrollCoordinates,
-     blink::features::kCSSOMViewScrollCoordinates},
     {wf::EnableTextFragmentAnchor, blink::features::kTextFragmentAnchor},
     {wf::EnableBackgroundFetch, features::kBackgroundFetch},
     {wf::EnableForcedColors, features::kForcedColors},
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index 5f81954..8d9d112 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -148,6 +148,10 @@
   // Associated RenderProcessHost never changes.
   virtual RenderProcessHost* GetProcess() = 0;
 
+  // Returns the GlobalFrameRoutingId for this frame. Embedders should store
+  // this instead of a raw RenderFrameHost pointer.
+  virtual GlobalFrameRoutingId GetGlobalFrameRoutingId() = 0;
+
   // Returns a StoragePartition associated with this RenderFrameHost.
   // Associated StoragePartition never changes.
   virtual StoragePartition* GetStoragePartition() = 0;
diff --git a/content/public/renderer/pepper_plugin_instance.h b/content/public/renderer/pepper_plugin_instance.h
index e3bef985..d346ac65 100644
--- a/content/public/renderer/pepper_plugin_instance.h
+++ b/content/public/renderer/pepper_plugin_instance.h
@@ -93,15 +93,6 @@
   // or embedded in a page).
   virtual bool IsFullPagePlugin() = 0;
 
-  // Switches between fullscreen and normal mode. If |delay_report| is set to
-  // false, it may report the new state through DidChangeView immediately. If
-  // true, it will delay it. When called from the plugin, delay_report should
-  // be true to avoid re-entrancy. Returns true if the switch will be carried
-  // out, because of this call or because a switch was pending already anyway.
-  // Returns false if the switch will not be carried out because fullscreen mode
-  // is disallowed by a preference.
-  virtual bool FlashSetFullscreen(bool fullscreen, bool delay_report) = 0;
-
   virtual bool IsRectTopmost(const gfx::Rect& rect) = 0;
 
   virtual int32_t Navigate(const ppapi::URLRequestInfoData& request,
diff --git a/content/public/test/fake_pepper_plugin_instance.cc b/content/public/test/fake_pepper_plugin_instance.cc
index 5492c90..49e35c49 100644
--- a/content/public/test/fake_pepper_plugin_instance.cc
+++ b/content/public/test/fake_pepper_plugin_instance.cc
@@ -55,11 +55,6 @@
   return false;
 }
 
-bool FakePepperPluginInstance::FlashSetFullscreen(bool fullscreen,
-                                                  bool delay_report) {
-  return false;
-}
-
 bool FakePepperPluginInstance::IsRectTopmost(const gfx::Rect& rect) {
   return false;
 }
diff --git a/content/public/test/fake_pepper_plugin_instance.h b/content/public/test/fake_pepper_plugin_instance.h
index 877d3691..c75baa28 100644
--- a/content/public/test/fake_pepper_plugin_instance.h
+++ b/content/public/test/fake_pepper_plugin_instance.h
@@ -34,7 +34,6 @@
       int plugin_child_id) override;
   void SetAlwaysOnTop(bool on_top) override;
   bool IsFullPagePlugin() override;
-  bool FlashSetFullscreen(bool fullscreen, bool delay_report) override;
   bool IsRectTopmost(const gfx::Rect& rect) override;
   int32_t Navigate(const ppapi::URLRequestInfoData& request,
                    const char* target,
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 6434741..6a5a043 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -457,7 +457,6 @@
       "pepper/content_renderer_pepper_host_factory.h",
       "pepper/event_conversion.cc",
       "pepper/event_conversion.h",
-      "pepper/fullscreen_container.h",
       "pepper/gfx_conversion.h",
       "pepper/host_array_buffer_var.cc",
       "pepper/host_array_buffer_var.h",
@@ -580,8 +579,6 @@
       "pepper/video_decoder_shim.h",
       "pepper/video_encoder_shim.cc",
       "pepper/video_encoder_shim.h",
-      "render_widget_fullscreen_pepper.cc",
-      "render_widget_fullscreen_pepper.h",
     ]
 
     deps += [
diff --git a/content/renderer/pepper/fullscreen_container.h b/content/renderer/pepper/fullscreen_container.h
deleted file mode 100644
index 4e8614d..0000000
--- a/content/renderer/pepper/fullscreen_container.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_PEPPER_FULLSCREEN_CONTAINER_H_
-#define CONTENT_RENDERER_PEPPER_FULLSCREEN_CONTAINER_H_
-
-#include "base/memory/ref_counted.h"
-
-namespace cc {
-class Layer;
-}
-
-namespace ui {
-class Cursor;
-}
-
-namespace content {
-
-// This class is like a lightweight WebPluginContainer for fullscreen PPAPI
-// plugins, that only handles painting.
-class FullscreenContainer {
- public:
-  // Destroys the fullscreen window. This also destroys the FullscreenContainer
-  // instance.
-  virtual void Destroy() = 0;
-
-  // Notifies the container that the mouse cursor has changed.
-  virtual void PepperDidChangeCursor(const ui::Cursor& cursor) = 0;
-
-  virtual void SetLayer(scoped_refptr<cc::Layer> layer) = 0;
-
- protected:
-  virtual ~FullscreenContainer() {}
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_PEPPER_FULLSCREEN_CONTAINER_H_
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index b827ec2..9277824 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -29,7 +29,6 @@
 #include "content/public/common/use_zoom_for_dsf_policy.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/renderer/pepper/event_conversion.h"
-#include "content/renderer/pepper/fullscreen_container.h"
 #include "content/renderer/pepper/gfx_conversion.h"
 #include "content/renderer/pepper/host_dispatcher_wrapper.h"
 #include "content/renderer/pepper/host_globals.h"
@@ -55,7 +54,6 @@
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
 #include "content/renderer/render_widget.h"
-#include "content/renderer/render_widget_fullscreen_pepper.h"
 #include "content/renderer/sad_plugin.h"
 #include "device/gamepad/public/cpp/gamepads.h"
 #include "ppapi/c/dev/ppp_text_input_dev.h"
@@ -504,7 +502,6 @@
       graphics2d_translation_(0, 0),
       graphics2d_scale_(1.f),
       container_(container),
-      layer_bound_to_fullscreen_(false),
       layer_is_hardware_(false),
       plugin_url_(plugin_url),
       document_url_(container ? GURL(container->GetDocument().Url()) : GURL()),
@@ -529,8 +526,6 @@
       uma_private_impl_(nullptr),
       plugin_print_interface_(nullptr),
       always_on_top_(false),
-      fullscreen_container_(nullptr),
-      flash_fullscreen_(false),
       desired_fullscreen_state_(false),
       message_channel_(nullptr),
       input_event_mask_(0),
@@ -576,8 +571,6 @@
 }
 
 PepperPluginInstanceImpl::~PepperPluginInstanceImpl() {
-  DCHECK(!fullscreen_container_);
-
   // Notify all the plugin objects of deletion. This will prevent blink from
   // calling into the plugin any more.
   //
@@ -687,11 +680,6 @@
   original_instance_interface_.reset();
   instance_interface_.reset();
 
-  if (fullscreen_container_) {
-    fullscreen_container_->Destroy();
-    fullscreen_container_ = nullptr;
-  }
-
   // Force-unbind any Graphics. In the case of Graphics2D, if the plugin
   // leaks the graphics 2D, it may actually get cleaned up after our
   // destruction, so we need its pointers to be up to date.
@@ -724,18 +712,13 @@
 }
 
 void PepperPluginInstanceImpl::InvalidateRect(const gfx::Rect& rect) {
-  if (fullscreen_container_) {
-    // The fullscreen container uses a composited layer, which we invalidate
-    // directly below via SetNeedsDisplay().
-  } else {
-    if (!container_ || view_data_.rect.size.width == 0 ||
-        view_data_.rect.size.height == 0)
-      return;  // Nothing to do.
-    if (rect.IsEmpty())
-      container_->Invalidate();
-    else
-      container_->InvalidateRect(rect);
-  }
+  if (!container_ || view_data_.rect.size.width == 0 ||
+      view_data_.rect.size.height == 0)
+    return;  // Nothing to do.
+  if (rect.IsEmpty())
+    container_->Invalidate();
+  else
+    container_->InvalidateRect(rect);
 
   if (texture_layer_) {
     if (rect.IsEmpty()) {
@@ -811,7 +794,6 @@
 
   // Free any associated graphics.
   SetFullscreen(false);
-  FlashSetFullscreen(false, false);
   // Unbind current 2D or 3D graphics context.
   BindGraphics(pp_instance(), 0);
   InvalidateRect(gfx::Rect());
@@ -1303,8 +1285,6 @@
     }
   }
 
-  UpdateFlashFullscreenState(fullscreen_container_ != nullptr);
-
   // During plugin initialization, there are often re-layouts. Avoid sending
   // intermediate sizes the plugin and throttler.
   if (sent_initial_did_change_view_)
@@ -1717,7 +1697,7 @@
 }
 
 bool PepperPluginInstanceImpl::PluginHasFocus() const {
-  return flash_fullscreen_ || has_webkit_focus_;
+  return has_webkit_focus_;
 }
 
 void PepperPluginInstanceImpl::SendFocusChangeNotification() {
@@ -1859,7 +1839,7 @@
   // If this call was delayed, we may have transitioned back to fullscreen in
   // the mean time, so only report the geometry if we are actually in normal
   // mode.
-  if (container_ && !fullscreen_container_ && !flash_fullscreen_)
+  if (container_)
     container_->ReportGeometry();
 }
 
@@ -2049,10 +2029,6 @@
   // NOTE: plugin instance may have been deleted.
 }
 
-bool PepperPluginInstanceImpl::FlashIsFullscreenOrPending() {
-  return fullscreen_container_ != nullptr;
-}
-
 bool PepperPluginInstanceImpl::IsFullscreenOrPending() {
   return desired_fullscreen_state_;
 }
@@ -2067,9 +2043,20 @@
   if (fullscreen == IsFullscreenOrPending())
     return false;
 
-  if (!SetFullscreenCommon(fullscreen))
+  if (!render_frame_)
     return false;
 
+  if (fullscreen) {
+    if (!render_frame_->render_view()
+             ->renderer_preferences()
+             .plugin_fullscreen_allowed) {
+      return false;
+    }
+
+    if (!HasTransientUserActivation())
+      return false;
+  }
+
   // Check whether we are trying to switch while the state is in transition.
   // The 2nd request gets dropped while messing up the internal state, so
   // disallow this.
@@ -2091,36 +2078,6 @@
   return true;
 }
 
-void PepperPluginInstanceImpl::UpdateFlashFullscreenState(
-    bool flash_fullscreen) {
-  bool is_mouselock_pending = TrackedCallback::IsPending(lock_mouse_callback_);
-
-  if (flash_fullscreen == flash_fullscreen_) {
-    // Manually clear callback when fullscreen fails with mouselock pending.
-    if (!flash_fullscreen && is_mouselock_pending)
-      lock_mouse_callback_->Run(PP_ERROR_FAILED);
-    return;
-  }
-
-  UpdateLayer(false);
-
-  bool old_plugin_focus = PluginHasFocus();
-  flash_fullscreen_ = flash_fullscreen;
-  if (is_mouselock_pending && !IsMouseLocked()) {
-    if (!HasTransientUserActivation() &&
-        !module_->permissions().HasPermission(
-            ppapi::PERMISSION_BYPASS_USER_GESTURE)) {
-      lock_mouse_callback_->Run(PP_ERROR_NO_USER_GESTURE);
-    } else {
-      if (!LockMouse(/*request_unadjusted_movement=*/false))
-        lock_mouse_callback_->Run(PP_ERROR_FAILED);
-    }
-  }
-
-  if (PluginHasFocus() != old_plugin_focus)
-    SendFocusChangeNotification();
-}
-
 void PepperPluginInstanceImpl::UpdateLayer(bool force_creation) {
   if (!container_)
     return;
@@ -2136,17 +2093,13 @@
   }
 
   if (!force_creation && (want_texture_layer == !!texture_layer_) &&
-      (want_3d_layer == layer_is_hardware_) &&
-      layer_bound_to_fullscreen_ == !!fullscreen_container_) {
+      (want_3d_layer == layer_is_hardware_)) {
     UpdateLayerTransform();
     return;
   }
 
   if (texture_layer_) {
-    if (!layer_bound_to_fullscreen_)
-      container_->SetCcLayer(nullptr, false);
-    else if (fullscreen_container_)
-      fullscreen_container_->SetLayer(nullptr);
+    container_->SetCcLayer(nullptr, false);
     texture_layer_->ClearClient();
     texture_layer_ = nullptr;
   }
@@ -2170,20 +2123,15 @@
     // Ignore transparency in fullscreen, since that's what Flash always
     // wants to do, and that lets it not recreate a context if
     // wmode=transparent was specified.
-    opaque = opaque || fullscreen_container_;
     texture_layer_->SetContentsOpaque(opaque);
   }
 
   if (texture_layer_) {
-    if (fullscreen_container_)
-      fullscreen_container_->SetLayer(texture_layer_);
-    else
-      container_->SetCcLayer(texture_layer_.get(), true);
+    container_->SetCcLayer(texture_layer_.get(), true);
     if (is_flash_plugin_)
       texture_layer_->SetMayContainVideo(true);
   }
 
-  layer_bound_to_fullscreen_ = !!fullscreen_container_;
   layer_is_hardware_ = want_3d_layer;
   UpdateLayerTransform();
 }
@@ -2364,10 +2312,8 @@
     return PP_TRUE;
   }
 
-  // Refuse to bind if in transition to fullscreen with PPB_FlashFullscreen or
-  // to/from fullscreen with PPB_Fullscreen.
-  if ((fullscreen_container_ && !flash_fullscreen_) ||
-      desired_fullscreen_state_ != view_data_.is_fullscreen)
+  // Refuse to bind if in transition to/from fullscreen with PPB_Fullscreen.
+  if (desired_fullscreen_state_ != view_data_.is_fullscreen)
     return PP_FALSE;
 
   const ppapi::host::PpapiHost* ppapi_host =
@@ -2420,10 +2366,6 @@
   return &view_data_;
 }
 
-PP_Bool PepperPluginInstanceImpl::FlashIsFullscreen(PP_Instance instance) {
-  return PP_FromBool(flash_fullscreen_);
-}
-
 PP_Var PepperPluginInstanceImpl::GetWindowObject(PP_Instance instance) {
   if (!container_)
     return PP_MakeUndefined();
@@ -2595,23 +2537,13 @@
 
 PP_Bool PepperPluginInstanceImpl::GetScreenSize(PP_Instance instance,
                                                 PP_Size* size) {
-  if (flash_fullscreen_) {
-    // Workaround for Flash rendering bug: Flash is assuming the fullscreen view
-    // size will be equal to the physical screen size.  However, the fullscreen
-    // view is sized by the browser UI, and may not be the same size as the
-    // screen or the desktop.  Therefore, report the view size as the screen
-    // size when in fullscreen mode.  http://crbug.com/506016
-    // TODO(miu): Remove this workaround once Flash has been fixed.
-    *size = view_data_.rect.size;
-  } else {
-    // All other cases: Report the screen size.
-    if (!render_frame_)
-      return PP_FALSE;
-    blink::ScreenInfo info = render_frame_->GetLocalRootRenderWidget()
-                                 ->GetWebWidget()
-                                 ->GetScreenInfo();
-    *size = PP_MakeSize(info.rect.width(), info.rect.height());
-  }
+  // All other cases: Report the screen size.
+  if (!render_frame_)
+    return PP_FALSE;
+  blink::ScreenInfo info = render_frame_->GetLocalRootRenderWidget()
+                               ->GetWebWidget()
+                               ->GetScreenInfo();
+  *size = PP_MakeSize(info.rect.width(), info.rect.height());
   return PP_TRUE;
 }
 
@@ -2736,13 +2668,6 @@
   if (!HasTransientUserActivation())
     return PP_ERROR_NO_USER_GESTURE;
 
-  // Attempt mouselock only if Flash isn't waiting on fullscreen, otherwise
-  // we wait and call LockMouse() in UpdateFlashFullscreenState().
-  if (!FlashIsFullscreenOrPending() || flash_fullscreen_) {
-    if (!LockMouse(false))
-      return PP_ERROR_FAILED;
-  }
-
   // Either mouselock succeeded or a Flash fullscreen is pending.
   lock_mouse_callback_ = callback;
   return PP_OK_COMPLETIONPENDING;
@@ -3037,9 +2962,7 @@
     return;
 
   cursor_ = std::move(cursor);
-  if (fullscreen_container_) {
-    fullscreen_container_->PepperDidChangeCursor(*cursor_);
-  } else if (render_frame_) {
+  if (render_frame_) {
     // Update the cursor appearance immediately if the requesting plugin is the
     // one which receives the last mouse event. Otherwise, the new cursor won't
     // be picked up until the plugin gets the next input event. That is bad if,
@@ -3062,49 +2985,7 @@
              .IsPluginDocument();
 }
 
-bool PepperPluginInstanceImpl::FlashSetFullscreen(bool fullscreen,
-                                                  bool delay_report) {
-  TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::FlashSetFullscreen");
-  // Keep a reference on the stack. See NOTE above.
-  scoped_refptr<PepperPluginInstanceImpl> ref(this);
-
-  // We check whether we are trying to switch to the state we're already going
-  // to (i.e. if we're already switching to fullscreen but the fullscreen
-  // container isn't ready yet, don't do anything more).
-  if (fullscreen == FlashIsFullscreenOrPending())
-    return true;
-
-  if (!SetFullscreenCommon(fullscreen))
-    return false;
-
-  // Unbind current 2D or 3D graphics context.
-  DVLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off");
-  if (fullscreen) {
-    DCHECK(!fullscreen_container_);
-    fullscreen_container_ =
-        render_frame_->CreatePepperFullscreenContainer(this);
-    UpdateLayer(false);
-  } else {
-    DCHECK(fullscreen_container_);
-    fullscreen_container_->Destroy();
-    fullscreen_container_ = nullptr;
-    UpdateFlashFullscreenState(false);
-    if (!delay_report) {
-      ReportGeometry();
-    } else {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::BindOnce(&PepperPluginInstanceImpl::ReportGeometry, this));
-    }
-  }
-
-  return true;
-}
-
 bool PepperPluginInstanceImpl::IsRectTopmost(const gfx::Rect& rect) {
-  if (flash_fullscreen_)
-    return true;
-
   return container_->IsRectTopmost(rect);
 }
 
@@ -3239,23 +3120,6 @@
   element.SetAttribute(WebString::FromUTF8(kStyle), style_before_fullscreen_);
 }
 
-bool PepperPluginInstanceImpl::SetFullscreenCommon(bool fullscreen) const {
-  if (!render_frame_)
-    return false;
-
-  if (fullscreen) {
-    if (!render_frame_->render_view()
-             ->renderer_preferences()
-             .plugin_fullscreen_allowed) {
-      return false;
-    }
-
-    if (!HasTransientUserActivation())
-      return false;
-  }
-  return true;
-}
-
 bool PepperPluginInstanceImpl::IsMouseLocked() {
   return GetMouseLockDispatcher()->IsMouseLockedTo(
       GetOrCreateLockTargetAdapter());
@@ -3277,11 +3141,6 @@
 }
 
 MouseLockDispatcher* PepperPluginInstanceImpl::GetMouseLockDispatcher() {
-  if (flash_fullscreen_) {
-    RenderWidgetFullscreenPepper* container =
-        static_cast<RenderWidgetFullscreenPepper*>(fullscreen_container_);
-    return container->mouse_lock_dispatcher();
-  }
   if (render_frame_)
     return render_frame_->GetLocalRootRenderWidget()->mouse_lock_dispatcher();
   return nullptr;
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h
index fbd7512..04715d77b 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.h
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.h
@@ -104,7 +104,6 @@
 
 namespace content {
 
-class FullscreenContainer;
 class MessageChannel;
 class PepperAudioController;
 class PepperGraphics2DHost;
@@ -279,38 +278,6 @@
   bool CanRotateView();
   void RotateView(blink::WebPlugin::RotationType type);
 
-  // There are 2 implementations of the fullscreen interface
-  // PPB_FlashFullscreen is used by Pepper Flash.
-  // PPB_Fullscreen is intended for other applications including NaCl.
-  // The two interface are mutually exclusive.
-
-  // Implementation of PPB_FlashFullscreen.
-
-  // Because going to fullscreen is asynchronous (but going out is not), there
-  // are 3 states:
-  // - normal            : fullscreen_container_ == NULL
-  //                       flash_fullscreen_ == false
-  // - fullscreen pending: fullscreen_container_ != NULL
-  //                       flash_fullscreen_ == false
-  // - fullscreen        : fullscreen_container_ != NULL
-  //                       flash_fullscreen_ == true
-  //
-  // In normal state, events come from webkit and painting goes back to it.
-  // In fullscreen state, events come from the fullscreen container, and
-  // painting goes back to it.
-  // In pending state, events from webkit are ignored, and as soon as we
-  // receive events from the fullscreen container, we go to the fullscreen
-  // state.
-  bool FlashIsFullscreenOrPending();
-
-  // Updates |flash_fullscreen_| and sends focus change notification if
-  // necessary.
-  void UpdateFlashFullscreenState(bool flash_fullscreen);
-
-  FullscreenContainer* fullscreen_container() const {
-    return fullscreen_container_;
-  }
-
   // Implementation of PPB_Fullscreen.
 
   // Because going to/from fullscreen is asynchronous, there are 4 states:
@@ -324,8 +291,6 @@
   //                       view_data_.is_fullscreen = true
   bool IsFullscreenOrPending();
 
-  bool flash_fullscreen() const { return flash_fullscreen_; }
-
   // Switches between fullscreen and normal mode. The transition is
   // asynchronous. WebKit will trigger corresponding ViewChanged calls.  Returns
   // true on success, false on failure (e.g. trying to enter fullscreen without
@@ -391,7 +356,6 @@
       int plugin_child_id) override;
   void SetAlwaysOnTop(bool on_top) override;
   bool IsFullPagePlugin() override;
-  bool FlashSetFullscreen(bool fullscreen, bool delay_report) override;
   bool IsRectTopmost(const gfx::Rect& rect) override;
   int32_t Navigate(const ppapi::URLRequestInfoData& request,
                    const char* target,
@@ -421,7 +385,6 @@
   PP_Bool BindGraphics(PP_Instance instance, PP_Resource device) override;
   PP_Bool IsFullFrame(PP_Instance instance) override;
   const ppapi::ViewData* GetViewData(PP_Instance instance) override;
-  PP_Bool FlashIsFullscreen(PP_Instance instance) override;
   PP_Var GetWindowObject(PP_Instance instance) override;
   PP_Var GetOwnerElementObject(PP_Instance instance) override;
   PP_Var ExecuteScript(PP_Instance instance,
@@ -645,9 +608,6 @@
   void SetSizeAttributesForFullscreen();
   void ResetSizeAttributesAfterFullscreen();
 
-  // Shared code between SetFullscreen() and FlashSetFullscreen().
-  bool SetFullscreenCommon(bool fullscreen) const;
-
   bool IsMouseLocked();
   bool LockMouse(bool request_unadjusted_movement);
   MouseLockDispatcher* GetMouseLockDispatcher();
@@ -704,7 +664,6 @@
   // NULL until we have been initialized.
   blink::WebPluginContainer* container_;
   scoped_refptr<cc::TextureLayer> texture_layer_;
-  bool layer_bound_to_fullscreen_;
   bool layer_is_hardware_;
 
   // Plugin URL.
@@ -801,18 +760,6 @@
   // to use a more optimized painting path in some cases.
   bool always_on_top_;
 
-  // Implementation of PPB_FlashFullscreen.
-
-  // Plugin container for fullscreen mode. NULL if not in fullscreen mode. Note:
-  // there is a transition state where fullscreen_container_ is non-NULL but
-  // flash_fullscreen_ is false (see above).
-  FullscreenContainer* fullscreen_container_;
-
-  // True if we are in "flash" fullscreen mode. False if we are in normal mode
-  // or in transition to fullscreen. Normal fullscreen mode is indicated in
-  // the ViewData.
-  bool flash_fullscreen_;
-
   // Implementation of PPB_Fullscreen.
 
   // Since entering fullscreen mode is an asynchronous operation, we set this
diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc
index 3306935..7da0d05 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.cc
+++ b/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -199,7 +199,7 @@
 void PepperWebPluginImpl::Paint(cc::PaintCanvas* canvas, const WebRect& rect) {
   // Re-entrancy may cause JS to try to execute script on the plugin before it
   // is fully initialized. See: crbug.com/715747.
-  if (instance_ && !instance_->FlashIsFullscreenOrPending())
+  if (instance_)
     instance_->Paint(canvas, plugin_rect_, rect);
 }
 
@@ -209,7 +209,7 @@
     const WebRect& unobscured_rect,
     bool is_visible) {
   plugin_rect_ = window_rect;
-  if (instance_ && !instance_->FlashIsFullscreenOrPending())
+  if (instance_)
     instance_->ViewChanged(plugin_rect_, clip_rect, unobscured_rect);
 }
 
@@ -253,7 +253,7 @@
     ui::Cursor* cursor) {
   // Re-entrancy may cause JS to try to execute script on the plugin before it
   // is fully initialized. See: crbug.com/715747.
-  if (!instance_ || instance_->FlashIsFullscreenOrPending())
+  if (!instance_)
     return blink::WebInputEventResult::kNotHandled;
   return instance_->HandleCoalescedInputEvent(coalesced_event, cursor)
              ? blink::WebInputEventResult::kHandledApplication
diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.cc b/content/renderer/pepper/renderer_ppapi_host_impl.cc
index c01b42d..db3962ac 100644
--- a/content/renderer/pepper/renderer_ppapi_host_impl.cc
+++ b/content/renderer/pepper/renderer_ppapi_host_impl.cc
@@ -11,7 +11,6 @@
 #include "base/process/process_handle.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "content/renderer/pepper/fullscreen_container.h"
 #include "content/renderer/pepper/host_globals.h"
 #include "content/renderer/pepper/pepper_browser_connection.h"
 #include "content/renderer/pepper/pepper_graphics_2d_host.h"
@@ -20,7 +19,6 @@
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
 #include "content/renderer/pepper/plugin_module.h"
 #include "content/renderer/render_view_impl.h"
-#include "content/renderer/render_widget_fullscreen_pepper.h"
 #include "ipc/ipc_message.h"
 #include "ipc/ipc_platform_file.h"
 #include "ppapi/host/ppapi_host.h"
@@ -192,10 +190,6 @@
   PepperPluginInstanceImpl* plugin_instance = GetAndValidateInstance(instance);
   if (!plugin_instance)
     return 0;
-  if (plugin_instance->flash_fullscreen()) {
-    FullscreenContainer* container = plugin_instance->fullscreen_container();
-    return static_cast<RenderWidgetFullscreenPepper*>(container)->routing_id();
-  }
   return GetRenderViewForInstance(instance)->GetRoutingID();
 }
 
@@ -203,11 +197,8 @@
     PP_Instance instance,
     const gfx::Point& pt) {
   PepperPluginInstanceImpl* plugin_instance = GetAndValidateInstance(instance);
-  if (!plugin_instance || plugin_instance->flash_fullscreen()) {
-    // Flash fullscreen is special in that it renders into its own separate,
-    // dedicated window.  So, do not offset the point.
+  if (!plugin_instance)
     return pt;
-  }
   return gfx::Point((pt.x() + plugin_instance->view_data().rect.point.x) /
                         viewport_to_dip_scale_,
                     (pt.y() + plugin_instance->view_data().rect.point.y) /
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 3b2626c..b0a4392 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -119,7 +119,6 @@
 #include "content/renderer/render_process.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
-#include "content/renderer/render_widget_fullscreen_pepper.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
 #include "content/renderer/service_worker/service_worker_network_provider_for_frame.h"
 #include "content/renderer/service_worker/web_service_worker_provider_impl.h"
@@ -2176,49 +2175,6 @@
   SyncSelectionIfRequired();
 }
 
-RenderWidgetFullscreenPepper* RenderFrameImpl::CreatePepperFullscreenContainer(
-    PepperPluginInstanceImpl* plugin) {
-  // Get the URL of the main frame if possible.
-  blink::WebURL main_frame_url;
-  WebFrame* main_frame = render_view()->GetWebView()->MainFrame();
-  if (main_frame->IsWebLocalFrame())
-    main_frame_url = main_frame->ToWebLocalFrame()->GetDocument().Url();
-
-  mojo::PendingAssociatedRemote<blink::mojom::Widget> blink_widget;
-  mojo::PendingAssociatedReceiver<blink::mojom::Widget> blink_widget_receiver =
-      blink_widget.InitWithNewEndpointAndPassReceiver();
-
-  mojo::PendingAssociatedRemote<blink::mojom::WidgetHost> blink_widget_host;
-  mojo::PendingAssociatedReceiver<blink::mojom::WidgetHost>
-      blink_widget_host_receiver =
-          blink_widget_host.InitWithNewEndpointAndPassReceiver();
-
-  // Synchronous IPC to obtain a routing id for the fullscreen widget.
-  int32_t fullscreen_widget_routing_id = MSG_ROUTING_NONE;
-  if (!GetFrameHost()->CreateNewFullscreenWidget(
-          std::move(blink_widget_host_receiver), std::move(blink_widget),
-          &fullscreen_widget_routing_id)) {
-    return nullptr;
-  }
-  RenderWidget::ShowCallback show_callback =
-      base::BindOnce(&RenderViewImpl::ShowCreatedFullscreenWidget,
-                     render_view()->GetWeakPtr());
-
-  RenderWidgetFullscreenPepper* widget = RenderWidgetFullscreenPepper::Create(
-      agent_scheduling_group_, fullscreen_widget_routing_id,
-      std::move(show_callback), GetLocalRootRenderWidget()->compositor_deps(),
-      GetLocalRootRenderWidget()->GetWebWidget()->GetOriginalScreenInfo(),
-      plugin, std::move(main_frame_url), std::move(blink_widget_host),
-      std::move(blink_widget_receiver));
-  // TODO(nick): The show() handshake seems like unnecessary complexity here,
-  // since there's no real delay between CreateFullscreenWidget and
-  // ShowCreatedFullscreenWidget. Would it be simpler to have the
-  // CreateFullscreenWidget mojo method implicitly show the window, and skip the
-  // subsequent step?
-  widget->Show(blink::kWebNavigationPolicyCurrentTab);
-  return widget;
-}
-
 bool RenderFrameImpl::IsPepperAcceptingCompositionEvents() const {
   if (!focused_pepper_plugin_)
     return false;
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 7c18f07..c8620c02 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -161,7 +161,6 @@
 class RenderFrameObserver;
 class RenderViewImpl;
 class RenderWidget;
-class RenderWidgetFullscreenPepper;
 struct CustomContextMenuContext;
 struct FrameReplicationState;
 
@@ -353,10 +352,6 @@
   // Informs the render view that a PPAPI plugin has changed selection.
   void PepperSelectionChanged(PepperPluginInstanceImpl* instance);
 
-  // Creates a fullscreen container for a pepper plugin instance.
-  RenderWidgetFullscreenPepper* CreatePepperFullscreenContainer(
-      PepperPluginInstanceImpl* plugin);
-
   bool IsPepperAcceptingCompositionEvents() const;
 
   // Notification that the given plugin has crashed.
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index fec5e231..e74bd8f 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -70,7 +70,6 @@
 #include "content/renderer/render_frame_proxy.h"
 #include "content/renderer/render_process.h"
 #include "content/renderer/render_thread_impl.h"
-#include "content/renderer/render_widget_fullscreen_pepper.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
 #include "content/renderer/v8_value_converter_impl.h"
 #include "content/renderer/web_ui_extension_data.h"
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 1e83fdb..bdd9dfa0 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -264,14 +264,6 @@
   Initialize(std::move(show_callback), web_page_popup, screen_info);
 }
 
-void RenderWidget::InitForPepperFullscreen(
-    ShowCallback show_callback,
-    blink::WebWidget* web_widget,
-    const blink::ScreenInfo& screen_info) {
-  for_pepper_fullscreen_ = true;
-  Initialize(std::move(show_callback), web_widget, screen_info);
-}
-
 void RenderWidget::InitForMainFrame(ShowCallback show_callback,
                                     blink::WebFrameWidget* web_frame_widget,
                                     const blink::ScreenInfo& screen_info,
@@ -357,7 +349,7 @@
 }
 
 void RenderWidget::OnClose() {
-  DCHECK(for_popup_ || for_pepper_fullscreen_);
+  DCHECK(for_popup_);
 
   Close(base::WrapUnique(this));
 }
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 493b515..30f7c2c 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -89,7 +89,6 @@
 //
 // RenderWidget is used to implement:
 // - RenderViewImpl (deprecated)
-// - Fullscreen mode (RenderWidgetFullScreen)
 // - Popup "menus" (like the color chooser and date picker)
 // - Widgets for frames (the main frame, and subframes due to out-of-process
 //   iframe support)
@@ -161,12 +160,6 @@
                     blink::WebPagePopup* web_page_popup,
                     const blink::ScreenInfo& screen_info);
 
-  // Initialize a new RenderWidget for pepper fullscreen. The |show_callback| is
-  // called when RenderWidget::Show() happens.
-  void InitForPepperFullscreen(ShowCallback show_callback,
-                               blink::WebWidget* web_widget,
-                               const blink::ScreenInfo& screen_info);
-
   // Initialize a new RenderWidget that will be attached to a RenderFrame (via
   // the WebFrameWidget), for a frame that is a main frame.
   void InitForMainFrame(ShowCallback show_callback,
@@ -335,8 +328,7 @@
   // Returns the WebFrameWidget associated with this RenderWidget if any.
   // Returns nullptr if GetWebWidget() returns nullptr or returns a WebWidget
   // that is not a WebFrameWidget. A WebFrameWidget only makes sense when there
-  // a local root associated with it. RenderWidgetFullscreenPepper and a swapped
-  // out RenderWidgets are amongst the cases where this method returns nullptr.
+  // a local root associated with it.
   blink::WebFrameWidget* GetFrameWidget() const;
 
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -401,13 +393,12 @@
   // that are not for a frame (eg popups) and excludes the widget for the main
   // frame (which is attached to the RenderViewImpl).
   bool for_child_local_root_frame_ = false;
-  // RenderWidgets are created for frames, popups and pepper fullscreen. In the
+  // RenderWidgets are created for frames and  popups. In the
   // former case, the caller frame takes ownership and eventually passes the
   // unique_ptr back in Close(). In the latter cases, the browser process takes
   // ownership via IPC.  These booleans exist to allow us to confirm than an IPC
-  // message to kill the render widget is coming for a popup or fullscreen.
+  // message to kill the render widget is coming for a popup.
   bool for_popup_ = false;
-  bool for_pepper_fullscreen_ = false;
 
   // A callback into the creator/opener of this widget, to be executed when
   // WebWidgetClient::Show() occurs.
diff --git a/content/renderer/render_widget_fullscreen_pepper.cc b/content/renderer/render_widget_fullscreen_pepper.cc
deleted file mode 100644
index eb8e7fa..0000000
--- a/content/renderer/render_widget_fullscreen_pepper.cc
+++ /dev/null
@@ -1,370 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/render_widget_fullscreen_pepper.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "cc/paint/paint_canvas.h"
-#include "content/common/view_messages.h"
-#include "content/common/widget_messages.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/use_zoom_for_dsf_policy.h"
-#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
-#include "content/renderer/render_thread_impl.h"
-#include "gpu/ipc/client/gpu_channel_host.h"
-#include "skia/ext/platform_canvas.h"
-#include "third_party/blink/public/common/input/web_gesture_event.h"
-#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
-#include "third_party/blink/public/platform/web_size.h"
-#include "third_party/blink/public/web/web_local_frame.h"
-#include "third_party/blink/public/web/web_widget.h"
-#include "ui/base/cursor/cursor.h"
-#include "ui/gfx/geometry/dip_util.h"
-#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gl/gpu_preference.h"
-
-using blink::WebCoalescedInputEvent;
-using blink::WebGestureEvent;
-using blink::WebInputEvent;
-using blink::WebInputEventResult;
-using blink::WebMouseEvent;
-using blink::WebMouseWheelEvent;
-using blink::WebRect;
-using blink::WebSize;
-using blink::WebString;
-using blink::WebTextInputType;
-using blink::WebVector;
-
-namespace content {
-
-namespace {
-
-class FullscreenMouseLockDispatcher : public MouseLockDispatcher {
- public:
-  explicit FullscreenMouseLockDispatcher(RenderWidgetFullscreenPepper* widget);
-  ~FullscreenMouseLockDispatcher() override;
-
- private:
-  // MouseLockDispatcher implementation.
-  void SendLockMouseRequest(blink::WebLocalFrame* requester_frame,
-                            bool request_unadjusted_movement) override;
-
-  RenderWidgetFullscreenPepper* widget_;
-
-  base::WeakPtrFactory<FullscreenMouseLockDispatcher> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(FullscreenMouseLockDispatcher);
-};
-
-WebMouseEvent WebMouseEventFromGestureEvent(const WebGestureEvent& gesture) {
-  // Only convert touch screen gesture events, do not convert
-  // touchpad/mouse wheel gesture events. (crbug.com/620974)
-  if (gesture.SourceDevice() != blink::WebGestureDevice::kTouchscreen)
-    return WebMouseEvent();
-
-  WebInputEvent::Type type = WebInputEvent::Type::kUndefined;
-  switch (gesture.GetType()) {
-    case WebInputEvent::Type::kGestureScrollBegin:
-      type = WebInputEvent::Type::kMouseDown;
-      break;
-    case WebInputEvent::Type::kGestureScrollUpdate:
-      type = WebInputEvent::Type::kMouseMove;
-      break;
-    case WebInputEvent::Type::kGestureFlingStart:
-      // A scroll gesture on the touchscreen may end with a GestureScrollEnd
-      // when there is no velocity, or a GestureFlingStart when it has a
-      // velocity. In both cases, it should end the drag that was initiated by
-      // the GestureScrollBegin (and subsequent GestureScrollUpdate) events.
-      type = WebInputEvent::Type::kMouseUp;
-      break;
-    case WebInputEvent::Type::kGestureScrollEnd:
-      type = WebInputEvent::Type::kMouseUp;
-      break;
-    default:
-      return WebMouseEvent();
-  }
-
-  WebMouseEvent mouse(type,
-                      gesture.GetModifiers() | WebInputEvent::kLeftButtonDown,
-                      gesture.TimeStamp());
-  mouse.button = WebMouseEvent::Button::kLeft;
-  mouse.click_count = (mouse.GetType() == WebInputEvent::Type::kMouseDown ||
-                       mouse.GetType() == WebInputEvent::Type::kMouseUp);
-
-  mouse.SetPositionInWidget(gesture.PositionInWidget());
-  mouse.SetPositionInScreen(gesture.PositionInScreen());
-
-  return mouse;
-}
-
-FullscreenMouseLockDispatcher::FullscreenMouseLockDispatcher(
-    RenderWidgetFullscreenPepper* widget)
-    : widget_(widget) {}
-
-FullscreenMouseLockDispatcher::~FullscreenMouseLockDispatcher() = default;
-
-void FullscreenMouseLockDispatcher::SendLockMouseRequest(
-    blink::WebLocalFrame* requester_frame,
-    bool request_unadjusted_movement) {
-  bool has_transient_user_activation =
-      requester_frame ? requester_frame->HasTransientUserActivation() : false;
-
-  widget_->GetWebWidget()->RequestMouseLock(
-      has_transient_user_activation, /*privileged=*/true,
-      request_unadjusted_movement,
-      base::BindOnce(&MouseLockDispatcher::OnLockMouseACK,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-}  // anonymous namespace
-
-// We place the WebExternalWidgetClient interface on a separate class because
-// RenderWidget implements blink::WebWidgetClient, which is not used for
-// WebExternalWidgets, but may have similar method definitions as this
-// interface.
-class PepperExternalWidgetClient : public blink::WebExternalWidgetClient {
- public:
-  explicit PepperExternalWidgetClient(RenderWidgetFullscreenPepper* widget)
-      : widget_(widget) {}
-  ~PepperExternalWidgetClient() override = default;
-
-  // blink::WebExternalWidgetClient overrides:
-  blink::WebInputEventResult HandleInputEvent(
-      const blink::WebCoalescedInputEvent& event) override {
-    return widget_->ProcessInputEvent(event);
-  }
-
-  blink::WebInputEventResult DispatchBufferedTouchEvents() override {
-    return WebInputEventResult::kNotHandled;
-  }
-
-  void DidResize(const gfx::Size& size) override { widget_->DidResize(size); }
-
-  void RecordTimeToFirstActivePaint(base::TimeDelta duration) override {
-    widget_->RecordTimeToFirstActivePaint(duration);
-  }
-
-  void DidCommitAndDrawCompositorFrame() override {
-    widget_->DidInitiatePaint();
-  }
-
-  void DidUpdateVisualProperties() override { widget_->UpdateLayerBounds(); }
-
- private:
-  RenderWidgetFullscreenPepper* widget_;
-};
-
-// static
-RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create(
-    AgentSchedulingGroup& agent_scheduling_group,
-    int32_t routing_id,
-    RenderWidget::ShowCallback show_callback,
-    CompositorDependencies* compositor_deps,
-    const blink::ScreenInfo& screen_info,
-    PepperPluginInstanceImpl* plugin,
-    const blink::WebURL& local_main_frame_url,
-    mojo::PendingAssociatedRemote<blink::mojom::WidgetHost> blink_widget_host,
-    mojo::PendingAssociatedReceiver<blink::mojom::Widget> blink_widget) {
-  DCHECK_NE(MSG_ROUTING_NONE, routing_id);
-  DCHECK(show_callback);
-  RenderWidgetFullscreenPepper* render_widget =
-      new RenderWidgetFullscreenPepper(
-          agent_scheduling_group, routing_id, compositor_deps, plugin,
-          std::move(blink_widget_host), std::move(blink_widget),
-          local_main_frame_url);
-  render_widget->InitForPepperFullscreen(std::move(show_callback),
-                                         render_widget->blink_widget_.get(),
-                                         screen_info);
-  return render_widget;
-}
-
-RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper(
-    AgentSchedulingGroup& agent_scheduling_group,
-    int32_t routing_id,
-    CompositorDependencies* compositor_deps,
-    PepperPluginInstanceImpl* plugin,
-    mojo::PendingAssociatedRemote<blink::mojom::WidgetHost> mojo_widget_host,
-    mojo::PendingAssociatedReceiver<blink::mojom::Widget> mojo_widget,
-    blink::WebURL main_frame_url)
-    : RenderWidget(agent_scheduling_group, routing_id, compositor_deps),
-      plugin_(plugin),
-      mouse_lock_dispatcher_(
-          std::make_unique<FullscreenMouseLockDispatcher>(this)),
-      widget_client_(std::make_unique<PepperExternalWidgetClient>(this)) {
-  blink_widget_ = blink::WebExternalWidget::Create(
-      widget_client_.get(), main_frame_url, std::move(mojo_widget_host),
-      std::move(mojo_widget));
-}
-
-RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() = default;
-
-void RenderWidgetFullscreenPepper::Destroy() {
-  // The plugin instance is going away reset any lock target that is set
-  // on the dispatcher since this object can still live and receive IPC
-  // responses and may call a dangling lock_target.
-  mouse_lock_dispatcher_->ClearLockTarget();
-
-  // This function is called by the plugin instance as it's going away, so reset
-  // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close().
-  plugin_ = nullptr;
-
-  // After calling Destroy(), the plugin instance assumes that the layer is not
-  // used by us anymore, so it may destroy the layer before this object goes
-  // away.
-  SetLayer(nullptr);
-
-  // This instructs the browser process, which owns this object, to send back a
-  // WidgetMsg_Close to destroy this object.
-  Send(new WidgetHostMsg_Close(routing_id()));
-}
-
-void RenderWidgetFullscreenPepper::PepperDidChangeCursor(
-    const ui::Cursor& cursor) {
-  blink_widget_->SetCursor(cursor);
-}
-
-void RenderWidgetFullscreenPepper::SetLayer(scoped_refptr<cc::Layer> layer) {
-  layer_ = layer.get();
-  if (!layer_) {
-    blink_widget_->SetRootLayer(nullptr);
-    return;
-  }
-  UpdateLayerBounds();
-  layer_->SetIsDrawable(true);
-  layer_->SetHitTestable(true);
-  blink_widget_->SetRootLayer(std::move(layer));
-}
-
-void RenderWidgetFullscreenPepper::DidInitiatePaint() {
-  if (plugin_)
-    plugin_->ViewInitiatedPaint();
-}
-
-void RenderWidgetFullscreenPepper::Close(std::unique_ptr<RenderWidget> widget) {
-  // If the fullscreen window is closed (e.g. user pressed escape), reset to
-  // normal mode.
-  if (plugin_)
-    plugin_->FlashSetFullscreen(false, false);
-
-  // Call Close on the base class to destroy the WebWidget instance.
-  RenderWidget::Close(std::move(widget));
-}
-
-void RenderWidgetFullscreenPepper::UpdateLayerBounds() {
-  if (!layer_)
-    return;
-
-  // The |layer_| is sized here to cover the entire renderer's compositor
-  // viewport.
-  gfx::Size layer_size = gfx::Rect(GetWebWidget()->ViewRect()).size();
-  // When IsUseZoomForDSFEnabled() is true, layout and compositor layer sizes
-  // given by blink are all in physical pixels, and the compositor does not do
-  // any scaling. But the ViewRect() is always in DIP so we must scale the layer
-  // here as the compositor won't.
-  if (compositor_deps()->IsUseZoomForDSFEnabled()) {
-    layer_size = gfx::ScaleToCeiledSize(
-        layer_size,
-        GetWebWidget()->GetOriginalScreenInfo().device_scale_factor);
-  }
-  layer_->SetBounds(layer_size);
-}
-
-WebInputEventResult RenderWidgetFullscreenPepper::ProcessInputEvent(
-    const WebCoalescedInputEvent& coalesced_event) {
-  if (!plugin())
-    return WebInputEventResult::kNotHandled;
-
-  const WebInputEvent& event = coalesced_event.Event();
-
-  // This cursor is ignored, we always set the cursor directly from
-  // RenderWidgetFullscreenPepper::DidChangeCursor.
-  ui::Cursor cursor;
-
-  // Pepper plugins do not accept gesture events. So do not send the gesture
-  // events directly to the plugin. Instead, try to convert them to equivalent
-  // mouse events, and then send to the plugin.
-  if (blink::WebInputEvent::IsGestureEventType(event.GetType())) {
-    bool result = false;
-    const WebGestureEvent* gesture_event =
-        static_cast<const WebGestureEvent*>(&event);
-    switch (event.GetType()) {
-      case WebInputEvent::Type::kGestureTap: {
-        WebMouseEvent mouse(WebInputEvent::Type::kMouseMove,
-                            gesture_event->GetModifiers(),
-                            gesture_event->TimeStamp());
-        mouse.SetPositionInWidget(gesture_event->PositionInWidget());
-        mouse.SetPositionInScreen(gesture_event->PositionInScreen());
-        mouse.movement_x = 0;
-        mouse.movement_y = 0;
-        result |= plugin()->HandleInputEvent(mouse, &cursor);
-
-        mouse.SetType(WebInputEvent::Type::kMouseDown);
-        mouse.button = WebMouseEvent::Button::kLeft;
-        mouse.click_count = gesture_event->data.tap.tap_count;
-        result |= plugin()->HandleInputEvent(mouse, &cursor);
-
-        mouse.SetType(WebInputEvent::Type::kMouseUp);
-        result |= plugin()->HandleInputEvent(mouse, &cursor);
-        break;
-      }
-
-      default: {
-        WebMouseEvent mouse = WebMouseEventFromGestureEvent(*gesture_event);
-        if (mouse.GetType() != WebInputEvent::Type::kUndefined)
-          result |= plugin()->HandleInputEvent(mouse, &cursor);
-        break;
-      }
-    }
-    return result ? WebInputEventResult::kHandledApplication
-                  : WebInputEventResult::kNotHandled;
-  }
-
-  bool result = plugin()->HandleInputEvent(event, &cursor);
-
-  // For normal web pages, WebViewImpl does input event translations and
-  // generates context menu events. Since we don't have a WebView, we need to
-  // do the necessary translation ourselves.
-  if (WebInputEvent::IsMouseEventType(event.GetType())) {
-    const WebMouseEvent& mouse_event = static_cast<const WebMouseEvent&>(event);
-    bool send_context_menu_event = false;
-    // On Mac/Linux, we handle it on mouse down.
-    // On Windows, we handle it on mouse up.
-#if defined(OS_WIN)
-    send_context_menu_event =
-        mouse_event.GetType() == WebInputEvent::Type::kMouseUp &&
-        mouse_event.button == WebMouseEvent::Button::kRight;
-#elif defined(OS_MAC)
-    send_context_menu_event =
-        mouse_event.GetType() == WebInputEvent::Type::kMouseDown &&
-        (mouse_event.button == WebMouseEvent::Button::kRight ||
-         (mouse_event.button == WebMouseEvent::Button::kLeft &&
-          mouse_event.GetModifiers() & WebMouseEvent::kControlKey));
-#else
-    send_context_menu_event =
-        mouse_event.GetType() == WebInputEvent::Type::kMouseDown &&
-        mouse_event.button == WebMouseEvent::Button::kRight;
-#endif
-    if (send_context_menu_event) {
-      WebMouseEvent context_menu_event(mouse_event);
-      context_menu_event.SetType(WebInputEvent::Type::kContextMenu);
-      plugin()->HandleInputEvent(context_menu_event, &cursor);
-    }
-  }
-  return result ? WebInputEventResult::kHandledApplication
-                : WebInputEventResult::kNotHandled;
-}
-
-void RenderWidgetFullscreenPepper::DidResize(const gfx::Size& size) {
-  if (!plugin())
-    return;
-  gfx::Rect plugin_rect(size);
-  plugin()->ViewChanged(plugin_rect, plugin_rect, plugin_rect);
-}
-
-}  // namespace content
diff --git a/content/renderer/render_widget_fullscreen_pepper.h b/content/renderer/render_widget_fullscreen_pepper.h
deleted file mode 100644
index 5dd20af..0000000
--- a/content/renderer/render_widget_fullscreen_pepper.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_RENDER_WIDGET_FULLSCREEN_PEPPER_H_
-#define CONTENT_RENDERER_RENDER_WIDGET_FULLSCREEN_PEPPER_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "content/renderer/mouse_lock_dispatcher.h"
-#include "content/renderer/pepper/fullscreen_container.h"
-#include "content/renderer/render_widget.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "third_party/blink/public/mojom/page/widget.mojom.h"
-#include "third_party/blink/public/web/web_external_widget.h"
-#include "third_party/blink/public/web/web_external_widget_client.h"
-#include "url/gurl.h"
-
-namespace cc {
-class Layer;
-}
-
-namespace content {
-class AgentSchedulingGroup;
-class CompositorDependencies;
-class PepperPluginInstanceImpl;
-class PepperExternalWidgetClient;
-
-// A RenderWidget that hosts a fullscreen pepper plugin. This provides a
-// FullscreenContainer that the plugin instance can callback into to e.g.
-// invalidate rects.
-class RenderWidgetFullscreenPepper : public RenderWidget,
-                                     public FullscreenContainer {
- public:
-  // The created object is owned by the browser process. The browser process
-  // is responsible for destroying it with an IPC message.
-  static RenderWidgetFullscreenPepper* Create(
-      AgentSchedulingGroup& agent_scheduling_group,
-      int32_t routing_id,
-      RenderWidget::ShowCallback show_callback,
-      CompositorDependencies* compositor_deps,
-      const blink::ScreenInfo& screen_info,
-      PepperPluginInstanceImpl* plugin,
-      const blink::WebURL& local_main_frame_url,
-      mojo::PendingAssociatedRemote<blink::mojom::WidgetHost> blink_widget_host,
-      mojo::PendingAssociatedReceiver<blink::mojom::Widget> blink_widget);
-
-  // pepper::FullscreenContainer API.
-  void Destroy() override;
-  void PepperDidChangeCursor(const ui::Cursor& cursor) override;
-  void SetLayer(scoped_refptr<cc::Layer> layer) override;
-
-  // Could be NULL when this widget is closing.
-  PepperPluginInstanceImpl* plugin() const { return plugin_; }
-
-  MouseLockDispatcher* mouse_lock_dispatcher() const {
-    return mouse_lock_dispatcher_.get();
-  }
-
- protected:
-  RenderWidgetFullscreenPepper(
-      AgentSchedulingGroup& agent_scheduling_group,
-      int32_t routing_id,
-      CompositorDependencies* compositor_deps,
-      PepperPluginInstanceImpl* plugin,
-      mojo::PendingAssociatedRemote<blink::mojom::WidgetHost> blink_widget_host,
-      mojo::PendingAssociatedReceiver<blink::mojom::Widget> blink_widget,
-      blink::WebURL main_frame_url);
-  ~RenderWidgetFullscreenPepper() override;
-
-  // RenderWidget API.
-  void Close(std::unique_ptr<RenderWidget> widget) override;
-
- private:
-  friend class PepperExternalWidgetClient;
-
-  void DidInitiatePaint();
-  void UpdateLayerBounds();
-  void DidResize(const gfx::Size& size);
-  blink::WebInputEventResult ProcessInputEvent(
-      const blink::WebCoalescedInputEvent& event);
-
-  // The plugin instance this widget wraps.
-  PepperPluginInstanceImpl* plugin_;
-
-  cc::Layer* layer_ = nullptr;
-
-  std::unique_ptr<MouseLockDispatcher> mouse_lock_dispatcher_;
-  std::unique_ptr<PepperExternalWidgetClient> widget_client_;
-  std::unique_ptr<blink::WebExternalWidget> blink_widget_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderWidgetFullscreenPepper);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_RENDER_WIDGET_FULLSCREEN_PEPPER_H_
diff --git a/content/shell/fuchsia/OWNERS b/content/shell/fuchsia/OWNERS
new file mode 100644
index 0000000..e7fa181
--- /dev/null
+++ b/content/shell/fuchsia/OWNERS
@@ -0,0 +1,7 @@
+file://build/fuchsia/OWNERS
+# COMPONENT: Fuchsia
+# OS: Fuchsia
+# TEAM: cr-fuchsia@chromium.org
+
+per-file *.cmx=set noparent
+per-file *.cmx=file://fuchsia/SECURITY_OWNERS
diff --git a/content/shell/fuchsia/content_shell.cmx b/content/shell/fuchsia/content_shell.cmx
index 912ae8b..57b1ccd 100644
--- a/content/shell/fuchsia/content_shell.cmx
+++ b/content/shell/fuchsia/content_shell.cmx
@@ -25,6 +25,7 @@
       "fuchsia.sysmem.Allocator",
       "fuchsia.ui.input.ImeService",
       "fuchsia.ui.input.ImeVisibilityService",
+      "fuchsia.ui.policy.Presenter",
       "fuchsia.ui.scenic.Scenic",
       "fuchsia.vulkan.loader.Loader"
     ]
diff --git a/device/BUILD.gn b/device/BUILD.gn
index bfe360d..747e5b6 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -171,6 +171,7 @@
       "fido/large_blob_unittest.cc",
       "fido/make_credential_handler_unittest.cc",
       "fido/make_credential_task_unittest.cc",
+      "fido/pin_unittest.cc",
       "fido/test_callback_receiver_unittest.cc",
       "fido/u2f_command_constructor_unittest.cc",
       "fido/u2f_register_operation_unittest.cc",
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn
index ec3c528..6e58545 100644
--- a/device/fido/BUILD.gn
+++ b/device/fido/BUILD.gn
@@ -173,6 +173,8 @@
       "opaque_attestation_statement.h",
       "pin.cc",
       "pin.h",
+      "pin_internal.cc",
+      "pin_internal.h",
       "platform_credential_store.h",
       "reset_request_handler.cc",
       "reset_request_handler.h",
diff --git a/device/fido/device_response_converter.cc b/device/fido/device_response_converter.cc
index 31e7a758..7e50fb4 100644
--- a/device/fido/device_response_converter.cc
+++ b/device/fido/device_response_converter.cc
@@ -746,7 +746,8 @@
 }
 
 base::Optional<PINUVAuthProtocol> ToPINUVAuthProtocol(int64_t in) {
-  if (in != static_cast<uint8_t>(PINUVAuthProtocol::kV1)) {
+  if (in != static_cast<uint8_t>(PINUVAuthProtocol::kV1) &&
+      in != static_cast<uint8_t>(PINUVAuthProtocol::kV2)) {
     return base::nullopt;
   }
   return static_cast<PINUVAuthProtocol>(in);
diff --git a/device/fido/fido_constants.h b/device/fido/fido_constants.h
index 5f6e9c164..514cf980 100644
--- a/device/fido/fido_constants.h
+++ b/device/fido/fido_constants.h
@@ -476,6 +476,7 @@
 // PINUVAuthProtocol is the version number of a PIN/UV auth protocol.
 enum class PINUVAuthProtocol : uint8_t {
   kV1 = 1,
+  kV2 = 2,
 };
 
 }  // namespace device
diff --git a/device/fido/fido_device_authenticator.cc b/device/fido/fido_device_authenticator.cc
index 7af7cc4..93f44ed3 100644
--- a/device/fido/fido_device_authenticator.cc
+++ b/device/fido/fido_device_authenticator.cc
@@ -261,7 +261,7 @@
   if (Options()->supports_pin_uv_auth_token) {
     pin::PinTokenWithPermissionsRequest request(*chosen_pin_uv_auth_protocol_,
                                                 pin, *key, permissions, rp_id);
-    std::array<uint8_t, 32> shared_key = request.shared_key();
+    std::vector<uint8_t> shared_key = request.shared_key();
     RunOperation<pin::PinTokenWithPermissionsRequest, pin::TokenResponse>(
         std::move(request), std::move(callback),
         base::BindOnce(&pin::TokenResponse::Parse,
@@ -270,7 +270,7 @@
   }
 
   pin::PinTokenRequest request(*chosen_pin_uv_auth_protocol_, pin, *key);
-  std::array<uint8_t, 32> shared_key = request.shared_key();
+  std::vector<uint8_t> shared_key = request.shared_key();
   RunOperation<pin::PinTokenRequest, pin::TokenResponse>(
       std::move(request), std::move(callback),
       base::BindOnce(&pin::TokenResponse::Parse, *chosen_pin_uv_auth_protocol_,
@@ -1068,7 +1068,7 @@
 
   pin::UvTokenRequest request(*chosen_pin_uv_auth_protocol_, *key,
                               std::move(rp_id));
-  std::array<uint8_t, 32> shared_key = request.shared_key();
+  std::vector<uint8_t> shared_key = request.shared_key();
   RunOperation<pin::UvTokenRequest, pin::TokenResponse>(
       std::move(request), std::move(callback),
       base::BindOnce(&pin::TokenResponse::Parse, *chosen_pin_uv_auth_protocol_,
diff --git a/device/fido/pin.cc b/device/fido/pin.cc
index 83c9dcc1..8ae7e09 100644
--- a/device/fido/pin.cc
+++ b/device/fido/pin.cc
@@ -15,13 +15,8 @@
 #include "device/fido/fido_constants.h"
 #include "device/fido/pin_internal.h"
 #include "third_party/boringssl/src/include/openssl/aes.h"
-#include "third_party/boringssl/src/include/openssl/bn.h"
 #include "third_party/boringssl/src/include/openssl/ec.h"
-#include "third_party/boringssl/src/include/openssl/ec_key.h"
-#include "third_party/boringssl/src/include/openssl/ecdh.h"
-#include "third_party/boringssl/src/include/openssl/evp.h"
-#include "third_party/boringssl/src/include/openssl/hmac.h"
-#include "third_party/boringssl/src/include/openssl/obj.h"
+#include "third_party/boringssl/src/include/openssl/nid.h"
 #include "third_party/boringssl/src/include/openssl/sha.h"
 
 namespace device {
@@ -35,19 +30,6 @@
   return it.Advance() && it.Advance() && it.Advance() && it.Advance();
 }
 
-// MakePinAuth returns `LEFT(HMAC-SHA-256(secret, data), 16)`.
-std::vector<uint8_t> MakePinAuth(base::span<const uint8_t> secret,
-                                 base::span<const uint8_t> data) {
-  std::vector<uint8_t> pin_auth;
-  pin_auth.resize(SHA256_DIGEST_LENGTH);
-  unsigned hmac_bytes;
-  CHECK(HMAC(EVP_sha256(), secret.data(), secret.size(), data.data(),
-             data.size(), pin_auth.data(), &hmac_bytes));
-  DCHECK_EQ(pin_auth.size(), static_cast<size_t>(hmac_bytes));
-  pin_auth.resize(16);
-  return pin_auth;
-}
-
 bool IsValid(const std::string& pin) {
   return pin.size() >= kMinBytes && pin.size() <= kMaxBytes &&
          pin.back() != 0 && base::IsStringUTF8(pin) &&
@@ -118,28 +100,6 @@
 
 KeyAgreementResponse::KeyAgreementResponse() = default;
 
-// PointFromKeyAgreementResponse returns an |EC_POINT| that represents the same
-// P-256 point as |response|. It returns |nullopt| if |response| encodes an
-// invalid point.
-base::Optional<bssl::UniquePtr<EC_POINT>> PointFromKeyAgreementResponse(
-    const EC_GROUP* group,
-    const KeyAgreementResponse& response) {
-  bssl::UniquePtr<EC_POINT> ret(EC_POINT_new(group));
-
-  bssl::UniquePtr<BIGNUM> x_bn(BN_new()), y_bn(BN_new());
-  BN_bin2bn(response.x, sizeof(response.x), x_bn.get());
-  BN_bin2bn(response.y, sizeof(response.y), y_bn.get());
-  const bool on_curve =
-      EC_POINT_set_affine_coordinates_GFp(group, ret.get(), x_bn.get(),
-                                          y_bn.get(), nullptr /* ctx */) == 1;
-
-  if (!on_curve) {
-    return base::nullopt;
-  }
-
-  return ret;
-}
-
 // static
 base::Optional<KeyAgreementResponse> KeyAgreementResponse::Parse(
     const base::Optional<cbor::Value>& cbor) {
@@ -224,31 +184,6 @@
   memcpy(pin_, pin.data(), pin.size());
 }
 
-// SHA256KDF implements CTAP2's KDF, which just runs SHA-256 on the x-coordinate
-// of the result. The function signature is such that it fits into OpenSSL's
-// ECDH API.
-static void* SHA256KDF(const void* in,
-                       size_t in_len,
-                       void* out,
-                       size_t* out_len) {
-  DCHECK_GE(*out_len, static_cast<size_t>(SHA256_DIGEST_LENGTH));
-  SHA256(reinterpret_cast<const uint8_t*>(in), in_len,
-         reinterpret_cast<uint8_t*>(out));
-  *out_len = SHA256_DIGEST_LENGTH;
-  return out;
-}
-
-// CalculateSharedKey writes the CTAP2 shared key between |key| and |peers_key|
-// to |out_shared_key|.
-void CalculateSharedKey(const EC_KEY* key,
-                        const EC_POINT* peers_key,
-                        uint8_t out_shared_key[SHA256_DIGEST_LENGTH]) {
-  CHECK_EQ(static_cast<int>(SHA256_DIGEST_LENGTH),
-           ECDH_compute_key(out_shared_key, SHA256_DIGEST_LENGTH, peers_key,
-                            key, SHA256KDF));
-}
-
-// EncodeCOSEPublicKey converts an X9.62 public key into a COSE structure.
 cbor::Value::MapValue EncodeCOSEPublicKey(
     base::span<const uint8_t, kP256X962Length> x962) {
   cbor::Value::MapValue cose_key;
@@ -262,44 +197,6 @@
   return cose_key;
 }
 
-// GenerateSharedKey generates and returns an ephemeral key, and writes the
-// shared key between that ephemeral key and the authenticator's ephemeral key
-// (from |peers_key|) to |out_shared_key|.
-static std::array<uint8_t, kP256X962Length> GenerateSharedKey(
-    const KeyAgreementResponse& peers_key,
-    uint8_t out_shared_key[SHA256_DIGEST_LENGTH]) {
-  bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
-  CHECK(EC_KEY_generate_key(key.get()));
-  auto peers_point =
-      PointFromKeyAgreementResponse(EC_KEY_get0_group(key.get()), peers_key);
-  CalculateSharedKey(key.get(), peers_point->get(), out_shared_key);
-  std::array<uint8_t, kP256X962Length> x962;
-  CHECK_EQ(x962.size(),
-           EC_POINT_point2oct(EC_KEY_get0_group(key.get()),
-                              EC_KEY_get0_public_key(key.get()),
-                              POINT_CONVERSION_UNCOMPRESSED, x962.data(),
-                              x962.size(), nullptr /* BN_CTX */));
-
-  return x962;
-}
-
-// Encrypt encrypts |plaintext| using |key|, writing the ciphertext to
-// |out_ciphertext|. |plaintext| must be a whole number of AES blocks.
-void Encrypt(const uint8_t key[SHA256_DIGEST_LENGTH],
-             base::span<const uint8_t> plaintext,
-             uint8_t* out_ciphertext) {
-  DCHECK_EQ(0u, plaintext.size() % AES_BLOCK_SIZE);
-
-  EVP_CIPHER_CTX aes_ctx;
-  EVP_CIPHER_CTX_init(&aes_ctx);
-  const uint8_t kZeroIV[AES_BLOCK_SIZE] = {0};
-  CHECK(EVP_EncryptInit_ex(&aes_ctx, EVP_aes_256_cbc(), nullptr, key, kZeroIV));
-  CHECK(EVP_CIPHER_CTX_set_padding(&aes_ctx, 0 /* no padding */));
-  CHECK(
-      EVP_Cipher(&aes_ctx, out_ciphertext, plaintext.data(), plaintext.size()));
-  EVP_CIPHER_CTX_cleanup(&aes_ctx);
-}
-
 ChangeRequest::ChangeRequest(PINUVAuthProtocol protocol,
                              const std::string& old_pin,
                              const std::string& new_pin,
@@ -336,24 +233,6 @@
 TokenResponse::TokenResponse(const TokenResponse&) = default;
 TokenResponse& TokenResponse::operator=(const TokenResponse&) = default;
 
-// Decrypt AES-256 CBC decrypts some number of whole blocks from |ciphertext|
-// into |plaintext|, using |key|.
-void Decrypt(const uint8_t key[SHA256_DIGEST_LENGTH],
-             base::span<const uint8_t> ciphertext,
-             uint8_t* out_plaintext) {
-  DCHECK_EQ(0u, ciphertext.size() % AES_BLOCK_SIZE);
-
-  EVP_CIPHER_CTX aes_ctx;
-  EVP_CIPHER_CTX_init(&aes_ctx);
-  const uint8_t kZeroIV[AES_BLOCK_SIZE] = {0};
-  CHECK(EVP_DecryptInit_ex(&aes_ctx, EVP_aes_256_cbc(), nullptr, key, kZeroIV));
-  CHECK(EVP_CIPHER_CTX_set_padding(&aes_ctx, 0 /* no padding */));
-
-  CHECK(EVP_Cipher(&aes_ctx, out_plaintext, ciphertext.data(),
-                   ciphertext.size()));
-  EVP_CIPHER_CTX_cleanup(&aes_ctx);
-}
-
 base::Optional<TokenResponse> TokenResponse::Parse(
     PINUVAuthProtocol protocol,
     base::span<const uint8_t> shared_key,
@@ -374,14 +253,14 @@
   }
 
   TokenResponse ret(protocol);
-  ret.token_.resize(encrypted_token.size());
-  Decrypt(shared_key.data(), encrypted_token, ret.token_.data());
+  ret.token_ = ProtocolVersion(protocol).Decrypt(shared_key, encrypted_token);
   return ret;
 }
 
 std::pair<PINUVAuthProtocol, std::vector<uint8_t>> TokenResponse::PinAuth(
     base::span<const uint8_t> client_data_hash) const {
-  return {protocol_, MakePinAuth(token_, client_data_hash)};
+  return {protocol_,
+          ProtocolVersion(protocol_).Authenticate(token_, client_data_hash)};
 }
 
 // static
@@ -407,27 +286,26 @@
 AsCTAPRequestValuePair(const SetRequest& request) {
   // See
   // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#settingNewPin
-  uint8_t shared_key[SHA256_DIGEST_LENGTH];
-  auto cose_key =
-      EncodeCOSEPublicKey(GenerateSharedKey(request.peer_key_, shared_key));
+  std::vector<uint8_t> shared_key;
+  const Protocol& pin_protocol = ProtocolVersion(request.protocol_);
+  auto cose_key = EncodeCOSEPublicKey(
+      pin_protocol.Encapsulate(request.peer_key_, &shared_key));
 
   static_assert((sizeof(request.pin_) % AES_BLOCK_SIZE) == 0,
                 "pin_ is not a multiple of the AES block size");
-  uint8_t encrypted_pin[sizeof(request.pin_)];
-  Encrypt(shared_key, request.pin_, encrypted_pin);
+  std::vector<uint8_t> encrypted_pin =
+      pin_protocol.Encrypt(shared_key, request.pin_);
 
   std::vector<uint8_t> pin_auth =
-      MakePinAuth(base::make_span(shared_key, sizeof(shared_key)),
-                  base::make_span(encrypted_pin, sizeof(encrypted_pin)));
+      pin_protocol.Authenticate(shared_key, encrypted_pin);
 
   return EncodePINCommand(
       request.protocol_, Subcommand::kSetPIN,
       [&cose_key, &encrypted_pin, &pin_auth](cbor::Value::MapValue* map) {
         map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
                      std::move(cose_key));
-        map->emplace(
-            static_cast<int>(RequestKey::kNewPINEnc),
-            base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin)));
+        map->emplace(static_cast<int>(RequestKey::kNewPINEnc),
+                     std::move(encrypted_pin));
         map->emplace(static_cast<int>(RequestKey::kPINAuth),
                      std::move(pin_auth));
       });
@@ -438,27 +316,29 @@
 AsCTAPRequestValuePair(const ChangeRequest& request) {
   // See
   // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#changingExistingPin
-  uint8_t shared_key[SHA256_DIGEST_LENGTH];
-  auto cose_key =
-      EncodeCOSEPublicKey(GenerateSharedKey(request.peer_key_, shared_key));
+  std::vector<uint8_t> shared_key;
+  const Protocol& pin_protocol = ProtocolVersion(request.protocol_);
+  auto cose_key = EncodeCOSEPublicKey(
+      pin_protocol.Encapsulate(request.peer_key_, &shared_key));
 
   static_assert((sizeof(request.new_pin_) % AES_BLOCK_SIZE) == 0,
                 "new_pin_ is not a multiple of the AES block size");
-  uint8_t encrypted_pin[sizeof(request.new_pin_)];
-  Encrypt(shared_key, request.new_pin_, encrypted_pin);
+  std::vector<uint8_t> encrypted_pin =
+      pin_protocol.Encrypt(shared_key, request.new_pin_);
 
   static_assert((sizeof(request.old_pin_hash_) % AES_BLOCK_SIZE) == 0,
                 "old_pin_hash_ is not a multiple of the AES block size");
-  uint8_t old_pin_hash_enc[sizeof(request.old_pin_hash_)];
-  Encrypt(shared_key, request.old_pin_hash_, old_pin_hash_enc);
+  std::vector<uint8_t> old_pin_hash_enc =
+      pin_protocol.Encrypt(shared_key, request.old_pin_hash_);
 
-  uint8_t ciphertexts_concat[sizeof(encrypted_pin) + sizeof(old_pin_hash_enc)];
-  memcpy(ciphertexts_concat, encrypted_pin, sizeof(encrypted_pin));
-  memcpy(ciphertexts_concat + sizeof(encrypted_pin), old_pin_hash_enc,
-         sizeof(old_pin_hash_enc));
-  std::vector<uint8_t> pin_auth = MakePinAuth(
-      base::make_span(shared_key, sizeof(shared_key)),
-      base::make_span(ciphertexts_concat, sizeof(ciphertexts_concat)));
+  std::vector<uint8_t> ciphertexts_concat(encrypted_pin.size() +
+                                          old_pin_hash_enc.size());
+  memcpy(ciphertexts_concat.data(), encrypted_pin.data(), encrypted_pin.size());
+  memcpy(ciphertexts_concat.data() + encrypted_pin.size(),
+         old_pin_hash_enc.data(), old_pin_hash_enc.size());
+
+  std::vector<uint8_t> pin_auth =
+      pin_protocol.Authenticate(shared_key, ciphertexts_concat);
 
   return EncodePINCommand(
       request.protocol_, Subcommand::kChangePIN,
@@ -467,11 +347,9 @@
         map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
                      std::move(cose_key));
         map->emplace(static_cast<int>(RequestKey::kPINHashEnc),
-                     base::span<const uint8_t>(old_pin_hash_enc,
-                                               sizeof(old_pin_hash_enc)));
-        map->emplace(
-            static_cast<int>(RequestKey::kNewPINEnc),
-            base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin)));
+                     std::move(old_pin_hash_enc));
+        map->emplace(static_cast<int>(RequestKey::kNewPINEnc),
+                     std::move(encrypted_pin));
         map->emplace(static_cast<int>(RequestKey::kPINAuth),
                      std::move(pin_auth));
       });
@@ -486,15 +364,14 @@
 TokenRequest::TokenRequest(PINUVAuthProtocol protocol,
                            const KeyAgreementResponse& peer_key)
     : protocol_(protocol),
-      public_key_(GenerateSharedKey(peer_key, shared_key_.data())) {
-  DCHECK_EQ(static_cast<size_t>(SHA256_DIGEST_LENGTH), shared_key_.size());
-}
+      public_key_(
+          ProtocolVersion(protocol_).Encapsulate(peer_key, &shared_key_)) {}
 
 TokenRequest::~TokenRequest() = default;
 
 TokenRequest::TokenRequest(TokenRequest&& other) = default;
 
-const std::array<uint8_t, 32>& TokenRequest::shared_key() const {
+const std::vector<uint8_t>& TokenRequest::shared_key() const {
   return shared_key_;
 }
 
@@ -516,17 +393,17 @@
 AsCTAPRequestValuePair(const PinTokenRequest& request) {
   static_assert((sizeof(request.pin_hash_) % AES_BLOCK_SIZE) == 0,
                 "pin_hash_ is not a multiple of the AES block size");
-  uint8_t encrypted_pin[sizeof(request.pin_hash_)];
-  Encrypt(request.shared_key_.data(), request.pin_hash_, encrypted_pin);
+  std::vector<uint8_t> encrypted_pin =
+      ProtocolVersion(request.protocol_)
+          .Encrypt(request.shared_key_, request.pin_hash_);
 
   return EncodePINCommand(
       request.protocol_, Subcommand::kGetPINToken,
       [&request, &encrypted_pin](cbor::Value::MapValue* map) {
         map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
                      EncodeCOSEPublicKey(request.public_key_));
-        map->emplace(
-            static_cast<int>(RequestKey::kPINHashEnc),
-            base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin)));
+        map->emplace(static_cast<int>(RequestKey::kPINHashEnc),
+                     std::move(encrypted_pin));
       });
 }
 
@@ -543,17 +420,17 @@
 // static
 std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
 AsCTAPRequestValuePair(const PinTokenWithPermissionsRequest& request) {
-  uint8_t encrypted_pin[sizeof(request.pin_hash_)];
-  Encrypt(request.shared_key_.data(), request.pin_hash_, encrypted_pin);
+  std::vector<uint8_t> encrypted_pin =
+      ProtocolVersion(request.protocol_)
+          .Encrypt(request.shared_key_, request.pin_hash_);
 
   return EncodePINCommand(
       request.protocol_, Subcommand::kGetPinUvAuthTokenUsingPinWithPermissions,
       [&request, &encrypted_pin](cbor::Value::MapValue* map) {
         map->emplace(static_cast<int>(RequestKey::kKeyAgreement),
                      EncodeCOSEPublicKey(request.public_key_));
-        map->emplace(
-            static_cast<int>(RequestKey::kPINHashEnc),
-            base::span<const uint8_t>(encrypted_pin, sizeof(encrypted_pin)));
+        map->emplace(static_cast<int>(RequestKey::kPINHashEnc),
+                     std::move(encrypted_pin));
         map->emplace(static_cast<int>(RequestKey::kPermissions),
                      std::move(request.permissions_));
         if (request.rp_id_) {
@@ -595,15 +472,6 @@
       });
 }
 
-static std::vector<uint8_t> EncryptToVector(
-    base::span<const uint8_t, SHA256_DIGEST_LENGTH> key,
-    base::span<const uint8_t> plaintext) {
-  std::vector<uint8_t> ret;
-  ret.resize(plaintext.size());
-  Encrypt(key.data(), plaintext, ret.data());
-  return ret;
-}
-
 static std::vector<uint8_t> ConcatSalts(
     base::span<const uint8_t, 32> salt1,
     const base::Optional<std::array<uint8_t, 32>>& salt2) {
@@ -625,9 +493,13 @@
     base::span<const uint8_t, 32> salt1,
     const base::Optional<std::array<uint8_t, 32>>& salt2)
     : protocol_(protocol),
-      public_key_x962(GenerateSharedKey(peer_key, shared_key_.data())),
-      encrypted_salts(EncryptToVector(shared_key_, ConcatSalts(salt1, salt2))),
-      salts_auth(MakePinAuth(shared_key_, encrypted_salts)) {}
+      public_key_x962(
+          ProtocolVersion(protocol_).Encapsulate(peer_key, &shared_key_)),
+      encrypted_salts(
+          ProtocolVersion(protocol_).Encrypt(shared_key_,
+                                             ConcatSalts(salt1, salt2))),
+      salts_auth(ProtocolVersion(protocol_).Authenticate(shared_key_,
+                                                         encrypted_salts)) {}
 
 HMACSecretRequest::~HMACSecretRequest() = default;
 
@@ -639,12 +511,8 @@
     return base::nullopt;
   }
 
-  std::vector<uint8_t> ret;
-  ret.resize(ciphertext.size());
-  pin::Decrypt(shared_key_.data(), ciphertext, ret.data());
-  return ret;
+  return pin::ProtocolVersion(protocol_).Decrypt(shared_key_, ciphertext);
 }
 
 }  // namespace pin
-
 }  // namespace device
diff --git a/device/fido/pin.h b/device/fido/pin.h
index fd485f91..dd478f9 100644
--- a/device/fido/pin.h
+++ b/device/fido/pin.h
@@ -55,6 +55,7 @@
 constexpr size_t kMaxBytes = 63;
 
 // EncodeCOSEPublicKey converts an X9.62 public key to a COSE structure.
+COMPONENT_EXPORT(DEVICE_FIDO)
 cbor::Value::MapValue EncodeCOSEPublicKey(
     base::span<const uint8_t, kP256X962Length> x962);
 
@@ -100,7 +101,7 @@
 // KeyAgreementResponse reflects an authenticator's response to a
 // |KeyAgreementRequest| and is also used as representation of the
 // authenticator's ephemeral key.
-struct KeyAgreementResponse {
+struct COMPONENT_EXPORT(DEVICE_FIDO) KeyAgreementResponse {
   static base::Optional<KeyAgreementResponse> Parse(
       const base::Optional<cbor::Value>& cbor);
   static base::Optional<KeyAgreementResponse> ParseFromCOSE(
@@ -177,7 +178,7 @@
 
   // shared_key returns the shared ECDH key that was used to encrypt the PIN.
   // This is needed to decrypt the response.
-  const std::array<uint8_t, 32>& shared_key() const;
+  const std::vector<uint8_t>& shared_key() const;
 
  protected:
   TokenRequest(TokenRequest&&);
@@ -186,7 +187,7 @@
   ~TokenRequest();
 
   const PINUVAuthProtocol protocol_;
-  std::array<uint8_t, 32> shared_key_;
+  std::vector<uint8_t> shared_key_;
   std::array<uint8_t, kP256X962Length> public_key_;
 };
 
@@ -257,7 +258,7 @@
 
  private:
   const PINUVAuthProtocol protocol_;
-  std::array<uint8_t, 32> shared_key_ = {};
+  std::vector<uint8_t> shared_key_;
 
  public:
   const std::array<uint8_t, kP256X962Length> public_key_x962;
diff --git a/device/fido/pin_internal.cc b/device/fido/pin_internal.cc
new file mode 100644
index 0000000..369fa35
--- /dev/null
+++ b/device/fido/pin_internal.cc
@@ -0,0 +1,316 @@
+// 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/fido/pin_internal.h"
+
+#include <string>
+#include <utility>
+
+#include "base/i18n/char_iterator.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_util.h"
+#include "crypto/random.h"
+#include "third_party/boringssl/src/include/openssl/aes.h"
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ec_key.h"
+#include "third_party/boringssl/src/include/openssl/ecdh.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
+#include "third_party/boringssl/src/include/openssl/hkdf.h"
+#include "third_party/boringssl/src/include/openssl/hmac.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
+
+namespace device {
+namespace pin {
+
+base::Optional<bssl::UniquePtr<EC_POINT>> PointFromKeyAgreementResponse(
+    const EC_GROUP* group,
+    const KeyAgreementResponse& response) {
+  bssl::UniquePtr<EC_POINT> ret(EC_POINT_new(group));
+
+  bssl::UniquePtr<BIGNUM> x_bn(BN_new()), y_bn(BN_new());
+  BN_bin2bn(response.x, sizeof(response.x), x_bn.get());
+  BN_bin2bn(response.y, sizeof(response.y), y_bn.get());
+  const bool on_curve =
+      EC_POINT_set_affine_coordinates_GFp(group, ret.get(), x_bn.get(),
+                                          y_bn.get(), nullptr /* ctx */) == 1;
+
+  if (!on_curve) {
+    return base::nullopt;
+  }
+
+  return ret;
+}
+
+// ProtocolV1 implements CTAP2.1 PIN/UV Auth Protocol One (6.5.10).
+class ProtocolV1 : public Protocol {
+ private:
+  static constexpr size_t kSharedKeySize = 32u;
+  static constexpr size_t kSignatureSize = 16u;
+
+  std::array<uint8_t, kP256X962Length> Encapsulate(
+      const KeyAgreementResponse& peers_key,
+      std::vector<uint8_t>* out_shared_key) const override {
+    bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+    CHECK(EC_KEY_generate_key(key.get()));
+    base::Optional<bssl::UniquePtr<EC_POINT>> peers_point =
+        PointFromKeyAgreementResponse(EC_KEY_get0_group(key.get()), peers_key);
+    *out_shared_key = CalculateSharedKey(key.get(), peers_point->get());
+    // KeyAgreementResponse parsing ensures that the point is on the curve.
+    DCHECK(peers_point);
+    std::array<uint8_t, kP256X962Length> x962;
+    CHECK_EQ(x962.size(),
+             EC_POINT_point2oct(EC_KEY_get0_group(key.get()),
+                                EC_KEY_get0_public_key(key.get()),
+                                POINT_CONVERSION_UNCOMPRESSED, x962.data(),
+                                x962.size(), nullptr /* BN_CTX */));
+
+    return x962;
+  }
+
+  std::vector<uint8_t> Encrypt(
+      base::span<const uint8_t> shared_key,
+      base::span<const uint8_t> plaintext) const override {
+    DCHECK_EQ(plaintext.size() % AES_BLOCK_SIZE, 0u);
+    DCHECK_EQ(shared_key.size(), kSharedKeySize);
+
+    std::vector<uint8_t> ciphertext(plaintext.size());
+
+    EVP_CIPHER_CTX aes_ctx;
+    EVP_CIPHER_CTX_init(&aes_ctx);
+    const uint8_t kZeroIV[AES_BLOCK_SIZE] = {};
+    CHECK(EVP_EncryptInit_ex(&aes_ctx, EVP_aes_256_cbc(), nullptr,
+                             shared_key.data(), kZeroIV));
+    CHECK(EVP_CIPHER_CTX_set_padding(&aes_ctx, 0 /* no padding */));
+    CHECK(EVP_Cipher(&aes_ctx, ciphertext.data(), plaintext.data(),
+                     plaintext.size()));
+    EVP_CIPHER_CTX_cleanup(&aes_ctx);
+    return ciphertext;
+  }
+
+  std::vector<uint8_t> Decrypt(
+      base::span<const uint8_t> shared_key,
+      base::span<const uint8_t> ciphertext) const override {
+    DCHECK_EQ(ciphertext.size() % AES_BLOCK_SIZE, 0u);
+    DCHECK_EQ(shared_key.size(), kSharedKeySize);
+
+    std::vector<uint8_t> plaintext(ciphertext.size());
+
+    EVP_CIPHER_CTX aes_ctx;
+    EVP_CIPHER_CTX_init(&aes_ctx);
+    const uint8_t kZeroIV[AES_BLOCK_SIZE] = {};
+    CHECK(EVP_DecryptInit_ex(&aes_ctx, EVP_aes_256_cbc(), nullptr,
+                             shared_key.data(), kZeroIV));
+    CHECK(EVP_CIPHER_CTX_set_padding(&aes_ctx, 0 /* no padding */));
+
+    CHECK(EVP_Cipher(&aes_ctx, plaintext.data(), ciphertext.data(),
+                     ciphertext.size()));
+    EVP_CIPHER_CTX_cleanup(&aes_ctx);
+    return plaintext;
+  }
+
+  std::vector<uint8_t> Authenticate(
+      base::span<const uint8_t> key,
+      base::span<const uint8_t> data) const override {
+    DCHECK_EQ(key.size(), kSharedKeySize);
+
+    std::vector<uint8_t> pin_auth(SHA256_DIGEST_LENGTH);
+    unsigned hmac_bytes;
+    CHECK(HMAC(EVP_sha256(), key.data(), key.size(), data.data(), data.size(),
+               pin_auth.data(), &hmac_bytes));
+    DCHECK_EQ(pin_auth.size(), static_cast<size_t>(hmac_bytes));
+    pin_auth.resize(kSignatureSize);
+    return pin_auth;
+  }
+
+  bool Verify(base::span<const uint8_t> key,
+              base::span<const uint8_t> data,
+              base::span<const uint8_t> signature) const override {
+    if (signature.size() != kSignatureSize) {
+      return false;
+    }
+    const std::vector<uint8_t> computed_signature = Authenticate(key, data);
+    CHECK_EQ(computed_signature.size(), kSignatureSize);
+    return CRYPTO_memcmp(signature.data(), computed_signature.data(),
+                         kSignatureSize) == 0;
+  }
+
+  std::vector<uint8_t> CalculateSharedKey(
+      const EC_KEY* key,
+      const EC_POINT* peers_key) const override {
+    std::vector<uint8_t> shared_key(SHA256_DIGEST_LENGTH);
+    CHECK_EQ(static_cast<int>(SHA256_DIGEST_LENGTH),
+             ECDH_compute_key(shared_key.data(), shared_key.size(), peers_key,
+                              key, SHA256KDF));
+    return shared_key;
+  }
+
+  static void* SHA256KDF(const void* in,
+                         size_t in_len,
+                         void* out,
+                         size_t* out_len) {
+    DCHECK_GE(*out_len, static_cast<size_t>(SHA256_DIGEST_LENGTH));
+    SHA256(reinterpret_cast<const uint8_t*>(in), in_len,
+           reinterpret_cast<uint8_t*>(out));
+    *out_len = SHA256_DIGEST_LENGTH;
+    return out;
+  }
+};
+
+// ProtocolV2 implements CTAP2.1 PIN/UV Auth Protocol Two (6.5.11).
+class ProtocolV2 : public ProtocolV1 {
+ private:
+  static constexpr size_t kAESKeyLength = 32;
+  static constexpr size_t kHMACKeyLength = 32;
+  static constexpr size_t kSharedKeyLength = kAESKeyLength + kHMACKeyLength;
+  static constexpr size_t kSignatureSize = SHA256_DIGEST_LENGTH;
+
+  // GetHMACSubKey returns the HMAC-key portion of the shared secret.
+  static base::span<const uint8_t, kHMACKeyLength> GetHMACSubKey(
+      base::span<const uint8_t, kSharedKeyLength> shared_key) {
+    CHECK_EQ(shared_key.size(), kSharedKeyLength);
+    return base::make_span<kHMACKeyLength>(
+        shared_key.subspan(0, kHMACKeyLength));
+  }
+
+  // GetAESSubKey returns the HMAC-key portion of the shared secret.
+  static base::span<const uint8_t, kAESKeyLength> GetAESSubKey(
+      base::span<const uint8_t, kSharedKeyLength> shared_key) {
+    return base::make_span<kAESKeyLength>(shared_key.subspan(kHMACKeyLength));
+  }
+
+  std::vector<uint8_t> Encrypt(
+      base::span<const uint8_t> shared_key,
+      base::span<const uint8_t> plaintext) const override {
+    DCHECK_EQ(plaintext.size() % AES_BLOCK_SIZE, 0u);
+
+    const base::span<const uint8_t, kAESKeyLength> aes_key =
+        GetAESSubKey(base::make_span<kSharedKeyLength>(shared_key));
+
+    std::vector<uint8_t> result(AES_BLOCK_SIZE + plaintext.size());
+    const base::span<uint8_t> iv =
+        base::make_span(result).subspan(0, AES_BLOCK_SIZE);
+    const base::span<uint8_t> ciphertext =
+        base::make_span(result).subspan(AES_BLOCK_SIZE);
+
+    crypto::RandBytes(iv);
+
+    EVP_CIPHER_CTX aes_ctx;
+    EVP_CIPHER_CTX_init(&aes_ctx);
+    CHECK(EVP_EncryptInit_ex(&aes_ctx, EVP_aes_256_cbc(), nullptr,
+                             aes_key.data(), iv.data()));
+    CHECK(EVP_CIPHER_CTX_set_padding(&aes_ctx, 0 /* no padding */));
+    CHECK(EVP_Cipher(&aes_ctx, ciphertext.data(), plaintext.data(),
+                     plaintext.size()));
+    EVP_CIPHER_CTX_cleanup(&aes_ctx);
+
+    return result;
+  }
+
+  std::vector<uint8_t> Decrypt(base::span<const uint8_t> shared_key,
+                               base::span<const uint8_t> input) const override {
+    DCHECK_EQ(input.size() % AES_BLOCK_SIZE, 0u);
+
+    const base::span<const uint8_t, kAESKeyLength> aes_key =
+        GetAESSubKey(base::make_span<kSharedKeyLength>(shared_key));
+    const base::span<const uint8_t> iv = input.subspan(0, AES_BLOCK_SIZE);
+    const base::span<const uint8_t> ciphertext = input.subspan(AES_BLOCK_SIZE);
+    std::vector<uint8_t> plaintext(ciphertext.size());
+
+    EVP_CIPHER_CTX aes_ctx;
+    EVP_CIPHER_CTX_init(&aes_ctx);
+    CHECK(EVP_DecryptInit_ex(&aes_ctx, EVP_aes_256_cbc(), nullptr,
+                             aes_key.data(), iv.data()));
+    CHECK(EVP_CIPHER_CTX_set_padding(&aes_ctx, 0 /* no padding */));
+
+    CHECK(EVP_Cipher(&aes_ctx, plaintext.data(), ciphertext.data(),
+                     ciphertext.size()));
+    EVP_CIPHER_CTX_cleanup(&aes_ctx);
+
+    return plaintext;
+  }
+
+  std::vector<uint8_t> Authenticate(
+      base::span<const uint8_t> key,
+      base::span<const uint8_t> data) const override {
+    // Authenticate can be invoked with the shared secret or with a PIN/UV Auth
+    // Token, which is fixed at 32 bytes in this protocol version.
+    CHECK(key.size() == kSharedKeyLength || key.size() == kHMACKeyLength);
+    const base::span<const uint8_t, kHMACKeyLength> hmac_key =
+        (key.size() == kSharedKeyLength
+             ? GetHMACSubKey(base::make_span<kSharedKeyLength>(key))
+             : base::make_span<kHMACKeyLength>(key));
+
+    std::vector<uint8_t> pin_auth(SHA256_DIGEST_LENGTH);
+    unsigned hmac_bytes;
+    CHECK(HMAC(EVP_sha256(), hmac_key.data(), hmac_key.size(), data.data(),
+               data.size(), pin_auth.data(), &hmac_bytes));
+    DCHECK_EQ(pin_auth.size(), static_cast<size_t>(hmac_bytes));
+    return pin_auth;
+  }
+
+  bool Verify(base::span<const uint8_t> key,
+              base::span<const uint8_t> data,
+              base::span<const uint8_t> signature) const override {
+    if (signature.size() != kSignatureSize) {
+      return false;
+    }
+    const std::vector<uint8_t> computed_signature = Authenticate(key, data);
+    CHECK_EQ(computed_signature.size(), kSignatureSize);
+    return CRYPTO_memcmp(signature.data(), computed_signature.data(),
+                         kSignatureSize) == 0;
+  }
+
+  std::vector<uint8_t> CalculateSharedKey(
+      const EC_KEY* key,
+      const EC_POINT* peers_key) const override {
+    std::vector<uint8_t> shared_key(kSharedKeyLength);
+    CHECK_EQ(static_cast<int>(kSharedKeyLength),
+             ECDH_compute_key(shared_key.data(), shared_key.size(), peers_key,
+                              key, KDF));
+    return shared_key;
+  }
+
+  static void* KDF(const void* in, size_t in_len, void* out, size_t* out_len) {
+    static_assert(kSharedKeyLength == 2 * SHA256_DIGEST_LENGTH, "");
+    DCHECK_GE(*out_len, static_cast<size_t>(kSharedKeyLength));
+    auto hmac_key_out =
+        base::make_span(reinterpret_cast<uint8_t*>(out), SHA256_DIGEST_LENGTH);
+    auto aes_key_out =
+        base::make_span(reinterpret_cast<uint8_t*>(out) + SHA256_DIGEST_LENGTH,
+                        SHA256_DIGEST_LENGTH);
+
+    constexpr uint8_t kHMACKeyInfo[] = "CTAP2 HMAC key";
+    constexpr uint8_t kAESKeyInfo[] = "CTAP2 AES key";
+    constexpr uint8_t kZeroSalt[32] = {};
+
+    CHECK(HKDF(hmac_key_out.data(), hmac_key_out.size(), EVP_sha256(),
+               reinterpret_cast<const uint8_t*>(in), in_len, kZeroSalt,
+               sizeof(kZeroSalt), kHMACKeyInfo, sizeof(kHMACKeyInfo) - 1));
+    CHECK(HKDF(aes_key_out.data(), aes_key_out.size(), EVP_sha256(),
+               reinterpret_cast<const uint8_t*>(in), in_len, kZeroSalt,
+               sizeof(kZeroSalt), kAESKeyInfo, sizeof(kAESKeyInfo) - 1));
+
+    *out_len = kSharedKeyLength;
+    return out;
+  }
+};
+
+// static
+const Protocol& ProtocolVersion(PINUVAuthProtocol protocol) {
+  static const base::NoDestructor<ProtocolV1> kProtocolV1;
+  static const base::NoDestructor<ProtocolV2> kProtocolV2;
+
+  switch (protocol) {
+    case PINUVAuthProtocol::kV1:
+      return *kProtocolV1;
+    case PINUVAuthProtocol::kV2:
+      return *kProtocolV2;
+  }
+}
+
+}  // namespace pin
+
+}  // namespace device
diff --git a/device/fido/pin_internal.h b/device/fido/pin_internal.h
index 73713bb..3712f49d 100644
--- a/device/fido/pin_internal.h
+++ b/device/fido/pin_internal.h
@@ -11,10 +11,16 @@
 
 #include <stdint.h>
 
+#include <array>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/containers/span.h"
+#include "base/optional.h"
 #include "components/cbor/values.h"
+#include "device/fido/fido_constants.h"
 #include "device/fido/pin.h"
-#include "third_party/boringssl/src/include/openssl/ec.h"
-#include "third_party/boringssl/src/include/openssl/sha.h"
+#include "third_party/boringssl/src/include/openssl/base.h"
 
 namespace device {
 namespace pin {
@@ -65,27 +71,60 @@
     const EC_GROUP* group,
     const KeyAgreementResponse& response);
 
-// MakePinAuth returns a PIN protocol v1 authentication tag for |data|.
-std::vector<uint8_t> MakePinAuth(base::span<const uint8_t> secret,
-                                 base::span<const uint8_t> data);
+// Protocol abstracts a PIN/UV Auth Token Protocol. Instances are obtained
+// through ProtocolVersion().
+class COMPONENT_EXPORT(DEVICE_FIDO) Protocol {
+ public:
+  virtual ~Protocol() = default;
+  Protocol(Protocol&) = delete;
+  Protocol& operator=(Protocol&) = delete;
 
-// CalculateSharedKey writes the CTAP2 shared key between |key| and |peers_key|
-// to |out_shared_key|.
-void CalculateSharedKey(const EC_KEY* key,
-                        const EC_POINT* peers_key,
-                        uint8_t out_shared_key[SHA256_DIGEST_LENGTH]);
+  // Encapsulate derives a shared secret, which it writes to |out_shared_key|,
+  // and returns the platform's public key.
+  virtual std::array<uint8_t, kP256X962Length> Encapsulate(
+      const KeyAgreementResponse& peers_key,
+      std::vector<uint8_t>* out_shared_key) const = 0;
 
-// Encrypt encrypts |plaintext| using |key|, writing the ciphertext to
-// |out_ciphertext|. |plaintext| must be a whole number of AES blocks.
-void Encrypt(const uint8_t key[SHA256_DIGEST_LENGTH],
-             base::span<const uint8_t> plaintext,
-             uint8_t* out_ciphertext);
+  // Encrypt encrypts |plaintext| under |shared_key|. |plaintext| must be a
+  // multiple of AES_BLOCK_SIZE in length. |shared_key| must be a shared secret
+  // derived by Encapsulate().
+  virtual std::vector<uint8_t> Encrypt(
+      base::span<const uint8_t> shared_key,
+      base::span<const uint8_t> plaintext) const = 0;
 
-// Decrypt AES-256 CBC decrypts some number of whole blocks from |ciphertext|
-// into |plaintext|, using |key|.
-void Decrypt(const uint8_t key[SHA256_DIGEST_LENGTH],
-             base::span<const uint8_t> ciphertext,
-             uint8_t* out_plaintext);
+  // Decrypt returns the decryption of |ciphertext|, which must be non-empty and
+  // a multiple of AES_BLOCK_SIZE in length. |shared_key| must be a shared
+  // secret derived by Encapsulate().
+  virtual std::vector<uint8_t> Decrypt(
+      base::span<const uint8_t> shared_key,
+      base::span<const uint8_t> ciphertext) const = 0;
+
+  // Authenticate() returns a signature of |data|. |key| must be either a shared
+  // secret derived by Encapsulate() or a valid pinUvAuthToken from the same
+  // PIN/UV Auth Protocol.
+  virtual std::vector<uint8_t> Authenticate(
+      base::span<const uint8_t> key,
+      base::span<const uint8_t> data) const = 0;
+
+  // Verify verifies a signature computed by Authenticate().
+  virtual bool Verify(base::span<const uint8_t> key,
+                      base::span<const uint8_t> data,
+                      base::span<const uint8_t> signature) const = 0;
+
+  // CalculateSharedKey returns the CTAP2 shared key between |key| and
+  // |peers_key|.
+  virtual std::vector<uint8_t> CalculateSharedKey(
+      const EC_KEY* key,
+      const EC_POINT* peers_key) const = 0;
+
+ protected:
+  Protocol() = default;
+};
+
+// ProtocolVersion returns the |Protocol| implementation for
+// |PINUvAuthProtocol|.
+COMPONENT_EXPORT(DEVICE_FIDO)
+const Protocol& ProtocolVersion(PINUVAuthProtocol protocol);
 
 }  // namespace pin
 }  // namespace device
diff --git a/device/fido/pin_unittest.cc b/device/fido/pin_unittest.cc
new file mode 100644
index 0000000..c4c7ba5a
--- /dev/null
+++ b/device/fido/pin_unittest.cc
@@ -0,0 +1,107 @@
+// Copyright 2020 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/fido/pin.h"
+
+#include "components/cbor/reader.h"
+#include "device/fido/fido_test_data.h"
+#include "device/fido/pin_internal.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/boringssl/src/include/openssl/aes.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ec_key.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
+#include "third_party/boringssl/src/include/openssl/nid.h"
+
+namespace device {
+namespace {
+
+using testing::ElementsAreArray;
+using testing::Not;
+
+class PINProtocolTest : public ::testing::TestWithParam<PINUVAuthProtocol> {
+ protected:
+  void SetUp() override {
+    peer_key_.reset(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+    CHECK(EC_KEY_generate_key(peer_key_.get()));
+  }
+
+  const pin::Protocol& pin_protocol() {
+    return pin::ProtocolVersion(GetParam());
+  }
+
+  pin::KeyAgreementResponse PeerKeyAgreement() {
+    std::array<uint8_t, kP256X962Length> peer_x962;
+    CHECK_EQ(EC_POINT_point2oct(EC_KEY_get0_group(peer_key_.get()),
+                                EC_KEY_get0_public_key(peer_key_.get()),
+                                POINT_CONVERSION_UNCOMPRESSED, peer_x962.data(),
+                                peer_x962.size(), nullptr /* BN_CTX */),
+             peer_x962.size());
+    const base::Optional<pin::KeyAgreementResponse> peer_response =
+        pin::KeyAgreementResponse::ParseFromCOSE(
+            pin::EncodeCOSEPublicKey(peer_x962));
+    CHECK(peer_response);
+    return *peer_response;
+  }
+
+  EC_KEY* peer_key() { return peer_key_.get(); }
+
+  bssl::UniquePtr<EC_KEY> peer_key_;
+};
+
+TEST_P(PINProtocolTest, EncapsulateDecapsulate) {
+  // Encapsulate() and CalculateSharedKey() should yield the same shared secret.
+  std::vector<uint8_t> shared_key;
+  const std::array<uint8_t, kP256X962Length> platform_x962 =
+      pin_protocol().Encapsulate(PeerKeyAgreement(), &shared_key);
+
+  const bssl::UniquePtr<EC_GROUP> p256(
+      EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+  const bssl::UniquePtr<EC_POINT> platform_point(EC_POINT_new(p256.get()));
+  ASSERT_TRUE(EC_POINT_oct2point(p256.get(), platform_point.get(),
+                                 platform_x962.data(), platform_x962.size(),
+                                 /*ctx=*/nullptr));
+
+  EXPECT_EQ(shared_key.size(),
+            GetParam() == PINUVAuthProtocol::kV1 ? 32u : 64u);
+  EXPECT_THAT(
+      pin_protocol().CalculateSharedKey(peer_key(), platform_point.get()),
+      ElementsAreArray(shared_key));
+}
+
+TEST_P(PINProtocolTest, EncryptDecrypt) {
+  constexpr char kTestPlaintext[] = "pinprotocoltestpinprotocoltest_";
+  static_assert(sizeof(kTestPlaintext) % AES_BLOCK_SIZE == 0u, "");
+  std::vector<uint8_t> shared_key;
+  pin_protocol().Encapsulate(PeerKeyAgreement(), &shared_key);
+
+  const std::vector<uint8_t> ciphertext = pin_protocol().Encrypt(
+      shared_key, base::as_bytes(base::make_span(kTestPlaintext)));
+  ASSERT_FALSE(ciphertext.empty());
+
+  EXPECT_THAT(pin_protocol().Decrypt(shared_key, ciphertext),
+              ElementsAreArray(base::make_span(kTestPlaintext)));
+}
+
+TEST_P(PINProtocolTest, AuthenticateVerify) {
+  constexpr char kTestMessage[] = "pin protocol test";
+  std::vector<uint8_t> shared_key;
+  pin_protocol().Encapsulate(PeerKeyAgreement(), &shared_key);
+
+  const std::vector<uint8_t> mac = pin_protocol().Authenticate(
+      shared_key, base::as_bytes(base::make_span(kTestMessage)));
+  ASSERT_FALSE(mac.empty());
+
+  EXPECT_TRUE(pin_protocol().Verify(
+      shared_key, base::as_bytes(base::make_span(kTestMessage)), mac));
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         PINProtocolTest,
+                         testing::Values(PINUVAuthProtocol::kV1,
+                                         PINUVAuthProtocol::kV2));
+
+}  // namespace
+}  // namespace device
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc
index 6004eaac..3f2efed 100644
--- a/device/fido/virtual_ctap2_device.cc
+++ b/device/fido/virtual_ctap2_device.cc
@@ -127,21 +127,6 @@
                                        data.value_or(std::vector<uint8_t>{}))));
 }
 
-// CheckPINToken returns true iff |pin_auth| is a valid authentication of
-// |data| given that the PIN token in effect is |pin_token|.
-bool CheckPINToken(base::span<const uint8_t> pin_token,
-                   base::span<const uint8_t> pin_auth,
-                   base::span<const uint8_t> data) {
-  uint8_t calculated_pin_auth[SHA256_DIGEST_LENGTH];
-  unsigned hmac_bytes;
-  CHECK(HMAC(EVP_sha256(), pin_token.data(), pin_token.size(), data.data(),
-             data.size(), calculated_pin_auth, &hmac_bytes));
-  DCHECK_EQ(sizeof(calculated_pin_auth), static_cast<size_t>(hmac_bytes));
-
-  return pin_auth.size() == 16 &&
-         CRYPTO_memcmp(pin_auth.data(), calculated_pin_auth, 16) == 0;
-}
-
 std::vector<uint8_t> ConstructSignatureBuffer(
     const AuthenticatorData& authenticator_data,
     base::span<const uint8_t, kClientDataHashLength> client_data_hash) {
@@ -233,9 +218,16 @@
 // possession of the PIN, given that |shared_key| is the result of the ECDH key
 // agreement.
 CtapDeviceResponseCode ConfirmPresentedPIN(
+    PINUVAuthProtocol pin_protocol,
     VirtualCtap2Device::State* state,
-    const uint8_t shared_key[SHA256_DIGEST_LENGTH],
+    const std::vector<uint8_t>& shared_key,
     const std::vector<uint8_t>& encrypted_pin_hash) {
+  constexpr size_t kPinHashSize = AES_BLOCK_SIZE;
+  if (encrypted_pin_hash.empty() ||
+      encrypted_pin_hash.size() % kPinHashSize != 0u) {
+    return CtapDeviceResponseCode::kCtap2ErrPinInvalid;
+  }
+
   if (state->pin_retries == 0) {
     return CtapDeviceResponseCode::kCtap2ErrPinBlocked;
   }
@@ -246,16 +238,16 @@
   state->pin_retries--;
   state->pin_retries_since_insertion++;
 
-  DCHECK_EQ(encrypted_pin_hash.size() % AES_BLOCK_SIZE, 0ul);
-  uint8_t pin_hash[AES_BLOCK_SIZE];
-  pin::Decrypt(shared_key, encrypted_pin_hash, pin_hash);
+  std::vector<uint8_t> pin_hash = pin::ProtocolVersion(pin_protocol)
+                                      .Decrypt(shared_key, encrypted_pin_hash);
 
   uint8_t calculated_pin_hash[SHA256_DIGEST_LENGTH];
   SHA256(reinterpret_cast<const uint8_t*>(state->pin.data()), state->pin.size(),
          calculated_pin_hash);
+  static_assert(sizeof(calculated_pin_hash) >= kPinHashSize, "");
 
-  if (state->pin.empty() ||
-      CRYPTO_memcmp(pin_hash, calculated_pin_hash, sizeof(pin_hash)) != 0) {
+  if (state->pin.empty() || pin_hash.size() != kPinHashSize ||
+      CRYPTO_memcmp(pin_hash.data(), calculated_pin_hash, kPinHashSize) != 0) {
     if (state->pin_retries == 0) {
       return CtapDeviceResponseCode::kCtap2ErrPinBlocked;
     }
@@ -275,24 +267,13 @@
 
 // SetPIN sets the current PIN based on the ciphertext in |encrypted_pin|, given
 // that |shared_key| is the result of the ECDH key agreement.
-CtapDeviceResponseCode SetPIN(VirtualCtap2Device::State* state,
-                              const uint8_t shared_key[SHA256_DIGEST_LENGTH],
+CtapDeviceResponseCode SetPIN(PINUVAuthProtocol protocol,
+                              VirtualCtap2Device::State* state,
+                              const std::vector<uint8_t>& shared_key,
                               const std::vector<uint8_t>& encrypted_pin,
                               const std::vector<uint8_t>& pin_auth) {
-  // See
-  // https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-client-to-authenticator-protocol-v2.0-rd-20180702.html#settingNewPin
-  uint8_t calculated_pin_auth[SHA256_DIGEST_LENGTH];
-  unsigned hmac_bytes;
-  CHECK(HMAC(EVP_sha256(), shared_key, SHA256_DIGEST_LENGTH,
-             encrypted_pin.data(), encrypted_pin.size(), calculated_pin_auth,
-             &hmac_bytes));
-  DCHECK_EQ(sizeof(calculated_pin_auth), static_cast<size_t>(hmac_bytes));
-
-  static_assert(sizeof(calculated_pin_auth) >= 16,
-                "calculated_pin_auth is expected to be at least 16 bytes");
-  if (pin_auth.size() != 16 ||
-      CRYPTO_memcmp(calculated_pin_auth, pin_auth.data(), pin_auth.size()) !=
-          0) {
+  const pin::Protocol& pin_protocol = pin::ProtocolVersion(protocol);
+  if (!pin_protocol.Verify(shared_key, encrypted_pin, pin_auth)) {
     return CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid;
   }
 
@@ -300,8 +281,8 @@
     return CtapDeviceResponseCode::kCtap2ErrPinPolicyViolation;
   }
 
-  std::vector<uint8_t> plaintext_pin(encrypted_pin.size());
-  pin::Decrypt(shared_key, encrypted_pin, plaintext_pin.data());
+  std::vector<uint8_t> plaintext_pin =
+      pin_protocol.Decrypt(shared_key, encrypted_pin);
 
   size_t padding_len = 0;
   while (padding_len < plaintext_pin.size() &&
@@ -355,8 +336,8 @@
   if (pinauth_it == request_map.end() || !pinauth_it->second.is_bytestring()) {
     return CtapDeviceResponseCode::kCtap2ErrCBORUnexpectedType;
   }
-  if (!CheckPINToken(pin_token, pinauth_it->second.GetBytestring(),
-                     pinauth_bytes)) {
+  if (!pin::ProtocolVersion(*protocol).Verify(
+          pin_token, pinauth_bytes, pinauth_it->second.GetBytestring())) {
     return CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid;
   }
   return CtapDeviceResponseCode::kSuccess;
@@ -446,13 +427,12 @@
   return WriteCBOR(cbor::Value(std::move(response_map)), allow_invalid_utf8);
 }
 
-std::array<uint8_t, 32> GenerateAndEncryptToken(
-    base::span<const uint8_t, SHA256_DIGEST_LENGTH> shared_key,
+std::vector<uint8_t> GenerateAndEncryptToken(
+    PINUVAuthProtocol pin_protocol,
+    base::span<const uint8_t> shared_key,
     base::span<uint8_t, 32> pin_token) {
   RAND_bytes(pin_token.data(), pin_token.size());
-  std::array<uint8_t, pin_token.size()> encrypted_pin_token;
-  pin::Encrypt(shared_key.data(), pin_token, encrypted_pin_token.data());
-  return encrypted_pin_token;
+  return pin::ProtocolVersion(pin_protocol).Encrypt(shared_key, pin_token);
 }
 
 }  // namespace
@@ -849,11 +829,12 @@
       }
 
       // Verify pinUvAuthParam.
-      if (CheckPINToken(pin_token, *pin_auth, client_data_hash)) {
-        uv = true;
-      } else {
+      if (!pin::ProtocolVersion(*pin_protocol)
+               .Verify(pin_token, client_data_hash, *pin_auth)) {
         return CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid;
       }
+
+      uv = true;
     }
 
     if (is_make_credential && !uv) {
@@ -1290,6 +1271,11 @@
       NOTREACHED();
       return CtapDeviceResponseCode::kCtap2ErrMissingParameter;
     }
+    if (!request.pin_protocol) {
+      return CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid;
+    }
+    const pin::Protocol& pin_protocol =
+        pin::ProtocolVersion(*request.pin_protocol);
 
     const auto& x962 = request.hmac_secret->public_key_x962;
     bssl::UniquePtr<EC_GROUP> p256(
@@ -1301,9 +1287,8 @@
       return CtapDeviceResponseCode::kCtap1ErrInvalidParameter;
     }
 
-    uint8_t shared_key[SHA256_DIGEST_LENGTH];
-    pin::CalculateSharedKey(mutable_state()->ecdh_key.get(),
-                            platform_point.get(), shared_key);
+    std::vector<uint8_t> shared_key = pin_protocol.CalculateSharedKey(
+        mutable_state()->ecdh_key.get(), platform_point.get());
 
     const auto& encrypted_salts = request.hmac_secret->encrypted_salts;
     if (encrypted_salts.size() != 32 && encrypted_salts.size() != 64) {
@@ -1311,26 +1296,27 @@
       return CtapDeviceResponseCode::kCtap1ErrInvalidParameter;
     }
 
-    uint8_t salts[64];
-    pin::Decrypt(shared_key, encrypted_salts, salts);
+    std::vector<uint8_t> salts =
+        pin_protocol.Decrypt(shared_key, encrypted_salts);
+    CHECK_EQ(salts.size(), encrypted_salts.size());
 
-    if (pin::MakePinAuth(shared_key, encrypted_salts) !=
+    if (pin_protocol.Authenticate(shared_key, encrypted_salts) !=
         request.hmac_secret->salts_auth) {
       NOTREACHED();
       return CtapDeviceResponseCode::kCtap1ErrInvalidParameter;
     }
 
     hmac_salt1.emplace();
-    memcpy(hmac_salt1->data(), salts, hmac_salt1->size());
+    memcpy(hmac_salt1->data(), salts.data(), hmac_salt1->size());
     if (encrypted_salts.size() == 64) {
       hmac_salt2.emplace();
-      memcpy(hmac_salt2->data(), salts + hmac_salt1->size(),
+      memcpy(hmac_salt2->data(), salts.data() + hmac_salt1->size(),
              hmac_salt2->size());
     }
 
     hmac_shared_key.emplace();
-    CHECK_EQ(hmac_shared_key->size(), sizeof(shared_key));
-    memcpy(hmac_shared_key->data(), shared_key, sizeof(shared_key));
+    CHECK_EQ(hmac_shared_key->size(), shared_key.size());
+    memcpy(hmac_shared_key->data(), shared_key.data(), shared_key.size());
   }
 
   // This implementation does not sort credentials by creation time as the spec
@@ -1377,8 +1363,10 @@
                        &hmac_result[sizeof(hmac_result)]);
       }
 
-      std::vector<uint8_t> encrypted_outputs(outputs.size());
-      pin::Encrypt(hmac_shared_key->data(), outputs, encrypted_outputs.data());
+      std::vector<uint8_t> encrypted_outputs =
+          pin::ProtocolVersion(*request.pin_protocol)
+              .Encrypt(*hmac_shared_key, outputs);
+      CHECK_EQ(encrypted_outputs.size(), outputs.size());
 
       extensions_map.emplace(kExtensionHmacSecret,
                              std::move(encrypted_outputs));
@@ -1586,8 +1574,7 @@
       const auto peer_key =
           GetPINKey(request_map, pin::RequestKey::kKeyAgreement);
 
-      if (!encrypted_pin || (encrypted_pin->size() % AES_BLOCK_SIZE) != 0 ||
-          !pin_auth || !peer_key) {
+      if (!encrypted_pin || !pin_auth || !peer_key) {
         return CtapDeviceResponseCode::kCtap2ErrMissingParameter;
       }
 
@@ -1595,17 +1582,19 @@
         return CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid;
       }
 
-      uint8_t shared_key[SHA256_DIGEST_LENGTH];
       if (!mutable_state()->ecdh_key) {
         // kGetKeyAgreement should have been called first.
         NOTREACHED();
         return CtapDeviceResponseCode::kCtap2ErrPinTokenExpired;
       }
-      pin::CalculateSharedKey(mutable_state()->ecdh_key.get(), peer_key->get(),
-                              shared_key);
+      std::vector<uint8_t> shared_key =
+          pin::ProtocolVersion(*pin_protocol)
+              .CalculateSharedKey(mutable_state()->ecdh_key.get(),
+                                  peer_key->get());
 
       CtapDeviceResponseCode err =
-          SetPIN(mutable_state(), shared_key, *encrypted_pin, *pin_auth);
+          SetPIN(*pin_protocol, mutable_state(), shared_key, *encrypted_pin,
+                 *pin_auth);
       if (err != CtapDeviceResponseCode::kSuccess) {
         return err;
       }
@@ -1628,25 +1617,29 @@
       const auto peer_key =
           GetPINKey(request_map, pin::RequestKey::kKeyAgreement);
 
-      if (!encrypted_pin_hash || encrypted_pin_hash->size() != AES_BLOCK_SIZE ||
-          !encrypted_new_pin ||
-          (encrypted_new_pin->size() % AES_BLOCK_SIZE) != 0 || !pin_auth ||
-          !peer_key) {
+      if (!encrypted_pin_hash || !encrypted_new_pin || !pin_auth || !peer_key) {
         return CtapDeviceResponseCode::kCtap2ErrMissingParameter;
       }
 
-      uint8_t shared_key[SHA256_DIGEST_LENGTH];
-      pin::CalculateSharedKey(mutable_state()->ecdh_key.get(), peer_key->get(),
-                              shared_key);
+      if (!mutable_state()->ecdh_key) {
+        // kGetKeyAgreement should have been called first.
+        NOTREACHED();
+        return CtapDeviceResponseCode::kCtap2ErrPinTokenExpired;
+      }
+      std::vector<uint8_t> shared_key =
+          pin::ProtocolVersion(*pin_protocol)
+              .CalculateSharedKey(mutable_state()->ecdh_key.get(),
+                                  peer_key->get());
 
-      CtapDeviceResponseCode err =
-          ConfirmPresentedPIN(mutable_state(), shared_key, *encrypted_pin_hash);
+      CtapDeviceResponseCode err = ConfirmPresentedPIN(
+          *pin_protocol, mutable_state(), shared_key, *encrypted_pin_hash);
       if (err != CtapDeviceResponseCode::kSuccess) {
         RegenerateKeyAgreementKey();
         return err;
       }
 
-      err = SetPIN(mutable_state(), shared_key, *encrypted_new_pin, *pin_auth);
+      err = SetPIN(*pin_protocol, mutable_state(), shared_key,
+                   *encrypted_new_pin, *pin_auth);
       if (err != CtapDeviceResponseCode::kSuccess) {
         return err;
       }
@@ -1668,8 +1661,7 @@
       const auto peer_key =
           GetPINKey(request_map, pin::RequestKey::kKeyAgreement);
 
-      if (!encrypted_pin_hash || encrypted_pin_hash->size() != AES_BLOCK_SIZE ||
-          !peer_key) {
+      if (!encrypted_pin_hash || !peer_key) {
         return CtapDeviceResponseCode::kCtap2ErrMissingParameter;
       }
 
@@ -1698,17 +1690,18 @@
         }
       }
 
-      uint8_t shared_key[SHA256_DIGEST_LENGTH];
       if (!mutable_state()->ecdh_key) {
         // kGetKeyAgreement should have been called first.
         NOTREACHED();
         return CtapDeviceResponseCode::kCtap2ErrPinTokenExpired;
       }
-      pin::CalculateSharedKey(mutable_state()->ecdh_key.get(), peer_key->get(),
-                              shared_key);
+      std::vector<uint8_t> shared_key =
+          pin::ProtocolVersion(*pin_protocol)
+              .CalculateSharedKey(mutable_state()->ecdh_key.get(),
+                                  peer_key->get());
 
-      CtapDeviceResponseCode err =
-          ConfirmPresentedPIN(mutable_state(), shared_key, *encrypted_pin_hash);
+      CtapDeviceResponseCode err = ConfirmPresentedPIN(
+          *pin_protocol, mutable_state(), shared_key, *encrypted_pin_hash);
       if (err != CtapDeviceResponseCode::kSuccess) {
         RegenerateKeyAgreementKey();
         return err;
@@ -1719,9 +1712,9 @@
       mutable_state()->pin_uv_token_permissions = permissions.permissions;
       mutable_state()->pin_uv_token_rpid = permissions.rp_id;
 
-      response_map.emplace(
-          static_cast<int>(pin::ResponseKey::kPINToken),
-          GenerateAndEncryptToken(shared_key, mutable_state()->pin_token));
+      response_map.emplace(static_cast<int>(pin::ResponseKey::kPINToken),
+                           GenerateAndEncryptToken(*pin_protocol, shared_key,
+                                                   mutable_state()->pin_token));
       break;
     }
 
@@ -1749,14 +1742,15 @@
         return CtapDeviceResponseCode::kCtap2ErrUvBlocked;
       }
 
-      uint8_t shared_key[SHA256_DIGEST_LENGTH];
       if (!mutable_state()->ecdh_key) {
         // kGetKeyAgreement should have been called first.
         NOTREACHED();
         return CtapDeviceResponseCode::kCtap2ErrPinTokenExpired;
       }
-      pin::CalculateSharedKey(mutable_state()->ecdh_key.get(), peer_key->get(),
-                              shared_key);
+      std::vector<uint8_t> shared_key =
+          pin::ProtocolVersion(*pin_protocol)
+              .CalculateSharedKey(mutable_state()->ecdh_key.get(),
+                                  peer_key->get());
 
       --mutable_state()->uv_retries;
 
@@ -1773,9 +1767,9 @@
       mutable_state()->pin_uv_token_permissions = permissions.permissions;
       mutable_state()->pin_uv_token_rpid = permissions.rp_id;
 
-      response_map.emplace(
-          static_cast<int>(pin::ResponseKey::kPINToken),
-          GenerateAndEncryptToken(shared_key, mutable_state()->pin_token));
+      response_map.emplace(static_cast<int>(pin::ResponseKey::kPINToken),
+                           GenerateAndEncryptToken(*pin_protocol, shared_key,
+                                                   mutable_state()->pin_token));
       break;
     }
 
diff --git a/docs/windows_shortcut_and_taskbar_handling.md b/docs/windows_shortcut_and_taskbar_handling.md
new file mode 100644
index 0000000..655d6ab8
--- /dev/null
+++ b/docs/windows_shortcut_and_taskbar_handling.md
@@ -0,0 +1,75 @@
+# Windows Shortcut and Pinned Taskbar Icon handling
+
+When Chrome is installed on Windows, it creates a shortcut on the desktop that
+launches Chrome. It also adds the same shortcut to the start menu. These
+shortcuts do not specify a profile, so they launch Chrome with the most recently
+used profile. 
+
+Windows allows users to pin applications to the taskbar. When a user
+pins an application to the taskbar, Windows looks for a desktop shortcut that
+matches the application, and if it finds one, it creates a .lnk file in the
+directory
+`<user dir>\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar.`
+If it does not find a matching desktop shortcut, it creates an 8-hex-digit
+sub-directory of
+`<user dir>\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch\ImplicitAppShortcuts\`
+and puts the .lnk file in that directory. For example, 3ffff1b1b170b31e.
+
+App windows on Windows have an
+[App User Model ID (AUMI)](https://docs.microsoft.com/en-us/windows/win32/shell/appids)
+property. For Chrome windows, this is set in
+[BrowserWindowPropertyManager::UpdateWindowProperties](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/views/frame/browser_window_property_manager_win.cc?q=BrowserWindowPropertyManager::UpdateWindowProperties),
+when a window is opened. Windows desktop shortcuts have an app model property,
+and this should match the open window's AUMI. Windows groups open windows with
+the same AUMI to a taskbar icon.
+
+There are two kinds of Chrome windows with AUMI's: browser windows, and app
+windows, which include web apps, and extensions, i.e., windows opened via
+--app-id or --app.
+
+[GetAppUserModelIdForBrowser](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/shell_integration_win.cc?q=GetAppUserModelIdForBrowser)
+constructs an AUMI for a browser window and
+[GetAppUserModelIdForApp](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/shell_integration_win.cc?q=GetAppUserModelIdForApp)
+constructs an AUMI for an app window. Each calls
+[ShellUtil::BuildAppUserModelId](https://source.chromium.org/chromium/chromium/src/+/master:chrome/installer/util/shell_util.cc;q=ShellUtil::BuildAppUserModelId)
+to construct the AUMI out of component strings.
+
+All AUMI's start with the base app id,
+[install_static::GetBaseAppId](https://source.chromium.org/chromium/chromium/src/+/master:chrome/install_static/install_util.cc?q=install_static::GetBaseAppId).
+This varies for different Chrome channels (e.g., Canary vs. Stable) and
+different Chromium-based browsers (e.g., Chrome vs. Chromium).
+
+The AUMI for a browser app has the format:
+`<BaseAppId>.<app_name>[.<profile_name>]`.
+profile_name is only appended when it's not the default profile.
+
+The AUMI for a Chrome browser window has the format:
+`<BaseAppId>[browser_suffix][.profile_name]`.
+profile_name is only appended when it's not the default profile.
+browser_suffix is only appended to the BaseAppId if the installer
+has set the kRegisterChromeBrowserSuffix command line switch, e.g.,
+on user-level installs.
+
+Since AUMI's for browser and app windows include the profile_name, each
+profile's windows will be grouped together on the taskbar.
+
+shell_integration_win.cc has a function [GetExpectedAppId](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/shell_integration_win.cc?q=GetExpectedAppid)
+to determine what the AUMI for a shortcut should be. It also has a function
+[MigrateTaskbarPins](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/shell_integration_win.cc?q=MigrateTaskbarPins)
+to migrate pinned taskbar icons if the AUMI's need to change.
+
+## Multi-profile Support
+When the user has more than one profile, the shortcuts are renamed to include
+the profile name, e.g., `Chrome.lnk` becomes `<profile name> - Chrome`.  The
+shortcut icons, both desktop and taskbar, are badged with their profile icon.
+This badged icon is also used in the tab preview for a Chrome window.
+
+## Diagnosing Issues
+To dump a taskbar icon's properties, run this command:
+
+`python \src\chromium\src\chrome\installer\tools\shortcut_properties.py --dump-all <user dir>\AppData\Roaming\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar`
+
+This shows you the properties of all the taskbar pinned icons. If the taskbar
+icon is in a subdirectory of ImplicitApps, pass that directory to
+shortcut_properties.py.
+
diff --git a/fuchsia/engine/browser/accessibility_bridge.cc b/fuchsia/engine/browser/accessibility_bridge.cc
index b45b4966..16bd613f 100644
--- a/fuchsia/engine/browser/accessibility_bridge.cc
+++ b/fuchsia/engine/browser/accessibility_bridge.cc
@@ -115,17 +115,6 @@
   TryCommit();
 }
 
-uint32_t AccessibilityBridge::ConvertToFuchsiaNodeId(int32_t ax_node_id) {
-  if (ax_node_id == root_id_) {
-    // On the Fuchsia side, the root node is indicated by id
-    // |kSemanticNodeRootId|, which is 0.
-    return kSemanticNodeRootId;
-  } else {
-    // AXNode ids are signed, Semantic Node ids are unsigned.
-    return bit_cast<uint32_t>(ax_node_id);
-  }
-}
-
 void AccessibilityBridge::AccessibilityEventReceived(
     const content::AXEventNotificationDetails& details) {
   // Updates to AXTree must be applied first.
@@ -143,7 +132,7 @@
         pending_hit_test_callbacks_.find(event.action_request_id) !=
             pending_hit_test_callbacks_.end()) {
       fuchsia::accessibility::semantics::Hit hit;
-      hit.set_node_id(ConvertToFuchsiaNodeId(event.id));
+      hit.set_node_id(ConvertToFuchsiaNodeId(event.id, root_id_));
 
       // Run the pending callback with the hit.
       pending_hit_test_callbacks_[event.action_request_id](std::move(hit));
@@ -236,7 +225,7 @@
   if (node->id() != root_id_) {
     to_send_.push_back(
         SemanticUpdateOrDelete(SemanticUpdateOrDelete::Type::DELETE, {},
-                               ConvertToFuchsiaNodeId(node->id())));
+                               ConvertToFuchsiaNodeId(node->id(), root_id_)));
   }
   for (ui::AXNode* child : node->children())
     DeleteSubtree(child);
diff --git a/fuchsia/engine/browser/accessibility_bridge.h b/fuchsia/engine/browser/accessibility_bridge.h
index 8165b12..35669c5 100644
--- a/fuchsia/engine/browser/accessibility_bridge.h
+++ b/fuchsia/engine/browser/accessibility_bridge.h
@@ -86,10 +86,6 @@
   // Callback for SemanticTree::CommitUpdates.
   void OnCommitComplete();
 
-  // Converts AXNode ids to Semantic Node ids, and handles special casing of
-  // the root.
-  uint32_t ConvertToFuchsiaNodeId(int32_t ax_node_id);
-
   // Deletes all nodes in subtree rooted at and including |node|, unless
   // |node| is the root of the tree. |tree| and |node| are owned by the
   // accessibility bridge.
diff --git a/fuchsia/engine/browser/ax_tree_converter.cc b/fuchsia/engine/browser/ax_tree_converter.cc
index 7fa4346..43f9089 100644
--- a/fuchsia/engine/browser/ax_tree_converter.cc
+++ b/fuchsia/engine/browser/ax_tree_converter.cc
@@ -8,9 +8,11 @@
 #include <fuchsia/ui/gfx/cpp/fidl.h>
 #include <fuchsia/ui/views/cpp/fidl.h>
 #include <lib/ui/scenic/cpp/commands.h>
+#include <stdint.h>
 #include <vector>
 
 #include "base/bit_cast.h"
+#include "base/numerics/safe_conversions.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_tree_id.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -19,6 +21,14 @@
 
 namespace {
 
+// Fuchsia's default root node ID.
+constexpr uint32_t kFuchsiaRootNodeId = 0;
+
+// Remmaped value for an AxNode ID that is 0 and is not a root.
+// Value is chosen specifically to be outside the range of a 32-bit signed int,
+// so as to not conflict with other values used by Chromium.
+constexpr uint32_t kZeroIdRemappedForFuchsia = 1u + INT32_MAX;
+
 fuchsia::accessibility::semantics::Role ConvertRole(ax::mojom::Role role) {
   if (role == ax::mojom::Role::kButton)
     return fuchsia::accessibility::semantics::Role::BUTTON;
@@ -152,7 +162,7 @@
   std::vector<uint32_t> child_ids;
   child_ids.reserve(ids.size());
   for (auto i : ids) {
-    child_ids.push_back(bit_cast<uint32_t>(i));
+    child_ids.push_back(base::checked_cast<uint32_t>(i));
   }
   return child_ids;
 }
@@ -182,7 +192,7 @@
 fuchsia::accessibility::semantics::Node AXNodeDataToSemanticNode(
     const ui::AXNodeData& node) {
   fuchsia::accessibility::semantics::Node fuchsia_node;
-  fuchsia_node.set_node_id(bit_cast<uint32_t>(node.id));
+  fuchsia_node.set_node_id(base::checked_cast<uint32_t>(node.id));
   fuchsia_node.set_role(ConvertRole(node.role));
   fuchsia_node.set_states(ConvertStates(node));
   fuchsia_node.set_attributes(ConvertAttributes(node));
@@ -223,3 +233,16 @@
       return false;
   }
 }
+
+uint32_t ConvertToFuchsiaNodeId(int32_t ax_node_id, int32_t ax_root_node_id) {
+  if (ax_node_id == ax_root_node_id)
+    return kFuchsiaRootNodeId;
+
+  if (ax_node_id == kFuchsiaRootNodeId) {
+    // This AxNode is not the root, but its ID is the same as Fuchsia's root ID.
+    // We remap it to something different to not create a confflict.
+    return kZeroIdRemappedForFuchsia;
+  }
+
+  return base::checked_cast<uint32_t>(ax_node_id);
+}
diff --git a/fuchsia/engine/browser/ax_tree_converter.h b/fuchsia/engine/browser/ax_tree_converter.h
index 839c988..bdb8e6e 100644
--- a/fuchsia/engine/browser/ax_tree_converter.h
+++ b/fuchsia/engine/browser/ax_tree_converter.h
@@ -24,4 +24,13 @@
 bool ConvertAction(fuchsia::accessibility::semantics::Action fuchsia_action,
                    ax::mojom::Action* mojom_action);
 
+// Converts |ax_node_id|, which is signed, to a Fuchsia node ID, which is
+// unsigned.
+// Fuchsia requires root node IDs to be zero. This function ensures
+// that the conversion takes that into account.
+// If |ax_node_id| is 0 and is not the root, we return the
+// MAX(int32_t) + 1, which is a number that will never conflict with other IDs.
+WEB_ENGINE_EXPORT uint32_t ConvertToFuchsiaNodeId(int32_t ax_node_id,
+                                                  int32_t ax_root_node_id);
+
 #endif  // FUCHSIA_ENGINE_BROWSER_AX_TREE_CONVERTER_H_
diff --git a/fuchsia/engine/browser/ax_tree_converter_unittest.cc b/fuchsia/engine/browser/ax_tree_converter_unittest.cc
index 16bdfba..cec422f3 100644
--- a/fuchsia/engine/browser/ax_tree_converter_unittest.cc
+++ b/fuchsia/engine/browser/ax_tree_converter_unittest.cc
@@ -41,6 +41,9 @@
                                 base::StringPiece description,
                                 ax::mojom::CheckedState checked_state) {
   ui::AXNodeData node;
+  // Important! ID must be set to zero here because its default value (-1), will
+  // fail when getting converted to an unsigned int (Fuchsia's ID format).
+  node.id = 0;
   node.role = role;
   node.AddAction(action);
   node.AddIntAttribute(ax::mojom::IntAttribute::kCheckedState,
@@ -113,8 +116,9 @@
   states.set_hidden(false);
   states.set_selected(false);
   auto expected_node = CreateSemanticNode(
-      source_node_data.id, Role::BUTTON, std::move(attributes),
-      std::move(states), std::vector<Action>{Action::SET_FOCUS},
+      static_cast<uint32_t>(source_node_data.id), Role::BUTTON,
+      std::move(attributes), std::move(states),
+      std::vector<Action>{Action::SET_FOCUS},
       std::vector<uint32_t>{kChildId1, kChildId2, kChildId3}, box, mat.value);
 
   EXPECT_TRUE(fidl::Equals(converted_node, expected_node));
@@ -122,6 +126,7 @@
 
 TEST_F(AXTreeConverterTest, SomeFieldsSetAndEqual) {
   ui::AXNodeData source_node_data;
+  source_node_data.id = 0;
   source_node_data.AddAction(ax::mojom::Action::kFocus);
   source_node_data.AddAction(ax::mojom::Action::kSetValue);
   source_node_data.child_ids = std::vector<int32_t>{kChildId1};
@@ -133,10 +138,11 @@
             converted_node.node_id());
 
   Node expected_node;
-  expected_node.set_node_id(source_node_data.id);
+  expected_node.set_node_id(static_cast<uint32_t>(source_node_data.id));
   expected_node.set_actions(
       std::vector<Action>{Action::SET_FOCUS, Action::SET_VALUE});
-  expected_node.set_child_ids(std::vector<uint32_t>{kChildId1});
+  expected_node.set_child_ids(
+      std::vector<uint32_t>{static_cast<uint32_t>(kChildId1)});
   expected_node.set_role(Role::IMAGE);
   States states;
   states.set_hidden(false);
@@ -198,4 +204,19 @@
   EXPECT_FALSE(fidl::Equals(converted_node, expected_node));
 }
 
+TEST_F(AXTreeConverterTest, ConvertToFuchsiaNodeId) {
+  // Root AxNode is 0, Fuchsia is also 0.
+  EXPECT_EQ(0u, ConvertToFuchsiaNodeId(0, 0));
+
+  // Root AxNode is not 0, Fuchsia is still 0.
+  EXPECT_EQ(0u, ConvertToFuchsiaNodeId(2, 2));
+
+  // Regular AxNode is 0, Fuchsia can't be 0.
+  EXPECT_EQ(static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) + 1,
+            ConvertToFuchsiaNodeId(0, 2));
+
+  // Regular AxNode is not 0, Fuchsia is same value.
+  EXPECT_EQ(10u, ConvertToFuchsiaNodeId(10, 0));
+}
+
 }  // namespace
diff --git a/fuchsia/engine/web_engine_integration_test.cc b/fuchsia/engine/web_engine_integration_test.cc
index 329885af..56a0d50 100644
--- a/fuchsia/engine/web_engine_integration_test.cc
+++ b/fuchsia/engine/web_engine_integration_test.cc
@@ -690,9 +690,8 @@
 #endif
 class MAYBE_VulkanWebEngineIntegrationTest : public WebEngineIntegrationTest {};
 
-// TODO(crbug.com/1104563): Flakily times-out.
 TEST_F(MAYBE_VulkanWebEngineIntegrationTest,
-       DISABLED_WebGLContextPresentWithVulkanFeature) {
+       WebGLContextPresentWithVulkanFeature) {
   fuchsia::web::CreateContextParams create_params = DefaultContextParams();
   create_params.set_features(fuchsia::web::ContextFeatureFlags::VULKAN);
   CreateContextAndFrame(std::move(create_params));
diff --git a/fuchsia/runners/cast/cast_runner.cc b/fuchsia/runners/cast/cast_runner.cc
index fa15d03..af4f3a3 100644
--- a/fuchsia/runners/cast/cast_runner.cc
+++ b/fuchsia/runners/cast/cast_runner.cc
@@ -67,6 +67,9 @@
   return false;
 }
 
+// Ephemeral remote debugging port used by child contexts.
+const uint16_t kEphemeralRemoteDebuggingPort = 0;
+
 }  // namespace
 
 CastRunner::CastRunner(bool is_headless)
@@ -226,8 +229,6 @@
   params.set_user_agent_product("CrKey");
   params.set_user_agent_version("1.43.000000");
 
-  params.set_remote_debugging_port(CastRunner::kRemoteDebuggingPort);
-
   // When tests require that VULKAN be disabled, DRM must also be disabled.
   if (disable_vulkan_for_test_) {
     *params.mutable_features() &=
@@ -248,6 +249,7 @@
 
 fuchsia::web::CreateContextParams CastRunner::GetMainContextParams() {
   fuchsia::web::CreateContextParams params = GetCommonContextParams();
+  params.set_remote_debugging_port(CastRunner::kRemoteDebuggingPort);
   *params.mutable_features() |=
       fuchsia::web::ContextFeatureFlags::NETWORK |
       fuchsia::web::ContextFeatureFlags::LEGACYMETRICS;
@@ -266,6 +268,7 @@
 CastRunner::GetIsolatedContextParamsWithFuchsiaDirs(
     std::vector<fuchsia::web::ContentDirectoryProvider> content_directories) {
   fuchsia::web::CreateContextParams params = GetCommonContextParams();
+  params.set_remote_debugging_port(kEphemeralRemoteDebuggingPort);
   params.set_content_directories(std::move(content_directories));
   isolated_services_->ConnectClient(
       params.mutable_service_directory()->NewRequest());
@@ -275,6 +278,7 @@
 fuchsia::web::CreateContextParams
 CastRunner::GetIsolatedContextParamsForCastStreaming() {
   fuchsia::web::CreateContextParams params = GetCommonContextParams();
+  params.set_remote_debugging_port(kEphemeralRemoteDebuggingPort);
   ApplyCastStreamingContextParams(&params);
   // TODO(crbug.com/1069746): Use a different FilteredServiceDirectory for Cast
   // Streaming Contexts.
diff --git a/ios/chrome/browser/crash_report/synthetic_crash_report_util.mm b/ios/chrome/browser/crash_report/synthetic_crash_report_util.mm
index f618c15..5772f318 100644
--- a/ios/chrome/browser/crash_report/synthetic_crash_report_util.mm
+++ b/ios/chrome/browser/crash_report/synthetic_crash_report_util.mm
@@ -72,6 +72,24 @@
                  "BreakpadServerParameterPrefix_memory_warning_in_progress",
                  "yes");
   }
+
+  if (previous_session.applicationState &&
+      *(previous_session.applicationState) == UIApplicationStateBackground) {
+    AppendConfig(config, "BreakpadServerParameterPrefix_crashed_in_background",
+                 "yes");
+  }
+
+  if (previous_session.terminatedDuringSessionRestoration) {
+    AppendConfig(config,
+                 "BreakpadServerParameterPrefix_crashed_during_session_restore",
+                 "yes");
+  }
+
+  if (previous_session.OSVersion) {
+    AppendConfig(config, "BreakpadServerParameterPrefix_os_version",
+                 base::SysNSStringToUTF8(previous_session.OSVersion));
+  }
+
   AppendConfig(config, "BreakpadServerParameterPrefix_platform",
                base::SysInfo::HardwareModelName());
 
diff --git a/ios/chrome/browser/crash_report/synthetic_crash_report_util_unittest.mm b/ios/chrome/browser/crash_report/synthetic_crash_report_util_unittest.mm
index 82815b5..fc681d66 100644
--- a/ios/chrome/browser/crash_report/synthetic_crash_report_util_unittest.mm
+++ b/ios/chrome/browser/crash_report/synthetic_crash_report_util_unittest.mm
@@ -37,6 +37,9 @@
   PreviousSessionInfo* previous_session = [PreviousSessionInfo sharedInstance];
   previous_session.availableDeviceStorage = kAvailableStorage;
   previous_session.didSeeMemoryWarningShortlyBeforeTerminating = YES;
+  NSString* const kOSVersion = @"OSVersion";
+  previous_session.OSVersion = kOSVersion;
+  previous_session.terminatedDuringSessionRestoration = YES;
 
   // Create crash report.
   base::ScopedTempDir temp_dir;
@@ -93,7 +96,7 @@
 
   // Verify config file content. Config file has the following format:
   // <Key1>\n<Value1Length>\n<Value1>\n...<KeyN>\n<ValueNLength>\n<ValueN>
-  ASSERT_EQ(33U, config_lines.size())
+  ASSERT_EQ(39U, config_lines.size())
       << "<content>" << config_content << "</content>";
 
   EXPECT_EQ("MinidumpDir", config_lines[0]);
@@ -144,10 +147,19 @@
   EXPECT_EQ(base::NumberToString(strlen(kYesString)), config_lines[28]);
   EXPECT_EQ(kYesString, config_lines[29]);
 
-  EXPECT_EQ("BreakpadServerParameterPrefix_platform", config_lines[30]);
+  EXPECT_EQ("BreakpadServerParameterPrefix_crashed_during_session_restore",
+            config_lines[30]);
+  EXPECT_EQ(base::NumberToString(strlen(kYesString)), config_lines[31]);
+  EXPECT_EQ(kYesString, config_lines[32]);
+
+  EXPECT_EQ("BreakpadServerParameterPrefix_os_version", config_lines[33]);
+  EXPECT_EQ(base::NumberToString(kOSVersion.length), config_lines[34]);
+  EXPECT_EQ(base::SysNSStringToUTF8(kOSVersion), config_lines[35]);
+
+  EXPECT_EQ("BreakpadServerParameterPrefix_platform", config_lines[36]);
   EXPECT_EQ(base::NumberToString(base::SysInfo::HardwareModelName().size()),
-            config_lines[31]);
-  EXPECT_EQ(base::SysInfo::HardwareModelName(), config_lines[32]);
+            config_lines[37]);
+  EXPECT_EQ(base::SysInfo::HardwareModelName(), config_lines[38]);
 
   // Read minidump file. It must be empty as there is no stack trace, but
   // Breakpad will not upload config without minidump file.
diff --git a/ios/chrome/browser/metrics/previous_session_info_private.h b/ios/chrome/browser/metrics/previous_session_info_private.h
index 6be2b24..026c0a7 100644
--- a/ios/chrome/browser/metrics/previous_session_info_private.h
+++ b/ios/chrome/browser/metrics/previous_session_info_private.h
@@ -17,6 +17,8 @@
 @property(nonatomic, assign)
     previous_session_info_constants::DeviceBatteryState deviceBatteryState;
 @property(nonatomic, assign) BOOL OSRestartedAfterPreviousSession;
+@property(nonatomic, copy) NSString* OSVersion;
+@property(nonatomic, assign) BOOL terminatedDuringSessionRestoration;
 @property(nonatomic, strong) NSMutableSet<NSString*>* connectedSceneSessionsIDs;
 
 + (void)resetSharedInstanceForTesting;
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
index ddd563cb..d46999a0 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
@@ -268,9 +268,6 @@
   // Verify keyboard is shown without the password controller.
   GREYAssertTrue([ChromeEarlGrey isKeyboardShownWithError:nil],
                  @"Keyboard Should be Shown");
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::NavigationBarCancelButton()]
-      performAction:grey_tap()];
   [[EarlGrey selectElementWithMatcher:ManualFallbackPasswordTableViewMatcher()]
       assertWithMatcher:grey_notVisible()];
 }
diff --git a/ios/chrome/browser/ui/settings/password/BUILD.gn b/ios/chrome/browser/ui/settings/password/BUILD.gn
index 3f25afa..0ac4f31 100644
--- a/ios/chrome/browser/ui/settings/password/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/password/BUILD.gn
@@ -233,7 +233,6 @@
     ":password_constants",
     "//base:base",
     "//base/test:test_support",
-    "//components/password_manager/core/common",
     "//components/strings:components_strings_grit",
     "//ios/chrome/app/strings:ios_strings_grit",
     "//ios/chrome/browser/ui/settings:settings_root_constants",
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_constants.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_constants.mm
index e1901d4..c74c413 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_constants.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_constants.mm
@@ -9,4 +9,4 @@
 #endif
 
 NSString* const kPasswordDetailsViewControllerId =
-    @"PasswordDetailsTableViewId";
+    @"kPasswordDetailsViewControllerId";
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
index 3c89c5c..0ae4468b 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
@@ -210,8 +210,6 @@
     item.identifyingIcon = [[UIImage imageNamed:image]
         imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
     item.identifyingIconEnabled = YES;
-    item.identifyingIconAccessibilityLabel =
-        l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_SHOW_BUTTON);
   }
   return item;
 }
diff --git a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
index ba4d7ced..00d88eb 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
@@ -8,9 +8,7 @@
 
 #include "base/callback.h"
 #include "base/ios/ios_util.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/ui/settings/password/passwords_settings_app_interface.h"
 #import "ios/chrome/browser/ui/settings/password/passwords_table_view_constants.h"
@@ -48,7 +46,6 @@
 // go here, the rest into the unittest.
 
 using chrome_test_util::ButtonWithAccessibilityLabel;
-using chrome_test_util::ButtonWithAccessibilityLabelId;
 using chrome_test_util::NavigationBarDoneButton;
 using chrome_test_util::SettingsDoneButton;
 using chrome_test_util::SettingsMenuBackButton;
@@ -61,11 +58,6 @@
 // it too high could result in scrolling way past the searched element.
 constexpr int kScrollAmount = 150;
 
-NSString* GetTextFieldForID(int category_id) {
-  return [NSString
-      stringWithFormat:@"%@_textField", l10n_util::GetNSString(category_id)];
-}
-
 // Returns the GREYElementInteraction* for the item on the password list with
 // the given |matcher|. It scrolls in |direction| if necessary to ensure that
 // the matched item is interactable.
@@ -92,12 +84,22 @@
     id<GREYMatcher> matcher) {
   return [[EarlGrey
       selectElementWithMatcher:grey_allOf(matcher, grey_interactable(), nil)]
-         usingSearchAction:grey_scrollToContentEdge(kGREYContentEdgeTop)
+         usingSearchAction:grey_scrollInDirection(kGREYDirectionDown,
+                                                  kScrollAmount)
       onElementWithMatcher:grey_accessibilityID(kPasswordDetailsTableViewId)];
 }
 
 // Returns the GREYElementInteraction* for the item on the deletion alert
 // identified with the given |matcher|.
+GREYElementInteraction* GetInteractionForPasswordDetailDeletionAlert(
+    id<GREYMatcher> matcher) {
+  return [[EarlGrey
+      selectElementWithMatcher:grey_allOf(matcher, grey_interactable(), nil)]
+      inRoot:grey_accessibilityID(kPasswordDetailsDeletionAlertViewId)];
+}
+
+// Returns the GREYElementInteraction* for the item on the deletion alert
+// identified with the given |matcher|.
 GREYElementInteraction* GetInteractionForPasswordsExportConfirmAlert(
     id<GREYMatcher> matcher) {
   return [[EarlGrey
@@ -118,6 +120,34 @@
   return grey_accessibilityID(kPasswordsSearchBarId);
 }
 
+id<GREYMatcher> SiteHeader() {
+  return grey_allOf(
+      grey_accessibilityLabel(
+          l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_SITE)),
+      grey_accessibilityTrait(UIAccessibilityTraitHeader), nullptr);
+}
+
+id<GREYMatcher> UsernameHeader() {
+  return grey_allOf(
+      grey_accessibilityLabel(
+          l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME)),
+      grey_accessibilityTrait(UIAccessibilityTraitHeader), nullptr);
+}
+
+id<GREYMatcher> PasswordHeader() {
+  return grey_allOf(
+      grey_accessibilityLabel(
+          l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD)),
+      grey_accessibilityTrait(UIAccessibilityTraitHeader), nullptr);
+}
+
+id<GREYMatcher> FederationHeader() {
+  return grey_allOf(
+      grey_accessibilityLabel(
+          l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_FEDERATION)),
+      grey_accessibilityTrait(UIAccessibilityTraitHeader), nullptr);
+}
+
 GREYLayoutConstraint* Below() {
   return [GREYLayoutConstraint
       layoutConstraintWithAttribute:kGREYLayoutAttributeTop
@@ -128,24 +158,39 @@
 }
 
 // Matcher for the Copy site button in Password Details view.
-id<GREYMatcher> PasswordDetailWebsite() {
+id<GREYMatcher> CopySiteButton() {
   return grey_allOf(
-      grey_accessibilityID(GetTextFieldForID(IDS_IOS_SHOW_PASSWORD_VIEW_SITE)),
-      grey_kindOfClassName(@"UITextField"), nil);
+      ButtonWithAccessibilityLabel(
+          [NSString stringWithFormat:@"%@: %@",
+                                     l10n_util::GetNSString(
+                                         IDS_IOS_SHOW_PASSWORD_VIEW_SITE),
+                                     l10n_util::GetNSString(
+                                         IDS_IOS_SETTINGS_SITE_COPY_BUTTON)]),
+      grey_interactable(), nullptr);
 }
 
 // Matcher for the Copy username button in Password Details view.
-id<GREYMatcher> PasswordDetailUsername() {
-  return grey_allOf(grey_accessibilityID(
-                        GetTextFieldForID(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME)),
-                    grey_kindOfClassName(@"UITextField"), nil);
+id<GREYMatcher> CopyUsernameButton() {
+  return grey_allOf(
+      ButtonWithAccessibilityLabel([NSString
+          stringWithFormat:@"%@: %@",
+                           l10n_util::GetNSString(
+                               IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME),
+                           l10n_util::GetNSString(
+                               IDS_IOS_SETTINGS_USERNAME_COPY_BUTTON)]),
+      grey_interactable(), nullptr);
 }
 
 // Matcher for the Copy password button in Password Details view.
-id<GREYMatcher> PasswordDetailPassword() {
-  return grey_allOf(grey_accessibilityID(
-                        GetTextFieldForID(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD)),
-                    grey_kindOfClassName(@"UITextField"), nil);
+id<GREYMatcher> CopyPasswordButton() {
+  return grey_allOf(
+      ButtonWithAccessibilityLabel([NSString
+          stringWithFormat:@"%@: %@",
+                           l10n_util::GetNSString(
+                               IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD),
+                           l10n_util::GetNSString(
+                               IDS_IOS_SETTINGS_PASSWORD_COPY_BUTTON)]),
+      grey_interactable(), nullptr);
 }
 
 // Matcher for the Show password button in Password Details view.
@@ -157,16 +202,8 @@
 
 // Matcher for the Delete button in Password Details view.
 id<GREYMatcher> DeleteButton() {
-  return grey_allOf(
-      ButtonWithAccessibilityLabelId(IDS_IOS_SETTINGS_TOOLBAR_DELETE),
-      grey_not(grey_accessibilityTrait(UIAccessibilityTraitNotEnabled)),
-      nullptr);
-}
-
-// Matcher for the Delete button in Confirmation Alert for password deletion.
-id<GREYMatcher> DeleteConfirmationButton() {
   return grey_allOf(ButtonWithAccessibilityLabel(l10n_util::GetNSString(
-                        IDS_IOS_CONFIRM_PASSWORD_DELETION)),
+                        IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON)),
                     grey_interactable(), nullptr);
 }
 
@@ -263,24 +300,10 @@
       performAction:grey_tap()];
 }
 
-void CopyPasswordDetailWithID(int detail_id) {
-  [GetInteractionForPasswordDetailItem(grey_allOf(
-      grey_accessibilityID(GetTextFieldForID(detail_id)),
-      grey_kindOfClassName(@"UITextField"), nil)) performAction:grey_tap()];
-
-  // Tap the context menu item for copying.
-  [[EarlGrey selectElementWithMatcher:PopUpMenuItemWithLabel(
-                                          IDS_IOS_SETTINGS_SITE_COPY_MENU_ITEM)]
-      performAction:grey_tap()];
-}
-
 }  // namespace
 
 // Various tests for the Save Passwords section of the settings.
-@interface PasswordsSettingsTestCase : ChromeTestCase {
-  base::test::ScopedFeatureList _featureList;
-}
-
+@interface PasswordsSettingsTestCase : ChromeTestCase
 @end
 
 @implementation PasswordsSettingsTestCase
@@ -296,18 +319,6 @@
   [super tearDown];
 }
 
-- (AppLaunchConfiguration)appConfigurationForTestCase {
-  AppLaunchConfiguration config;
-
-  // Password Check Feature is enabled for all tests. This is done because it
-  // is inefficient to use ensureAppLaunchedWithConfiguration for each test.
-  // This should be removed once test config is modified.
-  // TODO(crbug.com/1075494): Remove this once feature is launched.
-  config.features_enabled.push_back(password_manager::features::kPasswordCheck);
-
-  return config;
-}
-
 // Verifies the UI elements are accessible on the Passwords page.
 - (void)testAccessibilityOnPasswords {
   // Saving a form is needed for using the "password details" view.
@@ -345,12 +356,13 @@
   [GetInteractionForPasswordEntry(@"example.com, concrete username")
       performAction:grey_tap()];
 
-  // Check the snackbar in case of successful reauthentication.
   [PasswordSettingsAppInterface setUpMockReauthenticationModule];
   [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
                                     ReauthenticationResult::kSuccess];
 
-  CopyPasswordDetailWithID(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD);
+  // Check the snackbar in case of successful reauthentication.
+  [GetInteractionForPasswordDetailItem(CopyPasswordButton())
+      performAction:grey_tap()];
 
   NSString* snackbarLabel =
       l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE);
@@ -361,8 +373,8 @@
   // Check the snackbar in case of failed reauthentication.
   [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
                                     ReauthenticationResult::kFailure];
-
-  CopyPasswordDetailWithID(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD);
+  [GetInteractionForPasswordDetailItem(CopyPasswordButton())
+      performAction:grey_tap()];
 
   snackbarLabel =
       l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_WAS_NOT_COPIED_MESSAGE);
@@ -380,7 +392,7 @@
 
 // Checks that an attempt to show a password provides an appropriate feedback
 // when reauthentication succeeds.
-- (void)testShowPasswordAuthSucceeded {
+- (void)testShowPasswordToastAuthSucceeded {
   // Saving a form is needed for using the "password details" view.
   SaveExamplePasswordForm();
 
@@ -393,12 +405,14 @@
   [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
                                     ReauthenticationResult::kSuccess];
 
+  // Check the snackbar in case of successful reauthentication.
   [GetInteractionForPasswordDetailItem(ShowPasswordButton())
       performAction:grey_tap()];
 
-  // Ensure that password is shown.
-  [GetInteractionForPasswordDetailItem(grey_textFieldValue(
-      @"concrete password")) assertWithMatcher:grey_notNil()];
+  // Check that the password is displayed.
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityLabel(@"concrete password")]
+      assertWithMatcher:grey_sufficientlyVisible()];
 
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
       performAction:grey_tap()];
@@ -428,7 +442,8 @@
       performAction:grey_tap()];
 
   // Check that the password is not displayed.
-  [[EarlGrey selectElementWithMatcher:grey_textFieldValue(@"concrete password")]
+  [[EarlGrey
+      selectElementWithMatcher:grey_accessibilityLabel(@"concrete password")]
       assertWithMatcher:grey_nil()];
 
   // Note that there is supposed to be no message (cf. the case of the copy
@@ -453,7 +468,8 @@
   [GetInteractionForPasswordEntry(@"example.com, concrete username")
       performAction:grey_tap()];
 
-  CopyPasswordDetailWithID(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME);
+  [GetInteractionForPasswordDetailItem(CopyUsernameButton())
+      performAction:grey_tap()];
   NSString* snackbarLabel =
       l10n_util::GetNSString(IDS_IOS_SETTINGS_USERNAME_WAS_COPIED_MESSAGE);
   // The tap checks the existence of the snackbar and also closes it.
@@ -478,8 +494,8 @@
   [GetInteractionForPasswordEntry(@"example.com, concrete username")
       performAction:grey_tap()];
 
-  CopyPasswordDetailWithID(IDS_IOS_SHOW_PASSWORD_VIEW_SITE);
-
+  [GetInteractionForPasswordDetailItem(CopySiteButton())
+      performAction:grey_tap()];
   NSString* snackbarLabel =
       l10n_util::GetNSString(IDS_IOS_SETTINGS_SITE_WAS_COPIED_MESSAGE);
   // The tap checks the existence of the snackbar and also closes it.
@@ -505,16 +521,11 @@
   [GetInteractionForPasswordEntry(@"example.com, concrete username")
       performAction:grey_tap()];
 
-  [PasswordSettingsAppInterface setUpMockReauthenticationModule];
-  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                    ReauthenticationResult::kSuccess];
-
-  [[EarlGrey selectElementWithMatcher:NavigationBarEditButton()]
+  [GetInteractionForPasswordDetailItem(DeleteButton())
       performAction:grey_tap()];
 
-  [[EarlGrey selectElementWithMatcher:DeleteButton()] performAction:grey_tap()];
-
-  [[EarlGrey selectElementWithMatcher:DeleteConfirmationButton()]
+  [GetInteractionForPasswordDetailDeletionAlert(ButtonWithAccessibilityLabel(
+      l10n_util::GetNSString(IDS_IOS_CONFIRM_PASSWORD_DELETION)))
       performAction:grey_tap()];
 
   // Wait until the alert and the detail view are dismissed.
@@ -565,16 +576,11 @@
   [GetInteractionForPasswordEntry(@"example.com, concrete username")
       performAction:grey_tap()];
 
-  [PasswordSettingsAppInterface setUpMockReauthenticationModule];
-  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                    ReauthenticationResult::kSuccess];
-
-  [[EarlGrey selectElementWithMatcher:NavigationBarEditButton()]
+  [GetInteractionForPasswordDetailItem(DeleteButton())
       performAction:grey_tap()];
 
-  [[EarlGrey selectElementWithMatcher:DeleteButton()] performAction:grey_tap()];
-
-  [[EarlGrey selectElementWithMatcher:DeleteConfirmationButton()]
+  [GetInteractionForPasswordDetailDeletionAlert(ButtonWithAccessibilityLabel(
+      l10n_util::GetNSString(IDS_IOS_CONFIRM_PASSWORD_DELETION)))
       performAction:grey_tap()];
 
   // Wait until the alert and the detail view are dismissed.
@@ -617,12 +623,11 @@
 
   [GetInteractionForPasswordEntry(@"blocked.com") performAction:grey_tap()];
 
-  [[EarlGrey selectElementWithMatcher:NavigationBarEditButton()]
+  [GetInteractionForPasswordDetailItem(DeleteButton())
       performAction:grey_tap()];
 
-  [[EarlGrey selectElementWithMatcher:DeleteButton()] performAction:grey_tap()];
-
-  [[EarlGrey selectElementWithMatcher:DeleteConfirmationButton()]
+  [GetInteractionForPasswordDetailDeletionAlert(ButtonWithAccessibilityLabel(
+      l10n_util::GetNSString(IDS_IOS_CONFIRM_PASSWORD_DELETION)))
       performAction:grey_tap()];
 
   // Wait until the alert and the detail view are dismissed.
@@ -666,17 +671,11 @@
   [GetInteractionForPasswordEntry(@"example.com, concrete username")
       performAction:grey_tap()];
 
-  [PasswordSettingsAppInterface setUpMockReauthenticationModule];
-  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                    ReauthenticationResult::kSuccess];
-
-  [[EarlGrey selectElementWithMatcher:NavigationBarEditButton()]
+  [GetInteractionForPasswordDetailItem(DeleteButton())
       performAction:grey_tap()];
 
-  [[EarlGrey selectElementWithMatcher:DeleteButton()] performAction:grey_tap()];
-
   // Tap the alert's Cancel button to cancel.
-  if ([ChromeEarlGrey isIPadIdiom]) {
+  if (base::ios::IsRunningOnOrLater(13, 2, 0) && [ChromeEarlGrey isIPadIdiom]) {
     [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
                                             kPasswordDetailsTableViewId)]
         performAction:grey_tap()];
@@ -690,10 +689,10 @@
         performAction:grey_tap()];
   }
 
-  // Check that the current view is still the detail view.
-  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
-                                          kPasswordDetailsTableViewId)]
-      assertWithMatcher:grey_notNil()];
+  // Check that the current view is still the detail view, by locating the Copy
+  // button.
+  [[EarlGrey selectElementWithMatcher:CopyPasswordButton()]
+      assertWithMatcher:grey_sufficientlyVisible()];
 
   // Verify that the deletion did not happen.
   GREYAssertEqual(1u, [PasswordSettingsAppInterface passwordStoreResultsCount],
@@ -733,7 +732,7 @@
 
   // Check that the current view is not the detail view, by failing to locate
   // the Copy button.
-  [[EarlGrey selectElementWithMatcher:PasswordDetailPassword()]
+  [[EarlGrey selectElementWithMatcher:CopyPasswordButton()]
       assertWithMatcher:grey_nil()];
 
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
@@ -742,6 +741,77 @@
       performAction:grey_tap()];
 }
 
+// Checks that attempts to copy the site via the context menu item provide an
+// appropriate feedback.
+- (void)testCopySiteMenuItem {
+  // Saving a form is needed for using the "password details" view.
+  SaveExamplePasswordForm();
+
+  OpenPasswordSettings();
+
+  [GetInteractionForPasswordEntry(@"example.com, concrete username")
+      performAction:grey_tap()];
+
+  // Tap the site cell to display the context menu.
+  [GetInteractionForPasswordDetailItem(grey_accessibilityLabel(
+      @"https://example.com/")) performAction:grey_tap()];
+
+  // Tap the context menu item for copying.
+  [[EarlGrey selectElementWithMatcher:PopUpMenuItemWithLabel(
+                                          IDS_IOS_SETTINGS_SITE_COPY_MENU_ITEM)]
+      performAction:grey_tap()];
+
+  // Check the snackbar.
+  NSString* snackbarLabel =
+      l10n_util::GetNSString(IDS_IOS_SETTINGS_SITE_WAS_COPIED_MESSAGE);
+  // The tap checks the existence of the snackbar and also closes it.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)]
+      performAction:grey_tap()];
+
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
+      performAction:grey_tap()];
+}
+
+// Checks that attempts to copy the username via the context menu item provide
+// an appropriate feedback.
+- (void)testCopyUsernameMenuItem {
+  // Saving a form is needed for using the "password details" view.
+  SaveExamplePasswordForm();
+
+  OpenPasswordSettings();
+
+  [GetInteractionForPasswordEntry(@"example.com, concrete username")
+      performAction:grey_tap()];
+
+  // Tap the username cell to display the context menu.
+  [GetInteractionForPasswordDetailItem(
+      grey_accessibilityLabel(@"concrete username")) performAction:grey_tap()];
+
+  // Tap the context menu item for copying.
+  [[EarlGrey
+      selectElementWithMatcher:PopUpMenuItemWithLabel(
+                                   IDS_IOS_SETTINGS_USERNAME_COPY_MENU_ITEM)]
+      performAction:grey_tap()];
+
+  // Check the snackbar.
+  NSString* snackbarLabel =
+      l10n_util::GetNSString(IDS_IOS_SETTINGS_USERNAME_WAS_COPIED_MESSAGE);
+  // The tap checks the existence of the snackbar and also closes it.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(snackbarLabel)]
+      performAction:grey_tap()];
+
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
+      performAction:grey_tap()];
+}
+
 // Checks that attempts to copy the password via the context menu item provide
 // an appropriate feedback.
 - (void)testCopyPasswordMenuItem {
@@ -790,6 +860,62 @@
       performAction:grey_tap()];
 }
 
+// Checks that attempts to show and hide the password via the context menu item
+// provide an appropriate feedback.
+- (void)testShowHidePasswordMenuItem {
+  if (![ChromeEarlGrey isIPadIdiom]) {
+    // TODO(crbug.com/1109644): Enable the test on iPhone once the bug is fixed.
+    EARL_GREY_TEST_DISABLED(@"Disabled for iPhone.");
+  }
+
+  // Saving a form is needed for using the "password details" view.
+  SaveExamplePasswordForm();
+
+  OpenPasswordSettings();
+
+  [GetInteractionForPasswordEntry(@"example.com, concrete username")
+      performAction:grey_tap()];
+
+  // Tap the password cell to display the context menu.
+  [GetInteractionForPasswordDetailItem(grey_text(kMaskedPassword))
+      performAction:grey_tap()];
+
+  // Make sure to capture the reauthentication module in a variable until the
+  // end of the test, otherwise it might get deleted too soon and break the
+  // functionality of copying and viewing passwords.
+  [PasswordSettingsAppInterface setUpMockReauthenticationModule];
+  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
+                                    ReauthenticationResult::kSuccess];
+
+  // Tap the context menu item for showing.
+  [[EarlGrey
+      selectElementWithMatcher:PopUpMenuItemWithLabel(
+                                   IDS_IOS_SETTINGS_PASSWORD_SHOW_MENU_ITEM)]
+      performAction:grey_tap()];
+
+  // Tap the password cell to display the context menu again, and to check that
+  // the password was unmasked.
+  [GetInteractionForPasswordDetailItem(
+      grey_accessibilityLabel(@"concrete password")) performAction:grey_tap()];
+
+  // Tap the context menu item for hiding.
+  [[EarlGrey
+      selectElementWithMatcher:PopUpMenuItemWithLabel(
+                                   IDS_IOS_SETTINGS_PASSWORD_HIDE_MENU_ITEM)]
+      performAction:grey_tap()];
+
+  // Check that the password is masked again.
+  [GetInteractionForPasswordDetailItem(grey_text(kMaskedPassword))
+      performAction:grey_tap()];
+
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
+      performAction:grey_tap()];
+}
+
 // Checks that federated credentials have no password but show the federation.
 - (void)testFederated {
   GREYAssert([PasswordSettingsAppInterface
@@ -803,26 +929,24 @@
   [GetInteractionForPasswordEntry(@"example.com, federated username")
       performAction:grey_tap()];
 
-  // Check that the Site and Username are present and correct.
-  [[EarlGrey selectElementWithMatcher:PasswordDetailWebsite()]
-      assertWithMatcher:grey_textFieldValue(@"https://example.com/")];
-  [[EarlGrey selectElementWithMatcher:PasswordDetailUsername()]
-      assertWithMatcher:grey_textFieldValue(@"federated username")];
+  // Check that the Site, Username, Federation and Delete Saved Password
+  // sections are there.
+  [GetInteractionForPasswordDetailItem(SiteHeader())
+      assertWithMatcher:grey_notNil()];
+  [GetInteractionForPasswordDetailItem(UsernameHeader())
+      assertWithMatcher:grey_notNil()];
+  // For federation check both the section header and content.
+  [GetInteractionForPasswordDetailItem(FederationHeader())
+      assertWithMatcher:grey_notNil()];
+  [GetInteractionForPasswordDetailItem(grey_text(@"famous.provider.net"))
+      assertWithMatcher:grey_notNil()];
+  [GetInteractionForPasswordDetailItem(DeleteButton())
+      assertWithMatcher:grey_notNil()];
 
   // Check that the password is not present.
-  [[EarlGrey selectElementWithMatcher:PasswordDetailPassword()]
+  [GetInteractionForPasswordDetailItem(PasswordHeader())
       assertWithMatcher:grey_nil()];
 
-  // Check that editing doesn't require reauth.
-  [PasswordSettingsAppInterface setUpMockReauthenticationModule];
-  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
-                                    ReauthenticationResult::kFailure];
-  [[EarlGrey selectElementWithMatcher:NavigationBarEditButton()]
-      performAction:grey_tap()];
-  // Ensure delete button is present after entering editing mode.
-  [[EarlGrey selectElementWithMatcher:DeleteButton()]
-      assertWithMatcher:grey_notNil()];
-
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
       performAction:grey_tap()];
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
@@ -841,17 +965,44 @@
   [GetInteractionForPasswordEntry(@"example.com, concrete username")
       performAction:grey_tap()];
 
-  [[EarlGrey selectElementWithMatcher:PasswordDetailWebsite()]
-      assertWithMatcher:grey_textFieldValue(@"https://example.com/")];
-  [[EarlGrey selectElementWithMatcher:PasswordDetailUsername()]
-      assertWithMatcher:grey_textFieldValue(@"concrete username")];
-  [[EarlGrey selectElementWithMatcher:PasswordDetailPassword()]
-      assertWithMatcher:grey_textFieldValue(kMaskedPassword)];
+  [GetInteractionForPasswordDetailItem(SiteHeader())
+      assertWithMatcher:grey_notNil()];
+  id<GREYMatcher> siteCell = grey_accessibilityLabel(@"https://example.com/");
+  [GetInteractionForPasswordDetailItem(siteCell)
+      assertWithMatcher:grey_layout(@[ Below() ], SiteHeader())];
+  [GetInteractionForPasswordDetailItem(CopySiteButton())
+      assertWithMatcher:grey_layout(@[ Below() ], siteCell)];
 
-  [GetInteractionForPasswordDetailItem(PasswordDetailPassword())
-      assertWithMatcher:grey_layout(@[ Below() ], PasswordDetailUsername())];
-  [GetInteractionForPasswordDetailItem(PasswordDetailUsername())
-      assertWithMatcher:grey_layout(@[ Below() ], PasswordDetailWebsite())];
+  [GetInteractionForPasswordDetailItem(UsernameHeader())
+      assertWithMatcher:grey_layout(@[ Below() ], CopySiteButton())];
+  id<GREYMatcher> usernameCell = grey_accessibilityLabel(@"concrete username");
+  [GetInteractionForPasswordDetailItem(usernameCell)
+      assertWithMatcher:grey_layout(@[ Below() ], UsernameHeader())];
+  [GetInteractionForPasswordDetailItem(CopyUsernameButton())
+      assertWithMatcher:grey_layout(@[ Below() ], usernameCell)];
+
+  id<GREYMatcher> passwordHeader =
+      grey_allOf(PasswordHeader(),
+                 grey_kindOfClassName(@"UITableViewHeaderFooterView"), nil);
+  [GetInteractionForPasswordDetailItem(passwordHeader)
+      assertWithMatcher:grey_layout(@[ Below() ], CopyUsernameButton())];
+  id<GREYMatcher> passwordCell = grey_accessibilityLabel(
+      l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_HIDDEN_LABEL));
+  [GetInteractionForPasswordDetailItem(passwordCell)
+      assertWithMatcher:grey_layout(@[ Below() ], passwordHeader)];
+  [GetInteractionForPasswordDetailItem(CopyPasswordButton())
+      assertWithMatcher:grey_layout(@[ Below() ], passwordCell)];
+  [GetInteractionForPasswordDetailItem(ShowPasswordButton())
+      assertWithMatcher:grey_layout(@[ Below() ], CopyPasswordButton())];
+
+  [GetInteractionForPasswordDetailItem(DeleteButton())
+      assertWithMatcher:grey_layout(@[ Below() ], ShowPasswordButton())];
+
+  // Check that the federation block is not present. Match directly to also
+  // catch the case where the block would be present but not currently visible
+  // due to the scrolling state.
+  [[EarlGrey selectElementWithMatcher:FederationHeader()]
+      assertWithMatcher:grey_nil()];
 
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
       performAction:grey_tap()];
@@ -872,11 +1023,25 @@
 
   [GetInteractionForPasswordEntry(@"example.com") performAction:grey_tap()];
 
-  [[EarlGrey selectElementWithMatcher:PasswordDetailWebsite()]
-      assertWithMatcher:grey_textFieldValue(@"https://example.com/")];
-  [[EarlGrey selectElementWithMatcher:PasswordDetailUsername()]
+  [GetInteractionForPasswordDetailItem(SiteHeader())
+      assertWithMatcher:grey_notNil()];
+  id<GREYMatcher> siteCell = grey_accessibilityLabel(@"https://example.com/");
+  [GetInteractionForPasswordDetailItem(siteCell)
+      assertWithMatcher:grey_layout(@[ Below() ], SiteHeader())];
+  [GetInteractionForPasswordDetailItem(CopySiteButton())
+      assertWithMatcher:grey_layout(@[ Below() ], siteCell)];
+
+  [GetInteractionForPasswordDetailItem(DeleteButton())
+      assertWithMatcher:grey_layout(@[ Below() ], CopySiteButton())];
+
+  // Check that the other blocks are not present. Match directly to also catch
+  // the case where those blocks would be present but not currently visible due
+  // to the scrolling state.
+  [[EarlGrey selectElementWithMatcher:UsernameHeader()]
       assertWithMatcher:grey_nil()];
-  [[EarlGrey selectElementWithMatcher:PasswordDetailPassword()]
+  [[EarlGrey selectElementWithMatcher:PasswordHeader()]
+      assertWithMatcher:grey_nil()];
+  [[EarlGrey selectElementWithMatcher:FederationHeader()]
       assertWithMatcher:grey_nil()];
 
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
@@ -901,15 +1066,36 @@
   [GetInteractionForPasswordEntry(@"example.com, federated username")
       performAction:grey_tap()];
 
-  [[EarlGrey selectElementWithMatcher:PasswordDetailWebsite()]
-      assertWithMatcher:grey_textFieldValue(@"https://example.com/")];
-  [[EarlGrey selectElementWithMatcher:PasswordDetailUsername()]
-      assertWithMatcher:grey_textFieldValue(@"federated username")];
-  [[EarlGrey selectElementWithMatcher:PasswordDetailPassword()]
-      assertWithMatcher:grey_nil()];
+  [GetInteractionForPasswordDetailItem(SiteHeader())
+      assertWithMatcher:grey_notNil()];
+  id<GREYMatcher> siteCell = grey_accessibilityLabel(@"https://example.com/");
+  [GetInteractionForPasswordDetailItem(siteCell)
+      assertWithMatcher:grey_layout(@[ Below() ], SiteHeader())];
+  [GetInteractionForPasswordDetailItem(CopySiteButton())
+      assertWithMatcher:grey_layout(@[ Below() ], siteCell)];
 
-  [GetInteractionForPasswordDetailItem(PasswordDetailUsername())
-      assertWithMatcher:grey_layout(@[ Below() ], PasswordDetailWebsite())];
+  [GetInteractionForPasswordDetailItem(UsernameHeader())
+      assertWithMatcher:grey_layout(@[ Below() ], CopySiteButton())];
+  id<GREYMatcher> usernameCell = grey_accessibilityLabel(@"federated username");
+  [GetInteractionForPasswordDetailItem(usernameCell)
+      assertWithMatcher:grey_layout(@[ Below() ], UsernameHeader())];
+  [GetInteractionForPasswordDetailItem(CopyUsernameButton())
+      assertWithMatcher:grey_layout(@[ Below() ], usernameCell)];
+
+  [GetInteractionForPasswordDetailItem(FederationHeader())
+      assertWithMatcher:grey_layout(@[ Below() ], CopyUsernameButton())];
+  id<GREYMatcher> federationCell = grey_text(@"famous.provider.net");
+  [GetInteractionForPasswordDetailItem(federationCell)
+      assertWithMatcher:grey_layout(@[ Below() ], FederationHeader())];
+
+  [GetInteractionForPasswordDetailItem(DeleteButton())
+      assertWithMatcher:grey_layout(@[ Below() ], federationCell)];
+
+  // Check that the password is not present. Match directly to also catch the
+  // case where the password header would be present but not currently visible
+  // due to the scrolling state.
+  [[EarlGrey selectElementWithMatcher:PasswordHeader()]
+      assertWithMatcher:grey_nil()];
 
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
       performAction:grey_tap()];
@@ -924,13 +1110,15 @@
 - (void)testStoredEntriesAlwaysShown {
   SaveExamplePasswordForm();
 
+  GREYAssert([PasswordSettingsAppInterface
+                 saveExampleBlockedOrigin:@"https://blocked.com"],
+             @"Stored form was not found in the PasswordStore results.");
+
   OpenPasswordSettings();
 
   // Toggle the "Save Passwords" control off and back on and check that stored
   // items are still present.
-  BOOL isSwitchEnabled =
-      [PasswordSettingsAppInterface isCredentialsServiceEnabled];
-  BOOL kExpectedState[] = {isSwitchEnabled, !isSwitchEnabled};
+  constexpr BOOL kExpectedState[] = {YES, NO};
   for (BOOL expected_state : kExpectedState) {
     // Toggle the switch. It is located near the top, so if not interactable,
     // try scrolling up.
@@ -948,6 +1136,8 @@
     // Check the stored items. Scroll down if needed.
     [GetInteractionForPasswordEntry(@"example.com, concrete username")
         assertWithMatcher:grey_notNil()];
+    [GetInteractionForPasswordEntry(@"blocked.com")
+        assertWithMatcher:grey_notNil()];
   }
 
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
@@ -1024,7 +1214,8 @@
   [PasswordSettingsAppInterface setUpMockReauthenticationModule];
   [PasswordSettingsAppInterface mockReauthenticationModuleCanAttempt:NO];
 
-  CopyPasswordDetailWithID(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD);
+  [GetInteractionForPasswordDetailItem(CopyPasswordButton())
+      performAction:grey_tap()];
 
   NSString* title =
       l10n_util::GetNSString(IDS_IOS_SETTINGS_SET_UP_SCREENLOCK_TITLE);
@@ -1032,10 +1223,6 @@
       assertWithMatcher:grey_sufficientlyVisible()];
   [[EarlGrey selectElementWithMatcher:chrome_test_util::OKButton()]
       performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
-      performAction:grey_tap()];
   [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
       performAction:grey_tap()];
 }
@@ -1116,12 +1303,12 @@
       assertWithMatcher:grey_notNil()];
 
   // Aim at an entry almost at the end of the list.
-  constexpr int kRemoteIndex = kPasswordsCount - 4;
+  constexpr int kRemoteIndex = kPasswordsCount - 2;
   // The scrolling in GetInteractionForPasswordEntry has too fine steps to
   // reach the desired part of the list quickly. The following gives it a head
-  // start of the desired position, counting 30 points per entry and
-  // aiming at |kRemoteIndex|.
-  constexpr int kJump = kRemoteIndex * 30 + 150;
+  // start of almost the desired position, counting 30 points per entry and
+  // aiming 3 entries before |kRemoteIndex|.
+  constexpr int kJump = (kRemoteIndex - 3) * 30;
   [[EarlGrey
       selectElementWithMatcher:grey_accessibilityID(kPasswordsTableViewId)]
       performAction:grey_scrollInDirection(kGREYDirectionDown, kJump)];
@@ -1130,10 +1317,10 @@
                        kRemoteIndex, kRemoteIndex]) performAction:grey_tap()];
 
   // Check that the detail view loaded correctly by verifying the site content.
-  [[EarlGrey selectElementWithMatcher:PasswordDetailWebsite()]
-      assertWithMatcher:grey_textFieldValue([NSString
-                            stringWithFormat:@"https://www%02d.example.com/",
-                                             kRemoteIndex])];
+  id<GREYMatcher> siteCell = grey_accessibilityLabel([NSString
+      stringWithFormat:@"https://www%02d.example.com/", kRemoteIndex]);
+  [GetInteractionForPasswordDetailItem(siteCell)
+      assertWithMatcher:grey_notNil()];
 
   [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
       performAction:grey_tap()];
@@ -1282,17 +1469,15 @@
       assertWithMatcher:grey_nil()];
   [GetInteractionForPasswordEntry(@"exclude2.com")
       assertWithMatcher:grey_notNil()];
-  [[EarlGrey
-      selectElementWithMatcher:ButtonWithAccessibilityLabelId(IDS_CANCEL)]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
-      performAction:grey_tap()];
 }
 
 // Test search and delete all passwords and blocked items.
 - (void)testSearchAndDeleteAllPasswords {
+  // TODO(crbug.com/1129441): This is failing regularly downstream on iOS14.
+  if (@available(iOS 14, *)) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS14.");
+  }
+
   SaveExamplePasswordForms();
   SaveExampleBlockedForms();
 
@@ -1304,10 +1489,6 @@
   //  [[EarlGrey selectElementWithMatcher:SearchTextField()]
   //      performAction:grey_typeText(@"u\n")];
 
-  [[EarlGrey
-      selectElementWithMatcher:grey_accessibilityID(kPasswordsTableViewId)]
-      performAction:grey_scrollToContentEdge(kGREYContentEdgeBottom)];
-
   TapEdit();
 
   // Select all.
@@ -1315,7 +1496,6 @@
       performAction:grey_tap()];
   [GetInteractionForPasswordEntry(@"example12.com, user2")
       performAction:grey_tap()];
-
   [GetInteractionForPasswordEntry(@"exclude1.com") performAction:grey_tap()];
   [GetInteractionForPasswordEntry(@"exclude2.com") performAction:grey_tap()];
 
diff --git a/ios/chrome/browser/web/content_mode_egtest.mm b/ios/chrome/browser/web/content_mode_egtest.mm
index ce376d5c..d4215e2 100644
--- a/ios/chrome/browser/web/content_mode_egtest.mm
+++ b/ios/chrome/browser/web/content_mode_egtest.mm
@@ -139,9 +139,10 @@
 
 // Tests the platform when the page is inside an iframe.
 - (void)testIFrameNavigation {
-  // TODO(crbug.com/1076233): Test is failing when running on iOS 13.4.
-  if (base::ios::IsRunningOnOrLater(13, 4, 0)) {
-    EARL_GREY_TEST_SKIPPED(@"Test disabled on iOS 13.4 and later.");
+  // This test fails in iOS 13.4 but is fixed in iOS 14. See crbug.com//1076233.
+  if (base::ios::IsRunningOnOrLater(13, 4, 0) &&
+      !base::ios::IsRunningOnIOS14OrLater()) {
+    EARL_GREY_TEST_SKIPPED(@"Test disabled on iOS 13.4 but enabled in iOS 14");
   }
 
   [ChromeEarlGrey loadURL:self.testServer->GetURL(kIFramePage)];
diff --git a/ios/chrome/browser/web/navigation_egtest.mm b/ios/chrome/browser/web/navigation_egtest.mm
index 48e294dc..e15c5e9 100644
--- a/ios/chrome/browser/web/navigation_egtest.mm
+++ b/ios/chrome/browser/web/navigation_egtest.mm
@@ -589,9 +589,10 @@
 // Tests that navigating forward from NTP works when resuming from session
 // restore. This is a regression test for https://crbug.com/814790.
 - (void)testRestoreHistoryToNTPAndNavigateForward {
-  // TODO(crbug.com/1076598): Test is failing when running on iOS 13.4.
-  if (base::ios::IsRunningOnOrLater(13, 4, 0)) {
-    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 13.4 and later.");
+  // This test fails in iOS 13.4 but is fixed in iOS 14. See crbug.com/1076598.
+  if (base::ios::IsRunningOnOrLater(13, 4, 0) &&
+      !base::ios::IsRunningOnIOS14OrLater()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 13.4 but enabled in iOS 14");
   }
 
 #if TARGET_IPHONE_SIMULATOR
diff --git a/ios/chrome/test/app/BUILD.gn b/ios/chrome/test/app/BUILD.gn
index 7cac1279..eb3edd97 100644
--- a/ios/chrome/test/app/BUILD.gn
+++ b/ios/chrome/test/app/BUILD.gn
@@ -43,7 +43,6 @@
     "//components/keyed_service/core",
     "//components/metrics",
     "//components/metrics:demographics_test_support",
-    "//components/password_manager/core/common",
     "//components/prefs",
     "//components/signin/public/base",
     "//components/sync:test_support_nigori",
@@ -71,7 +70,6 @@
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/tabs",
-    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/authentication/cells",
     "//ios/chrome/browser/ui/browser_view",
     "//ios/chrome/browser/ui/commands",
@@ -83,7 +81,6 @@
     "//ios/chrome/browser/ui/settings/password",
     "//ios/chrome/browser/ui/settings/password:password_ui",
     "//ios/chrome/browser/ui/settings/password:test_support",
-    "//ios/chrome/browser/ui/settings/password/password_details:password_details_ui",
     "//ios/chrome/browser/ui/tab_grid",
     "//ios/chrome/browser/ui/tabs",
     "//ios/chrome/browser/ui/util",
diff --git a/ios/chrome/test/app/password_test_util.mm b/ios/chrome/test/app/password_test_util.mm
index cbf55d0e..56b6cfe9 100644
--- a/ios/chrome/test/app/password_test_util.mm
+++ b/ios/chrome/test/app/password_test_util.mm
@@ -6,10 +6,8 @@
 
 #include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/settings/password/legacy_password_details_table_view_controller+testing.h"
-#import "ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/password/passwords_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
-#include "ios/chrome/browser/ui/ui_feature_flags.h"
 #import "ios/chrome/browser/ui/util/top_view_controller.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -55,11 +53,12 @@
   SettingsNavigationController* settings_navigation_controller =
       base::mac::ObjCCastStrict<SettingsNavigationController>(
           top_view_controller::TopPresentedViewController());
-  PasswordDetailsTableViewController* password_details_table_view_controller =
-      base::mac::ObjCCastStrict<PasswordDetailsTableViewController>(
-          settings_navigation_controller.topViewController);
-  password_details_table_view_controller.reauthModule =
-      mock_reauthentication_module;
+  LegacyPasswordDetailsTableViewController*
+      password_details_table_view_controller =
+          base::mac::ObjCCastStrict<LegacyPasswordDetailsTableViewController>(
+              settings_navigation_controller.topViewController);
+  [password_details_table_view_controller
+      setReauthenticationModule:mock_reauthentication_module];
   return mock_reauthentication_module;
 }
 
diff --git a/ios/web/web_state/web_state_observer_inttest.mm b/ios/web/web_state/web_state_observer_inttest.mm
index b1f3f49..cb6218b 100644
--- a/ios/web/web_state/web_state_observer_inttest.mm
+++ b/ios/web/web_state/web_state_observer_inttest.mm
@@ -2323,8 +2323,9 @@
 
 // Tests that iframe navigation triggers DidChangeBackForwardState.
 TEST_F(WebStateObserverTest, IframeNavigation) {
-  // TODO(crbug.com/1076233): Test is failing when running on iOS 13.4.
-  if (base::ios::IsRunningOnOrLater(13, 4, 0)) {
+  // This test fails in iOS 13.4 but is fixed in iOS 14. See crbug.com//1076233.
+  if (base::ios::IsRunningOnOrLater(13, 4, 0) &&
+      !base::ios::IsRunningOnIOS14OrLater()) {
     return;
   }
 
diff --git a/mojo/public/tools/bindings/generators/mojom_java_generator.py b/mojo/public/tools/bindings/generators/mojom_java_generator.py
index 96b2fdf..c51824a 100644
--- a/mojo/public/tools/bindings/generators/mojom_java_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_java_generator.py
@@ -20,9 +20,12 @@
 import mojom.generate.module as mojom
 from mojom.generate.template_expander import UseJinja
 
-sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir,
-                             os.pardir, os.pardir, os.pardir, os.pardir,
-                             'build', 'android', 'gyp'))
+# Item 0 of sys.path is the directory of the main file; item 1 is PYTHONPATH
+# (if set); item 2 is system libraries.
+sys.path.insert(
+    1,
+    os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
+                 os.pardir, os.pardir, 'build', 'android', 'gyp'))
 from util import build_utils
 
 
diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc
index f47f551f..bddc6974 100644
--- a/ppapi/proxy/ppb_instance_proxy.cc
+++ b/ppapi/proxy/ppb_instance_proxy.cc
@@ -227,13 +227,6 @@
   return &data->view;
 }
 
-PP_Bool PPB_Instance_Proxy::FlashIsFullscreen(PP_Instance instance) {
-  // This function is only used for proxying in the renderer process. It is not
-  // implemented in the plugin process.
-  NOTREACHED();
-  return PP_FALSE;
-}
-
 PP_Var PPB_Instance_Proxy::GetWindowObject(PP_Instance instance) {
   ReceiveSerializedVarReturnValue result;
   dispatcher()->Send(new PpapiHostMsg_PPBInstance_GetWindowObject(
diff --git a/ppapi/proxy/ppb_instance_proxy.h b/ppapi/proxy/ppb_instance_proxy.h
index 7bea4ee..a84b4872 100644
--- a/ppapi/proxy/ppb_instance_proxy.h
+++ b/ppapi/proxy/ppb_instance_proxy.h
@@ -47,7 +47,6 @@
   PP_Bool BindGraphics(PP_Instance instance, PP_Resource device) override;
   PP_Bool IsFullFrame(PP_Instance instance) override;
   const ViewData* GetViewData(PP_Instance instance) override;
-  PP_Bool FlashIsFullscreen(PP_Instance instance) override;
   PP_Var GetWindowObject(PP_Instance instance) override;
   PP_Var GetOwnerElementObject(PP_Instance instance) override;
   PP_Var ExecuteScript(PP_Instance instance,
diff --git a/ppapi/proxy/ppp_instance_proxy.cc b/ppapi/proxy/ppp_instance_proxy.cc
index afe0a720..6809295 100644
--- a/ppapi/proxy/ppp_instance_proxy.cc
+++ b/ppapi/proxy/ppp_instance_proxy.cc
@@ -77,8 +77,6 @@
 
   PP_Bool flash_fullscreen = PP_FALSE;
   EnterInstanceNoLock enter_instance(instance);
-  if (!enter_instance.failed())
-    flash_fullscreen = enter_instance.functions()->FlashIsFullscreen(instance);
   dispatcher->Send(new PpapiMsg_PPPInstance_DidChangeView(
       API_ID_PPP_INSTANCE, instance, enter_view.object()->GetData(),
       flash_fullscreen));
diff --git a/ppapi/thunk/ppb_instance_api.h b/ppapi/thunk/ppb_instance_api.h
index 390e2ce7..520cb3c 100644
--- a/ppapi/thunk/ppb_instance_api.h
+++ b/ppapi/thunk/ppb_instance_api.h
@@ -50,8 +50,6 @@
   // Unexposed PPAPI functions for proxying.
   // Returns the internal view data struct.
   virtual const ViewData* GetViewData(PP_Instance instance) = 0;
-  // Returns the flash fullscreen status.
-  virtual PP_Bool FlashIsFullscreen(PP_Instance instance) = 0;
 
   // InstancePrivate.
   virtual PP_Var GetWindowObject(PP_Instance instance) = 0;
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 4b9aed5..9416676 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -323,6 +323,7 @@
     ]
     deps += [
       "//remoting/host/linux:x11",
+      "//ui/events/platform/x11",
       "//ui/gfx/x",
     ]
     if (is_linux) {
diff --git a/remoting/host/it2me/it2me_native_messaging_host_main.cc b/remoting/host/it2me/it2me_native_messaging_host_main.cc
index f429809..545a57d0 100644
--- a/remoting/host/it2me/it2me_native_messaging_host_main.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host_main.cc
@@ -33,6 +33,7 @@
 #include <gtk/gtk.h>
 
 #include "base/linux_util.h"
+#include "ui/events/platform/x11/x11_event_source.h"
 #include "ui/gfx/x/x11.h"
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
@@ -116,6 +117,11 @@
   // Required in order for us to run multiple X11 threads.
   XInitThreads();
 
+  // Create an X11EventSource so the global X11 connection
+  // (x11::Connection::Get()) can dispatch X events.
+  auto event_source =
+      std::make_unique<ui::X11EventSource>(x11::Connection::Get());
+
   // Required for any calls into GTK functions, such as the Disconnect and
   // Continue windows. Calling with nullptr arguments because we don't have
   // any command line arguments for gtk to consume.
diff --git a/remoting/host/keyboard_layout_monitor_linux.cc b/remoting/host/keyboard_layout_monitor_linux.cc
index 22d6866..a897dba4 100644
--- a/remoting/host/keyboard_layout_monitor_linux.cc
+++ b/remoting/host/keyboard_layout_monitor_linux.cc
@@ -18,6 +18,7 @@
 #include "ui/base/glib/glib_signal.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/events/platform/x11/x11_event_source.h"
 #include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/xkb.h"
 #include "ui/gfx/x/xproto.h"
@@ -42,7 +43,7 @@
 
 // Can be constructed on any thread, but must be started and destroyed on the
 // main GTK+ thread (i.e., the GLib global default main context).
-class GdkLayoutMonitorOnGtkThread : public x11::Connection::Delegate {
+class GdkLayoutMonitorOnGtkThread : public ui::XEventDispatcher {
  public:
   GdkLayoutMonitorOnGtkThread(
       scoped_refptr<base::SequencedTaskRunner> task_runner,
@@ -53,19 +54,17 @@
   void Start();
 
  private:
-  // x11::Connection::Delegate:
-  bool ShouldContinueStream() const override;
-  void DispatchXEvent(x11::Event* event) override;
+  // ui::XEventDispatcher:
+  bool DispatchXEvent(x11::Event* event) override;
 
   void QueryLayout();
-  void OnConnectionData();
   CHROMEG_CALLBACK_0(GdkLayoutMonitorOnGtkThread,
                      void,
                      OnKeysChanged,
                      GdkKeymap*);
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   base::WeakPtr<KeyboardLayoutMonitorLinux> weak_ptr_;
-  std::unique_ptr<x11::Connection> connection_;
+  x11::Connection* connection_;
   std::unique_ptr<base::FileDescriptorWatcher::Controller> controller_;
   GdkDisplay* display_ = nullptr;
   GdkKeymap* keymap_ = nullptr;
@@ -120,8 +119,10 @@
 
 GdkLayoutMonitorOnGtkThread::~GdkLayoutMonitorOnGtkThread() {
   DCHECK(g_main_context_is_owner(g_main_context_default()));
-  if (handler_id_)
+  if (handler_id_) {
     g_signal_handler_disconnect(keymap_, handler_id_);
+    ui::X11EventSource::GetInstance()->RemoveXEventDispatcher(this);
+  }
 }
 
 void GdkLayoutMonitorOnGtkThread::Start() {
@@ -143,30 +144,22 @@
   // when switching between groups with different writing directions. As a
   // result, we have to use Xkb directly to get and monitor that information,
   // which is a pain.
-  connection_ = std::make_unique<x11::Connection>();
+  connection_ = x11::Connection::Get();
   auto& xkb = connection_->xkb();
   if (xkb.UseExtension({x11::Xkb::major_version, x11::Xkb::minor_version})
           .Sync()) {
-    auto req = xkb.GetState(
-        {static_cast<x11::Xkb::DeviceSpec>(x11::Xkb::Id::UseCoreKbd)});
-    if (auto reply = req.Sync()) {
-      current_group_ = static_cast<int>(reply->group);
-      constexpr auto kXkbAllStateComponentsMask =
-          static_cast<x11::Xkb::StatePart>(0x3fff);
-      xkb.SelectEvents({
-          .deviceSpec =
-              static_cast<x11::Xkb::DeviceSpec>(x11::Xkb::Id::UseCoreKbd),
-          .affectWhich = x11::Xkb::EventType::StateNotify,
-          .affectState = kXkbAllStateComponentsMask,
-          .stateDetails = x11::Xkb::StatePart::GroupState,
-      });
-      connection_->Flush();
-      controller_ = base::FileDescriptorWatcher::WatchReadable(
-          connection_->GetFd(),
-          base::BindRepeating(&GdkLayoutMonitorOnGtkThread::OnConnectionData,
-                              base::Unretained(this)));
-    }
+    constexpr auto kXkbAllStateComponentsMask =
+        static_cast<x11::Xkb::StatePart>(0x3fff);
+    xkb.SelectEvents({
+        .deviceSpec =
+            static_cast<x11::Xkb::DeviceSpec>(x11::Xkb::Id::UseCoreKbd),
+        .affectWhich = x11::Xkb::EventType::StateNotify,
+        .affectState = kXkbAllStateComponentsMask,
+        .stateDetails = x11::Xkb::StatePart::GroupState,
+    });
+    connection_->Flush();
   }
+  ui::X11EventSource::GetInstance()->AddXEventDispatcher(this);
 
   keymap_ = gdk_keymap_get_for_display(display_);
   handler_id_ = g_signal_connect(keymap_, "keys-changed",
@@ -174,19 +167,18 @@
   QueryLayout();
 }
 
-bool GdkLayoutMonitorOnGtkThread::ShouldContinueStream() const {
-  return true;
-}
-
-void GdkLayoutMonitorOnGtkThread::DispatchXEvent(x11::Event* event) {
-  if (auto* notify = event->As<x11::Xkb::StateNotifyEvent>()) {
+bool GdkLayoutMonitorOnGtkThread::DispatchXEvent(x11::Event* event) {
+  if (event->As<x11::MappingNotifyEvent>() ||
+      event->As<x11::Xkb::NewKeyboardNotifyEvent>()) {
+    QueryLayout();
+  } else if (auto* notify = event->As<x11::Xkb::StateNotifyEvent>()) {
     int new_group = notify->baseGroup + notify->latchedGroup +
                     static_cast<int16_t>(notify->lockedGroup);
-    if (new_group != current_group_) {
-      current_group_ = new_group;
+    if (new_group != current_group_)
       QueryLayout();
-    }
+    return true;
   }
+  return false;
 }
 
 void GdkLayoutMonitorOnGtkThread::QueryLayout() {
@@ -198,6 +190,11 @@
 
   bool have_altgr = false;
 
+  auto req = connection_->xkb().GetState(
+      {static_cast<x11::Xkb::DeviceSpec>(x11::Xkb::Id::UseCoreKbd)});
+  if (auto reply = req.Sync())
+    current_group_ = static_cast<int>(reply->group);
+
   for (ui::DomCode key : KeyboardLayoutMonitorLinux::kSupportedKeys) {
     // Skip single-layout IME keys for now, as they are always present in the
     // keyboard map but not present on most keyboards. Client-side IME is likely
@@ -298,10 +295,6 @@
                                 weak_ptr_, std::move(layout_message)));
 }
 
-void GdkLayoutMonitorOnGtkThread::OnConnectionData() {
-  connection_->Dispatch(this);
-}
-
 void GdkLayoutMonitorOnGtkThread::OnKeysChanged(GdkKeymap* keymap) {
   QueryLayout();
 }
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 0436254..aa8ed13 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -120,9 +120,11 @@
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
 #include <gtk/gtk.h>
+
 #include "base/linux_util.h"
 #include "remoting/host/audio_capturer_linux.h"
 #include "remoting/host/linux/certificate_watcher.h"
+#include "ui/events/platform/x11/x11_event_source.h"
 #include "ui/gfx/x/x11.h"
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
@@ -1686,11 +1688,16 @@
   HOST_LOG << "Starting host process: version " << STRINGIZE(VERSION);
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
+  std::unique_ptr<ui::X11EventSource> event_source;
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
           kReportOfflineReasonSwitchName)) {
     // Required in order for us to run multiple X11 threads.
     XInitThreads();
 
+    // Create an X11EventSource so the global X11 connection
+    // (x11::Connection::Get()) can dispatch X events.
+    event_source = std::make_unique<ui::X11EventSource>(x11::Connection::Get());
+
     // Required for any calls into GTK functions, such as the Disconnect and
     // Continue windows, though these should not be used for the Me2Me case
     // (crbug.com/104377).
diff --git a/remoting/test/DEPS b/remoting/test/DEPS
index 8f93383..9c9e8445 100644
--- a/remoting/test/DEPS
+++ b/remoting/test/DEPS
@@ -11,6 +11,7 @@
   "+remoting/signaling",
   "+ui/gfx",
   "+ui/events/keycodes/dom",
+  "+ui/events/platform/x11",
   "+services/network",
   "+third_party/skia",
 ]
diff --git a/remoting/test/it2me_standalone_host_main.cc b/remoting/test/it2me_standalone_host_main.cc
index d45013c0..e8c73f0 100644
--- a/remoting/test/it2me_standalone_host_main.cc
+++ b/remoting/test/it2me_standalone_host_main.cc
@@ -13,6 +13,7 @@
 #include <gtk/gtk.h>
 
 #include "base/linux_util.h"
+#include "ui/events/platform/x11/x11_event_source.h"
 #include "ui/gfx/x/x11.h"
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
@@ -25,6 +26,11 @@
   // Required in order for us to run multiple X11 threads.
   XInitThreads();
 
+  // Create an X11EventSource so the global X11 connection
+  // (x11::Connection::Get()) can dispatch X events.
+  auto event_source =
+      std::make_unique<ui::X11EventSource>(x11::Connection::Get());
+
   // Required for any calls into GTK functions, such as the Disconnect and
   // Continue windows. Calling with nullptr arguments because we don't have
   // any command line arguments for gtk to consume.
diff --git a/sandbox/policy/mac/gpu_v2.sb b/sandbox/policy/mac/gpu_v2.sb
index 948e2900..f7e7559 100644
--- a/sandbox/policy/mac/gpu_v2.sb
+++ b/sandbox/policy/mac/gpu_v2.sb
@@ -35,6 +35,7 @@
       (path (param "PARENT_DIR"))
       (path (param "PWD"))
       (path-ancestors (param "PARENT_DIR")) ; libxpc.dylib`_xpc_bundle_resolve_sync walks the dir tree.
+      (subpath "/Library/Apple")
       (subpath "/Library/Application Support/CrashReporter")
       (subpath "/usr/share/locale")
     )
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
index cdb82f7..c10f7b2b 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
@@ -49,6 +49,7 @@
 #include "third_party/perfetto/include/perfetto/ext/tracing/core/shared_memory_arbiter.h"
 #include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_writer.h"
 #include "third_party/perfetto/include/perfetto/tracing/track.h"
+#include "third_party/perfetto/include/perfetto/tracing/track_event_interned_data_index.h"
 #include "third_party/perfetto/protos/perfetto/trace/chrome/chrome_metadata.pbzero.h"
 #include "third_party/perfetto/protos/perfetto/trace/chrome/chrome_trace_event.pbzero.h"
 #include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
@@ -1041,6 +1042,24 @@
   }
 }
 
+namespace {
+
+struct InternedHistogramName
+    : public perfetto::TrackEventInternedDataIndex<
+          InternedHistogramName,
+          perfetto::protos::pbzero::InternedData::kHistogramNamesFieldNumber,
+          std::string> {
+  static void Add(perfetto::protos::pbzero::InternedData* interned_data,
+                  size_t iid,
+                  const std::string& histogram_name) {
+    auto* msg = interned_data->add_histogram_names();
+    msg->set_iid(iid);
+    msg->set_name(histogram_name);
+  }
+};
+
+}  // namespace
+
 // static
 void TraceEventDataSource::OnMetricsSampleCallback(
     const char* histogram_name,
@@ -1056,7 +1075,8 @@
         new_sample->set_name_hash(name_hash);
         new_sample->set_sample(sample);
         if (!privacy_filtering_enabled) {
-          new_sample->set_name(histogram_name);
+          size_t iid = InternedHistogramName::Get(&ctx, histogram_name);
+          new_sample->set_name_iid(iid);
         }
       });
 }
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
index d7e1f8e6..7ca1c5a 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source_unittest.cc
@@ -1917,9 +1917,11 @@
                         {{1u, TRACE_DISABLED_BY_DEFAULT("histogram_samples")}});
   ExpectEventNames(e_packet, {{1u, "HistogramSample"}});
   ASSERT_TRUE(e_packet->track_event().has_chrome_histogram_sample());
-  EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().name_hash(),
-            base::HashMetricName("Foo.Bar"));
   EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().sample(), 1u);
+  ASSERT_TRUE(e_packet->has_interned_data());
+  EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().name_iid(),
+            e_packet->interned_data().histogram_names()[0].iid());
+  EXPECT_EQ(e_packet->interned_data().histogram_names()[0].name(), "Foo.Bar");
 }
 
 TEST_F(TraceEventDataSourceTest, HistogramSampleTraceConfigNotEmpty) {
@@ -1946,9 +1948,11 @@
   ASSERT_TRUE(e_packet->track_event().has_chrome_histogram_sample());
   EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().name_hash(),
             base::HashMetricName("Foo1.Bar1"));
-  EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().name(),
-            "Foo1.Bar1");
   EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().sample(), 1u);
+  ASSERT_TRUE(e_packet->has_interned_data());
+  EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().name_iid(),
+            e_packet->interned_data().histogram_names()[0].iid());
+  EXPECT_EQ(e_packet->interned_data().histogram_names()[0].name(), "Foo1.Bar1");
 
   e_packet = producer_client()->GetFinalizedPacket(packet_index++);
 
@@ -1957,9 +1961,11 @@
   ASSERT_TRUE(e_packet->track_event().has_chrome_histogram_sample());
   EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().name_hash(),
             base::HashMetricName("Foo3.Bar3"));
-  EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().name(),
-            "Foo3.Bar3");
   EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().sample(), 1u);
+  ASSERT_TRUE(e_packet->has_interned_data());
+  EXPECT_EQ(e_packet->track_event().chrome_histogram_sample().name_iid(),
+            e_packet->interned_data().histogram_names()[0].iid());
+  EXPECT_EQ(e_packet->interned_data().histogram_names()[0].name(), "Foo3.Bar3");
 
   EXPECT_EQ(packet_index, producer_client()->GetFinalizedPacketCount());
 }
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 67dc60c..73f788c 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -23998,6 +23998,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -26431,6 +26434,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.dawn.json b/testing/buildbot/chromium.dawn.json
index aa6e8bc..552f08a3 100644
--- a/testing/buildbot/chromium.dawn.json
+++ b/testing/buildbot/chromium.dawn.json
@@ -234,6 +234,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -265,6 +268,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -511,6 +517,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -542,6 +551,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -788,6 +800,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -819,6 +834,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1065,6 +1083,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1096,6 +1117,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1343,6 +1367,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1374,6 +1401,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1604,6 +1634,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1633,6 +1666,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1877,6 +1913,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1908,6 +1947,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2138,6 +2180,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2167,6 +2212,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2413,6 +2461,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2658,6 +2709,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2688,6 +2742,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2926,6 +2983,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2956,6 +3016,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3194,6 +3257,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3224,6 +3290,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3462,6 +3531,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3492,6 +3564,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3731,6 +3806,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3760,6 +3838,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3997,6 +4078,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4026,6 +4110,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4263,6 +4350,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4292,6 +4382,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4529,6 +4622,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4558,6 +4654,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webgpu_blink_web_tests_with_backend_validation",
+        "resultdb": {
+          "enable": true
+        },
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.devtools-frontend.json b/testing/buildbot/chromium.devtools-frontend.json
index 92a4447..062b03e 100644
--- a/testing/buildbot/chromium.devtools-frontend.json
+++ b/testing/buildbot/chromium.devtools-frontend.json
@@ -41,6 +41,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -68,6 +71,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_from_devtools",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index afaed73f..0125212 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -99,6 +99,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "non_skia_renderer_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -134,6 +137,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "vulkan_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1567,6 +1573,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -2123,6 +2132,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -2181,6 +2193,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -5150,6 +5165,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -7367,6 +7385,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -18836,6 +18857,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -37053,6 +37077,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -38690,6 +38717,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -38722,6 +38752,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "high_dpi_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -38751,6 +38784,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -42181,6 +42217,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -42357,6 +42396,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "non_skia_renderer_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -42384,6 +42426,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "not_site_per_process_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -42511,6 +42556,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "vulkan_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -44286,6 +44334,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -44471,6 +44522,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "non_skia_renderer_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -44500,6 +44554,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "not_site_per_process_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -44630,6 +44687,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "vulkan_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -49543,6 +49603,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -52967,6 +53030,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -53384,6 +53450,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -53437,6 +53506,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -53490,6 +53562,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -53542,6 +53617,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -53595,6 +53673,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -53691,6 +53772,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -55070,6 +55154,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 924c230..a4d4bd3b 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -14131,6 +14131,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "skia_renderer_gl_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -14214,6 +14217,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "vulkan_native_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -14559,6 +14565,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "skia_renderer_gl_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -14642,6 +14651,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "vulkan_native_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 894598d..c17cf11a 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -4097,6 +4097,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -6838,6 +6841,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -7023,6 +7029,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "non_skia_renderer_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -7052,6 +7061,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "not_site_per_process_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -7184,6 +7196,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "vulkan_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -8869,6 +8884,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -9278,6 +9296,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -10943,6 +10964,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -11119,6 +11143,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "non_skia_renderer_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -11146,6 +11173,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "not_site_per_process_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -11273,6 +11303,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "vulkan_swiftshader_blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index f81a851..fbd4dba2 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -4906,6 +4906,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -6679,6 +6682,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -8464,6 +8470,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -10198,6 +10207,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -11979,6 +11991,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -13690,6 +13705,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index b732d44d..18ba2c5 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -15099,6 +15099,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -15136,6 +15139,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -15170,6 +15176,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 25588ec..d3798b8 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -15,6 +15,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -3534,6 +3537,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -7248,6 +7254,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -8772,6 +8781,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/client.devtools-frontend.integration.json b/testing/buildbot/client.devtools-frontend.integration.json
index 845f6c6..09c8a5a8 100644
--- a/testing/buildbot/client.devtools-frontend.integration.json
+++ b/testing/buildbot/client.devtools-frontend.integration.json
@@ -62,6 +62,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -89,6 +92,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_from_devtools",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json
index 33541c9..79e9b72 100644
--- a/testing/buildbot/client.v8.fyi.json
+++ b/testing/buildbot/client.v8.fyi.json
@@ -1367,6 +1367,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1425,6 +1428,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1481,6 +1487,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1534,6 +1543,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1590,6 +1602,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1622,6 +1637,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 35ec22fa..7e42d4d 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -934,10 +934,13 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
         'swarming': {
           'shards': 12,
-        }
+        },
       },
       'webdriver_tests_suite': {
         'isolate_name': 'webdriver_wpt_tests',
@@ -973,6 +976,9 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
         'swarming': {
           'shards': 12,
@@ -997,6 +1003,9 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
         'swarming': {
           'shards': 12,
@@ -1152,6 +1161,9 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
         'swarming': {
           'shards': 12,
@@ -1219,6 +1231,9 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
         'swarming': {
           'shards': 12,
@@ -1240,6 +1255,9 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
         'swarming': {
           'shards': 4,
@@ -2061,6 +2079,9 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
       },
     },
@@ -2096,6 +2117,9 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
       },
    },
@@ -3142,6 +3166,9 @@
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
         'isolate_name': 'webgpu_blink_web_tests',
+        'resultdb': {
+          'enable': True,
+        },
       },
     },
 
@@ -3178,6 +3205,9 @@
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
         'isolate_name': 'webgpu_blink_web_tests',
+        'resultdb': {
+          'enable': True,
+        },
       },
     },
 
@@ -3432,6 +3462,9 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
         'swarming': {
           'shards': 10,
@@ -3930,6 +3963,9 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
       },
       'vulkan_swiftshader_blink_web_tests': {
@@ -3957,6 +3993,9 @@
           ],
           'script': '//third_party/blink/tools/merge_web_test_results.py',
         },
+        'resultdb': {
+          'enable': True,
+        },
         'results_handler': 'layout tests',
       },
     },
diff --git a/testing/buildbot/tryserver.chromium.android.json b/testing/buildbot/tryserver.chromium.android.json
index abcb2f1..92059ee3 100644
--- a/testing/buildbot/tryserver.chromium.android.json
+++ b/testing/buildbot/tryserver.chromium.android.json
@@ -166,6 +166,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/tryserver.chromium.linux.json b/testing/buildbot/tryserver.chromium.linux.json
index 2b5296b..b1054e2 100644
--- a/testing/buildbot/tryserver.chromium.linux.json
+++ b/testing/buildbot/tryserver.chromium.linux.json
@@ -24,6 +24,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -57,6 +60,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/tryserver.devtools-frontend.json b/testing/buildbot/tryserver.devtools-frontend.json
index d3d4b0e..fe4f44b 100644
--- a/testing/buildbot/tryserver.devtools-frontend.json
+++ b/testing/buildbot/tryserver.devtools-frontend.json
@@ -39,6 +39,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -66,6 +69,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_from_devtools",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -95,6 +101,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "blink_web_tests",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -122,6 +131,9 @@
           "script": "//third_party/blink/tools/merge_web_test_results.py"
         },
         "name": "webkit_layout_from_devtools",
+        "resultdb": {
+          "enable": true
+        },
         "results_handler": "layout tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b235728d..6b86db6 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1248,27 +1248,6 @@
             ]
         }
     ],
-    "CSSOMViewScrollCoordinates": [
-        {
-            "platforms": [
-                "android",
-                "android_weblayer",
-                "android_webview",
-                "chromeos",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "EnableCSSOMViewScrollCoordinates",
-                    "enable_features": [
-                        "CSSOMViewScrollCoordinates"
-                    ]
-                }
-            ]
-        }
-    ],
     "CacheStorageSequenceChromeOS": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index b1e77d0f..b4d8789 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -162,10 +162,6 @@
 #endif
 };
 
-// Enable CSSOM View Scroll Coordinates. https://crbug.com/721759.
-const base::Feature kCSSOMViewScrollCoordinates{
-    "CSSOMViewScrollCoordinates", base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Enables Raw Clipboard. https://crbug.com/897289.
 const base::Feature kRawClipboard{"RawClipboard",
                                   base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index ed0274a6..4797031 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -28,7 +28,6 @@
 BLINK_COMMON_EXPORT extern const base::Feature kFreezeUserAgent;
 BLINK_COMMON_EXPORT extern const base::Feature kFtpProtocol;
 BLINK_COMMON_EXPORT extern const base::Feature kImplicitRootScroller;
-BLINK_COMMON_EXPORT extern const base::Feature kCSSOMViewScrollCoordinates;
 BLINK_COMMON_EXPORT extern const base::Feature kDisplayLocking;
 BLINK_COMMON_EXPORT extern const base::Feature kJSONModules;
 BLINK_COMMON_EXPORT extern const base::Feature kForceSynchronousHTMLParsing;
diff --git a/third_party/blink/public/common/privacy_budget/identifiable_surface.h b/third_party/blink/public/common/privacy_budget/identifiable_surface.h
index f2ea1d5a..c6ee81b 100644
--- a/third_party/blink/public/common/privacy_budget/identifiable_surface.h
+++ b/third_party/blink/public/common/privacy_budget/identifiable_surface.h
@@ -187,6 +187,12 @@
     // Represents a call to GPU.requestAdapter. Input is the options filter.
     kGPU_RequestAdapter = 20,
 
+    // For instrumenting HTMLCanvas.getContext() fingerprinting. Some scripts
+    // will iterate through the different possible arguments and record whether
+    // each type of context is supported.
+    // The input should be an instance of CanvasRenderingContext::ContextType.
+    kCanvasRenderingContext = 21,
+
     // NavigatorUAData.getHighEntropyValues() is, shockingly, a high entropy
     // API to provide more detailed User-Agent data. The output is keyed on
     // the hint parameter.
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index 1207db2..a666132d7 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -111,7 +111,6 @@
   BLINK_PLATFORM_EXPORT static void EnableForceTallerSelectPopup(bool);
   BLINK_PLATFORM_EXPORT static void EnableGenericSensorExtraClasses(bool);
   BLINK_PLATFORM_EXPORT static void EnableImplicitRootScroller(bool);
-  BLINK_PLATFORM_EXPORT static void EnableCSSOMViewScrollCoordinates(bool);
   BLINK_PLATFORM_EXPORT static void EnableInputMultipleFieldsUI(bool);
   BLINK_PLATFORM_EXPORT static void EnableLayoutNG(bool);
   BLINK_PLATFORM_EXPORT static void EnableLazyFrameLoading(bool);
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 9875903..c4f36e6f 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -693,16 +693,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection_ice_error_event_init.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection_ice_event_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection_ice_event_init.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_parameters.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_parameters.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_event_init.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_event_init.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_read_result.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_read_result.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_write_parameters.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_write_parameters.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_transport_stats.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_transport_stats.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtcp_parameters.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtcp_parameters.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_capabilities.cc",
@@ -1114,12 +1104,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection_state.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_priority_type.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_priority_type.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_role.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_role.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_state.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_state.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_transport_state.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_transport_state.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtcp_mux_policy.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtcp_mux_policy.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_transceiver_direction.cc",
@@ -1899,12 +1883,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection_ice_error_event.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection_ice_event.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_peer_connection_ice_event.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_event.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_event.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_transport.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_transport.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_receiver.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_receiver.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_rtp_sender.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni
index 3f3c2d3..317eac0 100644
--- a/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -498,14 +498,6 @@
           "//third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event_init.idl",
           "//third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.idl",
           "//third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event_init.idl",
-          "//third_party/blink/renderer/modules/peerconnection/rtc_quic_parameters.idl",
-          "//third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl",
-          "//third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl",
-          "//third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event_init.idl",
-          "//third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_read_result.idl",
-          "//third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_write_parameters.idl",
-          "//third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl",
-          "//third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl",
           "//third_party/blink/renderer/modules/peerconnection/rtc_rtcp_parameters.idl",
           "//third_party/blink/renderer/modules/peerconnection/rtc_rtp_capabilities.idl",
           "//third_party/blink/renderer/modules/peerconnection/rtc_rtp_codec_capability.idl",
diff --git a/third_party/blink/renderer/bindings/modules/BUILD.gn b/third_party/blink/renderer/bindings/modules/BUILD.gn
index 5df6401..f13639be 100644
--- a/third_party/blink/renderer/bindings/modules/BUILD.gn
+++ b/third_party/blink/renderer/bindings/modules/BUILD.gn
@@ -52,7 +52,6 @@
     "//third_party/blink/renderer/modules/peerconnection/rtc_dtmf_tone_change_event.idl",
     "//third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_error_event.idl",
     "//third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.idl",
-    "//third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl",
     "//third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_event.idl",
     "//third_party/blink/renderer/modules/presentation/presentation_connection_available_event.idl",
     "//third_party/blink/renderer/modules/presentation/presentation_connection_close_event.idl",
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 45a7fe8..7ec31d8 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1399,16 +1399,8 @@
               kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop);
     }
 
-    // In order to keep the behavior of element scroll consistent with document
-    // scroll, and consistent with the behavior of other vendors, the scrollLeft
-    // of a box is changed to the offset from |ScrollOrigin()|.
-    if (RuntimeEnabledFeatures::CSSOMViewScrollCoordinatesEnabled()) {
-      return AdjustForAbsoluteZoom::AdjustScroll(
-          scrollable_area->GetScrollOffset().Width(), *GetLayoutBox());
-    } else {
-      return AdjustForAbsoluteZoom::AdjustScroll(
-          scrollable_area->ScrollPosition().X(), *GetLayoutBox());
-    }
+    return AdjustForAbsoluteZoom::AdjustScroll(
+        scrollable_area->GetScrollOffset().Width(), *GetLayoutBox());
   }
 
   return 0;
@@ -1440,16 +1432,8 @@
               kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop);
     }
 
-    // In order to keep the behavior of element scroll consistent with document
-    // scroll, and consistent with the behavior of other vendors, the scrollTop
-    // of a box is changed to the offset from |ScrollOrigin()|.
-    if (RuntimeEnabledFeatures::CSSOMViewScrollCoordinatesEnabled()) {
-      return AdjustForAbsoluteZoom::AdjustScroll(
-          scrollable_area->GetScrollOffset().Height(), *GetLayoutBox());
-    } else {
-      return AdjustForAbsoluteZoom::AdjustScroll(
-          scrollable_area->ScrollPosition().Y(), *GetLayoutBox());
-    }
+    return AdjustForAbsoluteZoom::AdjustScroll(
+        scrollable_area->GetScrollOffset().Height(), *GetLayoutBox());
   }
 
   return 0;
@@ -1490,38 +1474,21 @@
       }
     }
 
-    if (RuntimeEnabledFeatures::CSSOMViewScrollCoordinatesEnabled()) {
-      ScrollOffset end_offset(new_left * box->Style()->EffectiveZoom(),
-                              scrollable_area->GetScrollOffset().Height());
-      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
-          cc::SnapSelectionStrategy::CreateForEndPosition(
-              gfx::ScrollOffset(
-                  scrollable_area->ScrollOffsetToPosition(end_offset)),
-              true, false);
-      base::Optional<FloatPoint> snap_point =
-          scrollable_area->GetSnapPositionAndSetTarget(*strategy);
-      if (snap_point.has_value()) {
-        end_offset =
-            scrollable_area->ScrollPositionToOffset(snap_point.value());
-      }
-      scrollable_area->SetScrollOffset(end_offset,
-                                       mojom::blink::ScrollType::kProgrammatic,
-                                       mojom::blink::ScrollBehavior::kAuto);
-    } else {
-      FloatPoint end_point(new_left * box->Style()->EffectiveZoom(),
-                           scrollable_area->ScrollPosition().Y());
-      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
-          cc::SnapSelectionStrategy::CreateForEndPosition(
-              gfx::ScrollOffset(end_point), true, false);
-      end_point =
-          scrollable_area->GetSnapPositionAndSetTarget(*strategy).value_or(
-              end_point);
-
-      FloatPoint new_position(end_point.X(),
-                              scrollable_area->ScrollPosition().Y());
-      scrollable_area->ScrollToAbsolutePosition(
-          new_position, mojom::blink::ScrollBehavior::kAuto);
+    ScrollOffset end_offset(new_left * box->Style()->EffectiveZoom(),
+                            scrollable_area->GetScrollOffset().Height());
+    std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+        cc::SnapSelectionStrategy::CreateForEndPosition(
+            gfx::ScrollOffset(
+                scrollable_area->ScrollOffsetToPosition(end_offset)),
+            true, false);
+    base::Optional<FloatPoint> snap_point =
+        scrollable_area->GetSnapPositionAndSetTarget(*strategy);
+    if (snap_point.has_value()) {
+      end_offset = scrollable_area->ScrollPositionToOffset(snap_point.value());
     }
+    scrollable_area->SetScrollOffset(end_offset,
+                                     mojom::blink::ScrollType::kProgrammatic,
+                                     mojom::blink::ScrollBehavior::kAuto);
   }
 }
 
@@ -1560,38 +1527,22 @@
       }
     }
 
-    if (RuntimeEnabledFeatures::CSSOMViewScrollCoordinatesEnabled()) {
-      ScrollOffset end_offset(scrollable_area->GetScrollOffset().Width(),
-                              new_top * box->Style()->EffectiveZoom());
-      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
-          cc::SnapSelectionStrategy::CreateForEndPosition(
-              gfx::ScrollOffset(
-                  scrollable_area->ScrollOffsetToPosition(end_offset)),
-              false, true);
-      base::Optional<FloatPoint> snap_point =
-          scrollable_area->GetSnapPositionAndSetTarget(*strategy);
-      if (snap_point.has_value()) {
-        end_offset =
-            scrollable_area->ScrollPositionToOffset(snap_point.value());
-      }
-
-      scrollable_area->SetScrollOffset(end_offset,
-                                       mojom::blink::ScrollType::kProgrammatic,
-                                       mojom::blink::ScrollBehavior::kAuto);
-    } else {
-      FloatPoint end_point(scrollable_area->ScrollPosition().X(),
-                           new_top * box->Style()->EffectiveZoom());
-      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
-          cc::SnapSelectionStrategy::CreateForEndPosition(
-              gfx::ScrollOffset(end_point), false, true);
-      end_point =
-          scrollable_area->GetSnapPositionAndSetTarget(*strategy).value_or(
-              end_point);
-      FloatPoint new_position(scrollable_area->ScrollPosition().X(),
-                              end_point.Y());
-      scrollable_area->ScrollToAbsolutePosition(
-          new_position, mojom::blink::ScrollBehavior::kAuto);
+    ScrollOffset end_offset(scrollable_area->GetScrollOffset().Width(),
+                            new_top * box->Style()->EffectiveZoom());
+    std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+        cc::SnapSelectionStrategy::CreateForEndPosition(
+            gfx::ScrollOffset(
+                scrollable_area->ScrollOffsetToPosition(end_offset)),
+            false, true);
+    base::Optional<FloatPoint> snap_point =
+        scrollable_area->GetSnapPositionAndSetTarget(*strategy);
+    if (snap_point.has_value()) {
+      end_offset = scrollable_area->ScrollPositionToOffset(snap_point.value());
     }
+
+    scrollable_area->SetScrollOffset(end_offset,
+                                     mojom::blink::ScrollType::kProgrammatic,
+                                     mojom::blink::ScrollBehavior::kAuto);
   }
 }
 
@@ -1759,60 +1710,31 @@
       }
     }
 
-    // In order to keep the behavior of element scroll consistent with document
-    // scroll, and consistent with the behavior of other vendors, the
-    // offsets in |scroll_to_options| are treated as the offset from
-    // |ScrollOrigin()|.
-    if (RuntimeEnabledFeatures::CSSOMViewScrollCoordinatesEnabled()) {
-      ScrollOffset new_offset = scrollable_area->GetScrollOffset();
-      if (scroll_to_options->hasLeft()) {
-        new_offset.SetWidth(ScrollableArea::NormalizeNonFiniteScroll(
-                                scroll_to_options->left()) *
-                            box->Style()->EffectiveZoom());
-      }
-      if (scroll_to_options->hasTop()) {
-        new_offset.SetHeight(
-            ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options->top()) *
-            box->Style()->EffectiveZoom());
-      }
-
-      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
-          cc::SnapSelectionStrategy::CreateForEndPosition(
-              gfx::ScrollOffset(
-                  scrollable_area->ScrollOffsetToPosition(new_offset)),
-              scroll_to_options->hasLeft(), scroll_to_options->hasTop());
-      base::Optional<FloatPoint> snap_point =
-          scrollable_area->GetSnapPositionAndSetTarget(*strategy);
-      if (snap_point.has_value()) {
-        new_offset =
-            scrollable_area->ScrollPositionToOffset(snap_point.value());
-      }
-
-      scrollable_area->SetScrollOffset(
-          new_offset, mojom::blink::ScrollType::kProgrammatic, scroll_behavior);
-    } else {
-      FloatPoint new_position(scrollable_area->ScrollPosition().X(),
-                              scrollable_area->ScrollPosition().Y());
-      if (scroll_to_options->hasLeft()) {
-        new_position.SetX(ScrollableArea::NormalizeNonFiniteScroll(
-                              scroll_to_options->left()) *
-                          box->Style()->EffectiveZoom());
-      }
-      if (scroll_to_options->hasTop()) {
-        new_position.SetY(
-            ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options->top()) *
-            box->Style()->EffectiveZoom());
-      }
-
-      std::unique_ptr<cc::SnapSelectionStrategy> strategy =
-          cc::SnapSelectionStrategy::CreateForEndPosition(
-              gfx::ScrollOffset(new_position), scroll_to_options->hasLeft(),
-              scroll_to_options->hasTop());
-      new_position =
-          scrollable_area->GetSnapPositionAndSetTarget(*strategy).value_or(
-              new_position);
-      scrollable_area->ScrollToAbsolutePosition(new_position, scroll_behavior);
+    ScrollOffset new_offset = scrollable_area->GetScrollOffset();
+    if (scroll_to_options->hasLeft()) {
+      new_offset.SetWidth(
+          ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options->left()) *
+          box->Style()->EffectiveZoom());
     }
+    if (scroll_to_options->hasTop()) {
+      new_offset.SetHeight(
+          ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options->top()) *
+          box->Style()->EffectiveZoom());
+    }
+
+    std::unique_ptr<cc::SnapSelectionStrategy> strategy =
+        cc::SnapSelectionStrategy::CreateForEndPosition(
+            gfx::ScrollOffset(
+                scrollable_area->ScrollOffsetToPosition(new_offset)),
+            scroll_to_options->hasLeft(), scroll_to_options->hasTop());
+    base::Optional<FloatPoint> snap_point =
+        scrollable_area->GetSnapPositionAndSetTarget(*strategy);
+    if (snap_point.has_value()) {
+      new_offset = scrollable_area->ScrollPositionToOffset(snap_point.value());
+    }
+
+    scrollable_area->SetScrollOffset(
+        new_offset, mojom::blink::ScrollType::kProgrammatic, scroll_behavior);
   }
 }
 
diff --git a/third_party/blink/renderer/core/editing/visible_position.cc b/third_party/blink/renderer/core/editing/visible_position.cc
index d271f495..8d5860f 100644
--- a/third_party/blink/renderer/core/editing/visible_position.cc
+++ b/third_party/blink/renderer/core/editing/visible_position.cc
@@ -82,49 +82,36 @@
   DocumentLifecycle::DisallowTransitionScope disallow_transition(
       document.Lifecycle());
 
-  // Find the canonical position with a backward preference.
-  const PositionWithAffinityTemplate<Strategy> backward_position =
-      SnapBackward(position_with_affinity.GetPosition());
-  if (backward_position.IsNull())
+  const PositionTemplate<Strategy> deep_position =
+      CanonicalPositionOf(position_with_affinity.GetPosition());
+  if (deep_position.IsNull())
     return VisiblePositionTemplate<Strategy>();
-  const PositionWithAffinityTemplate<Strategy> backward_position_upstream(
-      backward_position.GetPosition(), TextAffinity::kUpstream);
-  const PositionWithAffinityTemplate<Strategy> backward_position_downstream(
-      backward_position.GetPosition(), TextAffinity::kDownstream);
+  const PositionWithAffinityTemplate<Strategy> downstream_position(
+      deep_position);
+  if (position_with_affinity.Affinity() == TextAffinity::kDownstream)
+    return VisiblePositionTemplate<Strategy>(downstream_position);
 
   if (RuntimeEnabledFeatures::BidiCaretAffinityEnabled() &&
-      NGInlineFormattingContextOf(backward_position.GetPosition())) {
-    if (position_with_affinity.Affinity() == TextAffinity::kDownstream)
-      return VisiblePositionTemplate<Strategy>(backward_position_downstream);
+      NGInlineFormattingContextOf(deep_position)) {
     // When not at a line wrap or bidi boundary, make sure to end up with
     // |TextAffinity::Downstream| affinity.
-    if (AbsoluteCaretBoundsOf(backward_position_upstream) ==
-        AbsoluteCaretBoundsOf(backward_position_downstream)) {
-      return VisiblePositionTemplate<Strategy>(backward_position_downstream);
+    const PositionWithAffinityTemplate<Strategy> upstream_position(
+        deep_position, TextAffinity::kUpstream);
+
+    if (AbsoluteCaretBoundsOf(downstream_position) !=
+        AbsoluteCaretBoundsOf(upstream_position)) {
+      return VisiblePositionTemplate<Strategy>(upstream_position);
     }
-    return VisiblePositionTemplate<Strategy>(backward_position_upstream);
+    return VisiblePositionTemplate<Strategy>(downstream_position);
   }
 
-  // Find the canonical position with a forward preference. If backward_position
-  // has a downstream affinity, it means that we couldn't find any backward
-  // candidate, so they must be equal and we can avoid calling SnapForward().
-  // The forward canonical position can't be null because we already checked
-  // that the backward one is not null.
-  const PositionWithAffinityTemplate<Strategy> forward_position =
-      backward_position.Affinity() == TextAffinity::kDownstream
-          ? backward_position
-          : SnapForward(position_with_affinity.GetPosition());
-  DCHECK(forward_position.IsNotNull());
-
-  // When not at a line wrap, make sure to end up with the backward canonical
-  // position with |TextAffinity::Downstream| affinity.
-  if (InSameLine(backward_position_upstream, forward_position))
-    return VisiblePositionTemplate<Strategy>(backward_position_downstream);
-  if (position_with_affinity.Affinity() == TextAffinity::kUpstream)
-    return VisiblePositionTemplate<Strategy>(backward_position_upstream);
-  if (StartOfLine(forward_position).IsNull())
-    return VisiblePositionTemplate<Strategy>(backward_position_downstream);
-  return VisiblePositionTemplate<Strategy>(forward_position);
+  // When not at a line wrap, make sure to end up with
+  // |TextAffinity::Downstream| affinity.
+  const PositionWithAffinityTemplate<Strategy> upstream_position(
+      deep_position, TextAffinity::kUpstream);
+  if (InSameLine(downstream_position, upstream_position))
+    return VisiblePositionTemplate<Strategy>(downstream_position);
+  return VisiblePositionTemplate<Strategy>(upstream_position);
 }
 
 template <typename Strategy>
diff --git a/third_party/blink/renderer/core/editing/visible_position_test.cc b/third_party/blink/renderer/core/editing/visible_position_test.cc
index 36547fc..46cb89b 100644
--- a/third_party/blink/renderer/core/editing/visible_position_test.cc
+++ b/third_party/blink/renderer/core/editing/visible_position_test.cc
@@ -157,35 +157,19 @@
   EXPECT_EQ(Position(one->firstChild(), 0),
             CanonicalPositionOf(Position(one, 0)));
   EXPECT_EQ(Position(one->firstChild(), 0),
-            SnapBackward(Position(one, 0)).GetPosition());
-  EXPECT_EQ(Position(one->firstChild(), 0),
-            SnapForward(Position(one, 0)).GetPosition());
-  EXPECT_EQ(Position(one->firstChild(), 0),
             CreateVisiblePosition(Position(one, 0)).DeepEquivalent());
   EXPECT_EQ(Position(one->firstChild(), 2),
             CanonicalPositionOf(Position(two, 0)));
   EXPECT_EQ(Position(one->firstChild(), 2),
-            SnapBackward(Position(two, 0)).GetPosition());
-  EXPECT_EQ(Position(two->firstChild(), 0),
-            SnapForward(Position(two, 0)).GetPosition());
-  EXPECT_EQ(Position(one->firstChild(), 2),
             CreateVisiblePosition(Position(two, 0)).DeepEquivalent());
 
   EXPECT_EQ(PositionInFlatTree(five->firstChild(), 2),
             CanonicalPositionOf(PositionInFlatTree(one, 0)));
   EXPECT_EQ(PositionInFlatTree(five->firstChild(), 2),
-            SnapBackward(PositionInFlatTree(one, 0)).GetPosition());
-  EXPECT_EQ(PositionInFlatTree(one->firstChild(), 0),
-            SnapForward(PositionInFlatTree(one, 0)).GetPosition());
-  EXPECT_EQ(PositionInFlatTree(five->firstChild(), 2),
             CreateVisiblePosition(PositionInFlatTree(one, 0)).DeepEquivalent());
   EXPECT_EQ(PositionInFlatTree(four->firstChild(), 2),
             CanonicalPositionOf(PositionInFlatTree(two, 0)));
   EXPECT_EQ(PositionInFlatTree(four->firstChild(), 2),
-            SnapBackward(PositionInFlatTree(two, 0)).GetPosition());
-  EXPECT_EQ(PositionInFlatTree(two->firstChild(), 0),
-            SnapForward(PositionInFlatTree(two, 0)).GetPosition());
-  EXPECT_EQ(PositionInFlatTree(four->firstChild(), 2),
             CreateVisiblePosition(PositionInFlatTree(two, 0)).DeepEquivalent());
 }
 
diff --git a/third_party/blink/renderer/core/editing/visible_units.cc b/third_party/blink/renderer/core/editing/visible_units.cc
index 78c03b1..f308a02 100644
--- a/third_party/blink/renderer/core/editing/visible_units.cc
+++ b/third_party/blink/renderer/core/editing/visible_units.cc
@@ -75,7 +75,32 @@
 }
 
 template <typename PositionType>
-static PositionType SnapFallbackTemplate(const PositionType& position) {
+static PositionType CanonicalPosition(const PositionType& position) {
+  // Sometimes updating selection positions can be extremely expensive and
+  // occur frequently.  Often calling preventDefault on mousedown events can
+  // avoid doing unnecessary text selection work.  http://crbug.com/472258.
+  TRACE_EVENT0("input", "VisibleUnits::canonicalPosition");
+
+  // FIXME (9535):  Canonicalizing to the leftmost candidate means that if
+  // we're at a line wrap, we will ask layoutObjects to paint downstream
+  // carets for other layoutObjects. To fix this, we need to either a) add
+  // code to all paintCarets to pass the responsibility off to the appropriate
+  // layoutObject for VisiblePosition's like these, or b) canonicalize to the
+  // rightmost candidate unless the affinity is upstream.
+  if (position.IsNull())
+    return PositionType();
+
+  DCHECK(position.GetDocument());
+  DCHECK(!position.GetDocument()->NeedsLayoutTreeUpdate());
+
+  const PositionType& backward_candidate = MostBackwardCaretPosition(position);
+  if (IsVisuallyEquivalentCandidate(backward_candidate))
+    return backward_candidate;
+
+  const PositionType& forward_candidate = MostForwardCaretPosition(position);
+  if (IsVisuallyEquivalentCandidate(forward_candidate))
+    return forward_candidate;
+
   // When neither upstream or downstream gets us to a candidate
   // (upstream/downstream won't leave blocks or enter new ones), we search
   // forward and backward until we find one.
@@ -128,93 +153,12 @@
   return next;
 }
 
-template <typename Strategy>
-static PositionWithAffinityTemplate<Strategy> SnapBackwardTemplate(
-    const PositionTemplate<Strategy>& position) {
-  // Sometimes updating selection positions can be extremely expensive and
-  // occur frequently.  Often calling preventDefault on mousedown events can
-  // avoid doing unnecessary text selection work.  http://crbug.com/472258.
-  TRACE_EVENT0("input", "VisibleUnits::SnapBackward");
-
-  if (position.IsNull())
-    return PositionWithAffinityTemplate<Strategy>();
-
-  DCHECK(position.GetDocument());
-  DCHECK(!position.GetDocument()->NeedsLayoutTreeUpdate());
-
-  const PositionTemplate<Strategy>& candidate1 =
-      MostBackwardCaretPosition(position);
-  if (IsVisuallyEquivalentCandidate(candidate1)) {
-    return PositionWithAffinityTemplate<Strategy>(candidate1,
-                                                  TextAffinity::kUpstream);
-  }
-
-  const PositionTemplate<Strategy>& candidate2 =
-      MostForwardCaretPosition(position);
-  if (IsVisuallyEquivalentCandidate(candidate2)) {
-    return PositionWithAffinityTemplate<Strategy>(candidate2,
-                                                  TextAffinity::kDownstream);
-  }
-
-  return PositionWithAffinityTemplate<Strategy>(SnapFallbackTemplate(position),
-                                                TextAffinity::kDownstream);
-}
-
-PositionWithAffinity SnapBackward(const Position& position) {
-  return SnapBackwardTemplate(position);
-}
-
-PositionInFlatTreeWithAffinity SnapBackward(
-    const PositionInFlatTree& position) {
-  return SnapBackwardTemplate(position);
-}
-
-template <typename Strategy>
-static PositionWithAffinityTemplate<Strategy> SnapForwardTemplate(
-    const PositionTemplate<Strategy>& position) {
-  // Sometimes updating selection positions can be extremely expensive and
-  // occur frequently.  Often calling preventDefault on mousedown events can
-  // avoid doing unnecessary text selection work.  http://crbug.com/472258.
-  TRACE_EVENT0("input", "VisibleUnits::SnapForward");
-
-  if (position.IsNull())
-    return PositionWithAffinityTemplate<Strategy>();
-
-  DCHECK(position.GetDocument());
-  DCHECK(!position.GetDocument()->NeedsLayoutTreeUpdate());
-
-  const PositionTemplate<Strategy>& candidate1 =
-      MostForwardCaretPosition(position);
-  if (IsVisuallyEquivalentCandidate(candidate1)) {
-    return PositionWithAffinityTemplate<Strategy>(candidate1,
-                                                  TextAffinity::kDownstream);
-  }
-
-  const PositionTemplate<Strategy>& candidate2 =
-      MostBackwardCaretPosition(position);
-  if (IsVisuallyEquivalentCandidate(candidate2)) {
-    return PositionWithAffinityTemplate<Strategy>(candidate2,
-                                                  TextAffinity::kDownstream);
-  }
-
-  return PositionWithAffinityTemplate<Strategy>(SnapFallbackTemplate(position),
-                                                TextAffinity::kDownstream);
-}
-
-PositionWithAffinity SnapForward(const Position& position) {
-  return SnapForwardTemplate(position);
-}
-
-PositionInFlatTreeWithAffinity SnapForward(const PositionInFlatTree& position) {
-  return SnapForwardTemplate(position);
-}
-
 Position CanonicalPositionOf(const Position& position) {
-  return SnapBackward(position).GetPosition();
+  return CanonicalPosition(position);
 }
 
 PositionInFlatTree CanonicalPositionOf(const PositionInFlatTree& position) {
-  return SnapBackward(position).GetPosition();
+  return CanonicalPosition(position);
 }
 
 template <typename Strategy>
diff --git a/third_party/blink/renderer/core/editing/visible_units.h b/third_party/blink/renderer/core/editing/visible_units.h
index 16fa1fb5..3c32ec2 100644
--- a/third_party/blink/renderer/core/editing/visible_units.h
+++ b/third_party/blink/renderer/core/editing/visible_units.h
@@ -92,12 +92,6 @@
 // If true, adjacent candidates are visually distinct.
 CORE_EXPORT bool EndsOfNodeAreVisuallyDistinctPositions(const Node*);
 
-CORE_EXPORT PositionWithAffinity SnapBackward(const Position&);
-CORE_EXPORT PositionInFlatTreeWithAffinity
-SnapBackward(const PositionInFlatTree&);
-CORE_EXPORT PositionWithAffinity SnapForward(const Position&);
-CORE_EXPORT PositionInFlatTreeWithAffinity
-SnapForward(const PositionInFlatTree&);
 CORE_EXPORT Position CanonicalPositionOf(const Position&);
 CORE_EXPORT PositionInFlatTree CanonicalPositionOf(const PositionInFlatTree&);
 
@@ -162,17 +156,11 @@
 CORE_EXPORT VisiblePosition StartOfLine(const VisiblePosition&);
 CORE_EXPORT VisiblePositionInFlatTree
 StartOfLine(const VisiblePositionInFlatTree&);
-CORE_EXPORT PositionWithAffinity StartOfLine(const PositionWithAffinity&);
-CORE_EXPORT PositionInFlatTreeWithAffinity
-StartOfLine(const PositionInFlatTreeWithAffinity&);
 // TODO(yosin) Return values of |VisiblePosition| version of |endOfLine()| with
 // shadow tree isn't defined well. We should not use it for shadow tree.
 CORE_EXPORT VisiblePosition EndOfLine(const VisiblePosition&);
 CORE_EXPORT VisiblePositionInFlatTree
 EndOfLine(const VisiblePositionInFlatTree&);
-CORE_EXPORT PositionWithAffinity EndOfLine(const PositionWithAffinity&);
-CORE_EXPORT PositionInFlatTreeWithAffinity
-EndOfLine(const PositionInFlatTreeWithAffinity&);
 CORE_EXPORT bool InSameLine(const VisiblePosition&, const VisiblePosition&);
 CORE_EXPORT bool InSameLine(const VisiblePositionInFlatTree&,
                             const VisiblePositionInFlatTree&);
diff --git a/third_party/blink/renderer/core/editing/visible_units_line.cc b/third_party/blink/renderer/core/editing/visible_units_line.cc
index 44c6b8b..96d9af5 100644
--- a/third_party/blink/renderer/core/editing/visible_units_line.cc
+++ b/third_party/blink/renderer/core/editing/visible_units_line.cc
@@ -313,8 +313,6 @@
       vis_pos, c.GetPosition());
 }
 
-}  // namespace
-
 PositionWithAffinity StartOfLine(const PositionWithAffinity& current_position) {
   return StartOfLineAlgorithm<EditingStrategy>(current_position);
 }
@@ -324,6 +322,8 @@
   return StartOfLineAlgorithm<EditingInFlatTreeStrategy>(current_position);
 }
 
+}  // namespace
+
 // FIXME: Rename this function to reflect the fact it ignores bidi levels.
 VisiblePosition StartOfLine(const VisiblePosition& current_position) {
   DCHECK(current_position.IsValid()) << current_position;
@@ -394,11 +394,11 @@
       candidate_position, current_position.GetPosition());
 }
 
-PositionWithAffinity EndOfLine(const PositionWithAffinity& position) {
+static PositionWithAffinity EndOfLine(const PositionWithAffinity& position) {
   return EndOfLineAlgorithm<EditingStrategy>(position);
 }
 
-PositionInFlatTreeWithAffinity EndOfLine(
+static PositionInFlatTreeWithAffinity EndOfLine(
     const PositionInFlatTreeWithAffinity& position) {
   return EndOfLineAlgorithm<EditingInFlatTreeStrategy>(position);
 }
diff --git a/third_party/blink/renderer/core/editing/visible_units_line_test.cc b/third_party/blink/renderer/core/editing/visible_units_line_test.cc
index 3d9c9f3..c1dfc5a 100644
--- a/third_party/blink/renderer/core/editing/visible_units_line_test.cc
+++ b/third_party/blink/renderer/core/editing/visible_units_line_test.cc
@@ -121,12 +121,8 @@
       PositionInFlatTree(seven, 7),
       EndOfLine(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
 
-  EXPECT_EQ(Position(seven, 7), EndOfLine(CreateVisiblePositionInDOMTree(
-                                              *two, 0, TextAffinity::kUpstream))
-                                    .DeepEquivalent());
   EXPECT_EQ(
-      // The result on legacy layout is broken and not worth fixing.
-      LayoutNGEnabled() ? Position(two, 2) : Position(five, 5),
+      Position(seven, 7),
       EndOfLine(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
   EXPECT_EQ(
       PositionInFlatTree(two, 2),
@@ -143,11 +139,6 @@
   EXPECT_EQ(
       // The result on legacy layout is broken and not worth fixing.
       LayoutNGEnabled() ? Position(two, 2) : Position(five, 5),
-      EndOfLine(
-          CreateVisiblePositionInDOMTree(*three, 0, TextAffinity::kUpstream))
-          .DeepEquivalent());
-  EXPECT_EQ(
-      Position(four, 4),
       EndOfLine(CreateVisiblePositionInDOMTree(*three, 0)).DeepEquivalent());
   EXPECT_EQ(
       PositionInFlatTree(four, 4),
@@ -213,9 +204,11 @@
   EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInDOMTree(*one, 1)));
   EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInFlatTree(*one, 1)));
 
-  EXPECT_TRUE(IsEndOfLine(
-      CreateVisiblePositionInFlatTree(*two, 2, TextAffinity::kUpstream)));
-  EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInDOMTree(*two, 2)));
+  // The result on legacy layout is broken and not worth fixing.
+  if (LayoutNGEnabled())
+    EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInFlatTree(*two, 2)));
+  else
+    EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInDOMTree(*two, 2)));
   EXPECT_TRUE(IsEndOfLine(CreateVisiblePositionInFlatTree(*two, 2)));
 
   EXPECT_FALSE(IsEndOfLine(CreateVisiblePositionInDOMTree(*three, 3)));
@@ -269,14 +262,10 @@
   EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*one, 1)));
 
   // The result in legacy layout is broken and not worth fixing.
-  if (LayoutNGEnabled()) {
-    EXPECT_TRUE(IsLogicalEndOfLine(
-        CreateVisiblePositionInDOMTree(*two, 2, TextAffinity::kUpstream)));
-  } else {
-    EXPECT_FALSE(IsLogicalEndOfLine(
-        CreateVisiblePositionInDOMTree(*two, 2, TextAffinity::kUpstream)));
-  }
-  EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 2)));
+  if (LayoutNGEnabled())
+    EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 2)));
+  else
+    EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 2)));
   EXPECT_TRUE(IsLogicalEndOfLine(CreateVisiblePositionInFlatTree(*two, 2)));
 
   EXPECT_FALSE(IsLogicalEndOfLine(CreateVisiblePositionInDOMTree(*three, 3)));
@@ -326,25 +315,15 @@
       InSameLine(PositionWithAffinityInDOMTree(*two->firstChild(), 0),
                  PositionWithAffinityInDOMTree(*four->firstChild(), 0)));
 
-  EXPECT_TRUE(InSameLine(
-      CreateVisiblePositionInDOMTree(*one, 0),
-      CreateVisiblePositionInDOMTree(*two, 0, TextAffinity::kUpstream)));
-  EXPECT_FALSE(InSameLine(CreateVisiblePositionInDOMTree(*one, 0),
-                          CreateVisiblePositionInDOMTree(*two, 0)));
-  EXPECT_TRUE(InSameLine(CreateVisiblePositionInDOMTree(*one->firstChild(), 0),
-                         CreateVisiblePositionInDOMTree(
-                             *two->firstChild(), 0, TextAffinity::kUpstream)));
-  EXPECT_FALSE(
+  EXPECT_TRUE(InSameLine(CreateVisiblePositionInDOMTree(*one, 0),
+                         CreateVisiblePositionInDOMTree(*two, 0)));
+  EXPECT_TRUE(
       InSameLine(CreateVisiblePositionInDOMTree(*one->firstChild(), 0),
                  CreateVisiblePositionInDOMTree(*two->firstChild(), 0)));
   EXPECT_FALSE(
       InSameLine(CreateVisiblePositionInDOMTree(*one->firstChild(), 0),
                  CreateVisiblePositionInDOMTree(*five->firstChild(), 0)));
   EXPECT_FALSE(
-      InSameLine(CreateVisiblePositionInDOMTree(*two->firstChild(), 0,
-                                                TextAffinity::kUpstream),
-                 CreateVisiblePositionInDOMTree(*four->firstChild(), 0)));
-  EXPECT_TRUE(
       InSameLine(CreateVisiblePositionInDOMTree(*two->firstChild(), 0),
                  CreateVisiblePositionInDOMTree(*four->firstChild(), 0)));
 
@@ -401,9 +380,7 @@
   EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*two, 0)));
   EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInFlatTree(*two, 0)));
 
-  EXPECT_FALSE(IsStartOfLine(
-      CreateVisiblePositionInDOMTree(*three, 0, TextAffinity::kUpstream)));
-  EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInDOMTree(*three, 0)));
+  EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*three, 0)));
   EXPECT_TRUE(IsStartOfLine(CreateVisiblePositionInFlatTree(*three, 0)));
 
   EXPECT_FALSE(IsStartOfLine(CreateVisiblePositionInDOMTree(*four, 0)));
@@ -458,11 +435,6 @@
                 .DeepEquivalent());
 
   EXPECT_EQ(Position(seven, 7),
-            LogicalEndOfLine(CreateVisiblePositionInDOMTree(
-                                 *two, 0, TextAffinity::kUpstream))
-                .DeepEquivalent());
-  // The result on legacy layout is broken and not worth fixing.
-  EXPECT_EQ(LayoutNGEnabled() ? Position(two, 2) : Position(five, 5),
             LogicalEndOfLine(CreateVisiblePositionInDOMTree(*two, 0))
                 .DeepEquivalent());
   EXPECT_EQ(PositionInFlatTree(two, 2),
@@ -480,10 +452,6 @@
   // DOM VisiblePosition canonicalization moves input position to (two, 2),
   // which yields wrong results in both legacy layout and LayoutNG.
   EXPECT_EQ(LayoutNGEnabled() ? Position(two, 2) : Position(five, 5),
-            LogicalEndOfLine(CreateVisiblePositionInDOMTree(
-                                 *three, 0, TextAffinity::kUpstream))
-                .DeepEquivalent());
-  EXPECT_EQ(Position(four, 4),
             LogicalEndOfLine(CreateVisiblePositionInDOMTree(*three, 0))
                 .DeepEquivalent());
   EXPECT_EQ(PositionInFlatTree(four, 4),
@@ -554,10 +522,6 @@
                 .DeepEquivalent());
 
   EXPECT_EQ(Position(one, 0),
-            LogicalStartOfLine(CreateVisiblePositionInDOMTree(
-                                   *two, 0, TextAffinity::kUpstream))
-                .DeepEquivalent());
-  EXPECT_EQ(Position(five, 0),
             LogicalStartOfLine(CreateVisiblePositionInDOMTree(*two, 0))
                 .DeepEquivalent());
   EXPECT_EQ(PositionInFlatTree(five, 0),
@@ -572,21 +536,15 @@
                 .DeepEquivalent());
 
   EXPECT_EQ(Position(five, 0),
-            LogicalStartOfLine(CreateVisiblePositionInDOMTree(
-                                   *three, 0, TextAffinity::kUpstream))
-                .DeepEquivalent());
-  EXPECT_EQ(Position(three, 0),
             LogicalStartOfLine(CreateVisiblePositionInDOMTree(*three, 0))
                 .DeepEquivalent());
   EXPECT_EQ(PositionInFlatTree(three, 0),
             LogicalStartOfLine(CreateVisiblePositionInFlatTree(*three, 1))
                 .DeepEquivalent());
 
-  EXPECT_EQ(Position(three, 0),
-            LogicalStartOfLine(CreateVisiblePositionInDOMTree(
-                                   *four, 1, TextAffinity::kUpstream))
-                .DeepEquivalent());
-  EXPECT_EQ(Position(three, 0),
+  // TODO(yosin) logicalStartOfLine(four, 1) -> (two, 2) is a broken result.
+  // We keep it as a marker for future change.
+  EXPECT_EQ(Position(two, 2),
             LogicalStartOfLine(CreateVisiblePositionInDOMTree(*four, 1))
                 .DeepEquivalent());
   EXPECT_EQ(PositionInFlatTree(three, 0),
@@ -653,11 +611,8 @@
       PositionInFlatTree(one, 0),
       StartOfLine(CreateVisiblePositionInFlatTree(*one, 1)).DeepEquivalent());
 
-  EXPECT_EQ(Position(one, 0), StartOfLine(CreateVisiblePositionInDOMTree(
-                                              *two, 0, TextAffinity::kUpstream))
-                                  .DeepEquivalent());
   EXPECT_EQ(
-      Position(five, 0),
+      Position(one, 0),
       StartOfLine(CreateVisiblePositionInDOMTree(*two, 0)).DeepEquivalent());
   EXPECT_EQ(
       PositionInFlatTree(five, 0),
@@ -670,23 +625,17 @@
       PositionInFlatTree(five, 0),
       StartOfLine(CreateVisiblePositionInFlatTree(*two, 1)).DeepEquivalent());
 
-  EXPECT_EQ(Position(five, 0),
-            StartOfLine(CreateVisiblePositionInDOMTree(*three, 0,
-                                                       TextAffinity::kUpstream))
-                .DeepEquivalent());
   EXPECT_EQ(
-      Position(three, 0),
+      Position(five, 0),
       StartOfLine(CreateVisiblePositionInDOMTree(*three, 0)).DeepEquivalent());
   EXPECT_EQ(
       PositionInFlatTree(three, 0),
       StartOfLine(CreateVisiblePositionInFlatTree(*three, 1)).DeepEquivalent());
 
-  EXPECT_EQ(Position(three, 0),
-            StartOfLine(CreateVisiblePositionInDOMTree(*four, 1,
-                                                       TextAffinity::kUpstream))
-                .DeepEquivalent());
+  // TODO(yosin) startOfLine(four, 1) -> (two, 2) is a broken result. We keep
+  // it as a marker for future change.
   EXPECT_EQ(
-      Position(three, 0),
+      Position(two, 2),
       StartOfLine(CreateVisiblePositionInDOMTree(*four, 1)).DeepEquivalent());
   EXPECT_EQ(
       PositionInFlatTree(three, 0),
diff --git a/third_party/blink/renderer/core/editing/visible_units_paragraph.cc b/third_party/blink/renderer/core/editing/visible_units_paragraph.cc
index 03ad84b..2c8f3a3a 100644
--- a/third_party/blink/renderer/core/editing/visible_units_paragraph.cc
+++ b/third_party/blink/renderer/core/editing/visible_units_paragraph.cc
@@ -147,10 +147,8 @@
     const VisiblePositionTemplate<Strategy>& visible_position,
     EditingBoundaryCrossingRule boundary_crossing_rule) {
   DCHECK(visible_position.IsValid()) << visible_position;
-  return CreateVisiblePosition(
-      StartOfParagraphAlgorithm(visible_position.DeepEquivalent(),
-                                boundary_crossing_rule),
-      TextAffinity::kDownstream);
+  return CreateVisiblePosition(StartOfParagraphAlgorithm(
+      visible_position.DeepEquivalent(), boundary_crossing_rule));
 }
 
 template <typename Strategy>
@@ -247,10 +245,8 @@
     const VisiblePositionTemplate<Strategy>& visible_position,
     EditingBoundaryCrossingRule boundary_crossing_rule) {
   DCHECK(visible_position.IsValid()) << visible_position;
-  return CreateVisiblePosition(
-      EndOfParagraphAlgorithm(visible_position.DeepEquivalent(),
-                              boundary_crossing_rule),
-      TextAffinity::kUpstream);
+  return CreateVisiblePosition(EndOfParagraphAlgorithm(
+      visible_position.DeepEquivalent(), boundary_crossing_rule));
 }
 
 template <typename Strategy>
diff --git a/third_party/blink/renderer/core/editing/visible_units_test.cc b/third_party/blink/renderer/core/editing/visible_units_test.cc
index aa3a50f..69ef2db 100644
--- a/third_party/blink/renderer/core/editing/visible_units_test.cc
+++ b/third_party/blink/renderer/core/editing/visible_units_test.cc
@@ -113,66 +113,25 @@
 
   EXPECT_EQ(Position(),
             CanonicalPositionOf(Position(GetDocument().documentElement(), 0)));
-  EXPECT_EQ(
-      Position(),
-      SnapBackward(Position(GetDocument().documentElement(), 0)).GetPosition());
-  EXPECT_EQ(
-      Position(),
-      SnapForward(Position(GetDocument().documentElement(), 0)).GetPosition());
 
   EXPECT_EQ(Position(one->firstChild(), 0),
             CanonicalPositionOf(Position(one, 0)));
-  EXPECT_EQ(Position(one->firstChild(), 0),
-            SnapBackward(Position(one, 0)).GetPosition());
-  EXPECT_EQ(Position(one->firstChild(), 0),
-            SnapForward(Position(one, 0)).GetPosition());
-
   EXPECT_EQ(Position(one->firstChild(), 1),
             CanonicalPositionOf(Position(one, 1)));
-  EXPECT_EQ(Position(one->firstChild(), 1),
-            SnapBackward(Position(one, 1)).GetPosition());
-  EXPECT_EQ(Position(one->firstChild(), 1),
-            SnapForward(Position(one, 1)).GetPosition());
 
   EXPECT_EQ(Position(one->firstChild(), 0),
             CanonicalPositionOf(Position(one->firstChild(), 0)));
-  EXPECT_EQ(Position(one->firstChild(), 0),
-            SnapBackward(Position(one->firstChild(), 0)).GetPosition());
-  EXPECT_EQ(Position(one->firstChild(), 0),
-            SnapForward(Position(one->firstChild(), 0)).GetPosition());
-
   EXPECT_EQ(Position(one->firstChild(), 1),
             CanonicalPositionOf(Position(one->firstChild(), 1)));
-  EXPECT_EQ(Position(one->firstChild(), 1),
-            SnapBackward(Position(one->firstChild(), 1)).GetPosition());
-  EXPECT_EQ(Position(one->firstChild(), 1),
-            SnapForward(Position(one->firstChild(), 1)).GetPosition());
 
   EXPECT_EQ(Position(html, 0), CanonicalPositionOf(Position(html, 0)));
-  EXPECT_EQ(Position(html, 0), SnapBackward(Position(html, 0)).GetPosition());
-  EXPECT_EQ(Position(html, 0), SnapForward(Position(html, 0)).GetPosition());
-
   EXPECT_EQ(Position(html, 1), CanonicalPositionOf(Position(html, 1)));
-  EXPECT_EQ(Position(html, 1), SnapBackward(Position(html, 1)).GetPosition());
-  EXPECT_EQ(Position(html, 1), SnapForward(Position(html, 1)).GetPosition());
-
   EXPECT_EQ(Position(html, 2), CanonicalPositionOf(Position(html, 2)));
-  EXPECT_EQ(Position(html, 2), SnapBackward(Position(html, 2)).GetPosition());
-  EXPECT_EQ(Position(html, 2), SnapForward(Position(html, 2)).GetPosition());
 
   EXPECT_EQ(Position(two->firstChild(), 0),
             CanonicalPositionOf(Position(two, 0)));
-  EXPECT_EQ(Position(two->firstChild(), 0),
-            SnapBackward(Position(two, 0)).GetPosition());
-  EXPECT_EQ(Position(two->firstChild(), 0),
-            SnapForward(Position(two, 0)).GetPosition());
-
   EXPECT_EQ(Position(two->firstChild(), 2),
             CanonicalPositionOf(Position(two, 1)));
-  EXPECT_EQ(Position(two->firstChild(), 2),
-            SnapBackward(Position(two, 1)).GetPosition());
-  EXPECT_EQ(Position(two->firstChild(), 2),
-            SnapForward(Position(two, 1)).GetPosition());
 }
 
 // For http://crbug.com/695317
@@ -180,20 +139,13 @@
   SetBodyContent("<input>123");
   Element* const input = GetDocument().QuerySelector("input");
 
-  Position position =
-      Position::FirstPositionInNode(*GetDocument().documentElement());
-  EXPECT_EQ(Position::BeforeNode(*input), CanonicalPositionOf(position));
-  EXPECT_EQ(Position::BeforeNode(*input), SnapBackward(position).GetPosition());
-  EXPECT_EQ(Position::BeforeNode(*input), SnapForward(position).GetPosition());
+  EXPECT_EQ(Position::BeforeNode(*input),
+            CanonicalPositionOf(Position::FirstPositionInNode(
+                *GetDocument().documentElement())));
 
-  PositionInFlatTree pos_in_flat_tree =
-      PositionInFlatTree::FirstPositionInNode(*GetDocument().documentElement());
   EXPECT_EQ(PositionInFlatTree::BeforeNode(*input),
-            CanonicalPositionOf(pos_in_flat_tree));
-  EXPECT_EQ(PositionInFlatTree::BeforeNode(*input),
-            SnapBackward(pos_in_flat_tree).GetPosition());
-  EXPECT_EQ(PositionInFlatTree::BeforeNode(*input),
-            SnapForward(pos_in_flat_tree).GetPosition());
+            CanonicalPositionOf(PositionInFlatTree::FirstPositionInNode(
+                *GetDocument().documentElement())));
 }
 
 TEST_F(VisibleUnitsTest, characterBefore) {
@@ -805,12 +757,8 @@
 
   Node* paragraph = GetDocument().QuerySelector("p");
   Node* text = paragraph->firstChild();
-  EXPECT_EQ(Position(text, 2),
-            CanonicalPositionOf(Position::BeforeNode(*paragraph)));
-  EXPECT_EQ(Position(text, 2),
-            SnapBackward(Position::BeforeNode(*paragraph)).GetPosition());
-  EXPECT_EQ(Position(text, 2),
-            SnapForward(Position::BeforeNode(*paragraph)).GetPosition());
+  Position start = CanonicalPositionOf(Position::BeforeNode(*paragraph));
+  EXPECT_EQ(Position(text, 2), start);
 }
 
 TEST_F(VisibleUnitsTest, MostForwardCaretPositionWithInvisibleFirstLetter) {
diff --git a/third_party/blink/renderer/core/editing/visible_units_word_test.cc b/third_party/blink/renderer/core/editing/visible_units_word_test.cc
index 343fde7..2dc0001e 100644
--- a/third_party/blink/renderer/core/editing/visible_units_word_test.cc
+++ b/third_party/blink/renderer/core/editing/visible_units_word_test.cc
@@ -233,13 +233,8 @@
                 StartOfWordPosition(
                     CreateVisiblePositionInFlatTree(*two, 1).DeepEquivalent()))
                 .DeepEquivalent());
-  EXPECT_EQ(Position(three, 0),
-            CreateVisiblePosition(
-                StartOfWordPosition(CreateVisiblePositionInDOMTree(
-                                        *three, 1, TextAffinity::kUpstream)
-                                        .DeepEquivalent()))
-                .DeepEquivalent());
-  EXPECT_EQ(Position(three, 0),
+  // DOM tree canonicalization moves the result to a wrong position.
+  EXPECT_EQ(Position(two, 2),
             CreateVisiblePosition(
                 StartOfWordPosition(
                     CreateVisiblePositionInDOMTree(*three, 1).DeepEquivalent()))
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 9503246..e146da4 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -43,6 +43,7 @@
 #include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
 #include "third_party/blink/public/common/privacy_budget/identifiability_metrics.h"
 #include "third_party/blink/public/common/privacy_budget/identifiability_study_participation.h"
+#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
 #include "third_party/blink/public/common/privacy_budget/identifiable_surface.h"
 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
 #include "third_party/blink/public/mojom/gpu/gpu.mojom-blink.h"
@@ -315,6 +316,17 @@
     const CanvasContextCreationAttributesCore& attributes) {
   auto* old_contents_cc_layer = ContentsCcLayer();
   auto* result = GetCanvasRenderingContextInternal(type, attributes);
+
+  if (ukm_params_ && IdentifiabilityStudySettings::Get()->IsTypeAllowed(
+                         IdentifiableSurface::Type::kCanvasRenderingContext)) {
+    IdentifiabilityMetricBuilder(ukm_params_->source_id)
+        .Set(IdentifiableSurface::FromTypeAndToken(
+                 IdentifiableSurface::Type::kCanvasRenderingContext,
+                 CanvasRenderingContext::ContextTypeFromId(type)),
+             !!result)
+        .Record(ukm_params_->ukm_recorder);
+  }
+
   if (ContentsCcLayer() != old_contents_cc_layer)
     OnContentsCcLayerChanged();
   return result;
@@ -333,13 +345,6 @@
 
   // Log the aliased context type used.
   if (!context_) {
-    if (IsUserInIdentifiabilityStudy()) {
-      RecordIdentifiabilityMetric(
-          IdentifiableSurface::FromTypeAndToken(
-              blink::IdentifiableSurface::Type::kWebFeature,
-              blink::WebFeature::kCanvasRenderingContext),
-          context_type);
-    }
     UMA_HISTOGRAM_ENUMERATION("Blink.Canvas.ContextType", context_type);
   }
 
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index 694ff382..92e39b8d 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -213,12 +213,6 @@
     "netinfo/testing/internals_net_info.h",
     "peerconnection/adapters/test/mock_ice_transport_adapter.h",
     "peerconnection/adapters/test/mock_ice_transport_adapter_cross_thread_factory.h",
-    "peerconnection/adapters/test/mock_p2p_quic_packet_transport.h",
-    "peerconnection/adapters/test/mock_p2p_quic_stream.h",
-    "peerconnection/adapters/test/mock_p2p_quic_stream_delegate.h",
-    "peerconnection/adapters/test/mock_p2p_quic_transport.h",
-    "peerconnection/adapters/test/mock_p2p_quic_transport_delegate.h",
-    "peerconnection/adapters/test/mock_p2p_quic_transport_factory.h",
     "peerconnection/testing/fake_resource_listener.cc",
     "peerconnection/testing/fake_resource_listener.h",
     "peerconnection/testing/internals_rtc_certificate.cc",
@@ -394,9 +388,6 @@
     "payments/payment_test_helper.cc",
     "payments/payment_test_helper.h",
     "payments/payments_validators_test.cc",
-    "peerconnection/adapters/p2p_quic_stream_unittest.cc",
-    "peerconnection/adapters/p2p_quic_transport_test.cc",
-    "peerconnection/adapters/quic_packet_transport_adapter_test.cc",
     "peerconnection/byte_buffer_queue_test.cc",
     "peerconnection/call_setup_state_tracker_unittest.cc",
     "peerconnection/media_stream_remote_video_source_test.cc",
@@ -413,9 +404,6 @@
     "peerconnection/rtc_ice_transport_test.h",
     "peerconnection/rtc_peer_connection_handler_test.cc",
     "peerconnection/rtc_peer_connection_test.cc",
-    "peerconnection/rtc_quic_stream_test.cc",
-    "peerconnection/rtc_quic_transport_test.cc",
-    "peerconnection/rtc_quic_transport_test.h",
     "peerconnection/rtc_rtp_receiver_impl_test.cc",
     "peerconnection/rtc_rtp_sender_impl_test.cc",
     "peerconnection/rtc_rtp_transceiver_impl_test.cc",
@@ -502,7 +490,6 @@
     "//media/mojo/mojom",
     "//media/webrtc:webrtc",
     "//mojo/public/cpp/bindings",
-    "//net:quic_test_tools",
     "//net:test_support",
     "//services/device/public/cpp:test_support",
     "//skia",
diff --git a/third_party/blink/renderer/modules/peerconnection/BUILD.gn b/third_party/blink/renderer/modules/peerconnection/BUILD.gn
index c4651cf..039fdaf 100644
--- a/third_party/blink/renderer/modules/peerconnection/BUILD.gn
+++ b/third_party/blink/renderer/modules/peerconnection/BUILD.gn
@@ -16,34 +16,6 @@
     "adapters/ice_transport_host.h",
     "adapters/ice_transport_proxy.cc",
     "adapters/ice_transport_proxy.h",
-    "adapters/p2p_quic_crypto_config_factory.h",
-    "adapters/p2p_quic_crypto_config_factory_impl.cc",
-    "adapters/p2p_quic_crypto_config_factory_impl.h",
-    "adapters/p2p_quic_crypto_stream_factory.h",
-    "adapters/p2p_quic_crypto_stream_factory_impl.cc",
-    "adapters/p2p_quic_crypto_stream_factory_impl.h",
-    "adapters/p2p_quic_packet_transport.h",
-    "adapters/p2p_quic_stream.h",
-    "adapters/p2p_quic_stream_impl.cc",
-    "adapters/p2p_quic_stream_impl.h",
-    "adapters/p2p_quic_transport.h",
-    "adapters/p2p_quic_transport_factory.h",
-    "adapters/p2p_quic_transport_factory_impl.cc",
-    "adapters/p2p_quic_transport_factory_impl.h",
-    "adapters/p2p_quic_transport_impl.cc",
-    "adapters/p2p_quic_transport_impl.h",
-    "adapters/p2p_quic_transport_stats.cc",
-    "adapters/p2p_quic_transport_stats.h",
-    "adapters/quic_packet_transport_adapter.cc",
-    "adapters/quic_packet_transport_adapter.h",
-    "adapters/quic_stream_host.cc",
-    "adapters/quic_stream_host.h",
-    "adapters/quic_stream_proxy.cc",
-    "adapters/quic_stream_proxy.h",
-    "adapters/quic_transport_host.cc",
-    "adapters/quic_transport_host.h",
-    "adapters/quic_transport_proxy.cc",
-    "adapters/quic_transport_proxy.h",
     "adapters/sctp_transport_proxy.cc",
     "adapters/sctp_transport_proxy.h",
     "adapters/web_rtc_cross_thread_copier.cc",
@@ -114,12 +86,6 @@
     "rtc_peer_connection_ice_error_event.h",
     "rtc_peer_connection_ice_event.cc",
     "rtc_peer_connection_ice_event.h",
-    "rtc_quic_stream.cc",
-    "rtc_quic_stream.h",
-    "rtc_quic_stream_event.cc",
-    "rtc_quic_stream_event.h",
-    "rtc_quic_transport.cc",
-    "rtc_quic_transport.h",
     "rtc_rtp_receiver.cc",
     "rtc_rtp_receiver.h",
     "rtc_rtp_receiver_impl.cc",
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h
index 7b0e6ca..f368a99 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h
@@ -12,8 +12,6 @@
 
 namespace blink {
 
-class P2PQuicPacketTransport;
-
 // Defines the ICE candidate policy the browser uses to surface the permitted
 // candidates to the application.
 // https://w3c.github.io/webrtc-pc/#dom-rtcicetransportpolicy
@@ -83,10 +81,6 @@
   // Adds a remote candidate to potentially start connectivity checks with.
   // The caller must ensure Start() has already bene called.
   virtual void AddRemoteCandidate(const cricket::Candidate& candidate) = 0;
-
-  // Gets a P2PQuicPacketTransport that is backed by this ICE connection. The
-  // returned instance lives the same lifetime as the IceTransportAdapter.
-  virtual P2PQuicPacketTransport* packet_transport() const = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
index 3214883..7f0bb03 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "base/notreached.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h"
 #include "third_party/webrtc/api/ice_transport_factory.h"
 
 namespace blink {
@@ -43,9 +42,6 @@
   // generated so that each peer can calculate a.tiebreaker <= b.tiebreaker
   // consistently.
   ice_transport_channel()->SetIceTiebreaker(rtc::CreateRandomId64());
-
-  quic_packet_transport_adapter_ =
-      std::make_unique<QuicPacketTransportAdapter>(ice_transport_channel());
 }
 
 IceTransportAdapterImpl::IceTransportAdapterImpl(
@@ -131,10 +127,6 @@
   ice_transport_channel()->AddRemoteCandidate(candidate);
 }
 
-P2PQuicPacketTransport* IceTransportAdapterImpl::packet_transport() const {
-  return quic_packet_transport_adapter_.get();
-}
-
 void IceTransportAdapterImpl::SetupIceTransportChannel() {
   if (!ice_transport_channel()) {
     LOG(ERROR) << "SetupIceTransportChannel called, but ICE transport released";
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h
index be28c9a6..558f229 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h
@@ -26,8 +26,8 @@
       std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory);
 
   // Create an IceTransportAdapter for an existing |ice_transport_channel|
-  // object. In this case, |port_allocator_|, |async_resolver_factory_| and
-  // |quic_packet_transport_adapter_| are not used (and null).
+  // object. In this case, |port_allocator_|, |async_resolver_factory_| is not
+  // used (and null).
   IceTransportAdapterImpl(
       Delegate* delegate,
       rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport_channel);
@@ -46,7 +46,6 @@
   void HandleRemoteRestart(
       const cricket::IceParameters& new_remote_parameters) override;
   void AddRemoteCandidate(const cricket::Candidate& candidate) override;
-  P2PQuicPacketTransport* packet_transport() const override;
 
  private:
   cricket::IceTransportInternal* ice_transport_channel() {
@@ -66,7 +65,6 @@
   std::unique_ptr<cricket::PortAllocator> port_allocator_;
   std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory_;
   rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport_channel_;
-  std::unique_ptr<P2PQuicPacketTransport> quic_packet_transport_adapter_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h
deleted file mode 100644
index fb37bf0..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h
+++ /dev/null
@@ -1,33 +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_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_H_
-
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
-
-namespace blink {
-
-// Builds the crypto configurations to be used by the P2PQuicTransport.
-class P2PQuicCryptoConfigFactory {
- public:
-  virtual ~P2PQuicCryptoConfigFactory() = default;
-
-  // Creates the client crypto configuration to be used by a
-  // quic::QuicCryptoClientStream. This includes a ProofVerifier object that
-  // verifies the server's certificate and is used in the QUIC handshake.
-  virtual std::unique_ptr<quic::QuicCryptoClientConfig>
-  CreateClientCryptoConfig() = 0;
-
-  // Creates the server crypto configuration to be used by a
-  // quic::QuicCryptoServerStream. This includes a ProofSource object that gives
-  // the server's certificate.
-  virtual std::unique_ptr<quic::QuicCryptoServerConfig>
-  CreateServerCryptoConfig() = 0;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.cc
deleted file mode 100644
index 5af9c17..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.cc
+++ /dev/null
@@ -1,140 +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 "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
-#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h"
-
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h"
-
-namespace blink {
-
-namespace {
-
-// Length of HKDF input keying material, equal to its number of bytes.
-// https://tools.ietf.org/html/rfc5869#section-2.2.
-const size_t kInputKeyingMaterialLength = 32;
-
-// TODO(https://crbug.com/874300): Implement a secure QUIC handshake, meaning
-// that both side's certificates are verified. This can be done by creating a
-// P2PProofSource and P2PProofVerifier, and removing these objects once the
-// TLS 1.3 handshake is implemented for QUIC.
-// - The self signed certificate fingerprint matches the remote
-//   fingerprint that was signaled.
-// - The peer owns the certificate, by verifying the signature of the hash of
-//   the handshake context.
-//
-// Ignores the peer's credentials (taken from quic/quartc).
-class InsecureProofVerifier : public quic::ProofVerifier {
- public:
-  InsecureProofVerifier() {}
-  ~InsecureProofVerifier() override {}
-
-  // ProofVerifier override.
-  quic::QuicAsyncStatus VerifyProof(
-      const std::string& hostname,
-      const uint16_t port,
-      const std::string& server_config,
-      quic::QuicTransportVersion transport_version,
-      quiche::QuicheStringPiece chlo_hash,
-      const std::vector<std::string>& certs,
-      const std::string& cert_sct,
-      const std::string& signature,
-      const quic::ProofVerifyContext* context,
-      std::string* error_details,
-      std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
-      std::unique_ptr<quic::ProofVerifierCallback> callback) override {
-    return quic::QUIC_SUCCESS;
-  }
-
-  quic::QuicAsyncStatus VerifyCertChain(
-      const std::string& hostname,
-      const uint16_t port,
-      const std::vector<std::string>& certs,
-      const std::string& ocsp_response,
-      const std::string& cert_sct,
-      const quic::ProofVerifyContext* context,
-      std::string* error_details,
-      std::unique_ptr<quic::ProofVerifyDetails>* details,
-      std::unique_ptr<quic::ProofVerifierCallback> callback) override {
-    return quic::QUIC_SUCCESS;
-  }
-
-  std::unique_ptr<quic::ProofVerifyContext> CreateDefaultContext() override {
-    return nullptr;
-  }
-};
-
-}  // namespace
-
-// Used by QuicCryptoServerConfig to provide dummy proof credentials
-// (taken from quic/quartc).
-class DummyProofSource : public quic::ProofSource {
- public:
-  DummyProofSource() {}
-  ~DummyProofSource() override {}
-
-  // ProofSource override.
-  void GetProof(const quic::QuicSocketAddress& server_addr,
-                const quic::QuicSocketAddress& client_addr,
-                const std::string& hostname,
-                const std::string& server_config,
-                quic::QuicTransportVersion transport_version,
-                quiche::QuicheStringPiece chlo_hash,
-                std::unique_ptr<Callback> callback) override {
-    quic::QuicCryptoProof proof;
-    proof.signature = "Dummy signature";
-    proof.leaf_cert_scts = "Dummy timestamp";
-    callback->Run(true, GetCertChain(server_addr, client_addr, hostname), proof,
-                  nullptr /* details */);
-  }
-
-  quic::QuicReferenceCountedPointer<Chain> GetCertChain(
-      const quic::QuicSocketAddress& server_address,
-      const quic::QuicSocketAddress& client_address,
-      const std::string& hostname) override {
-    std::vector<std::string> certs;
-    certs.push_back("Dummy cert");
-    return quic::QuicReferenceCountedPointer<Chain>(
-        new quic::ProofSource::Chain(certs));
-  }
-  void ComputeTlsSignature(
-      const quic::QuicSocketAddress& server_address,
-      const quic::QuicSocketAddress& client_address,
-      const std::string& hostname,
-      uint16_t signature_algorithm,
-      quiche::QuicheStringPiece in,
-      std::unique_ptr<SignatureCallback> callback) override {
-    callback->Run(true, "Dummy signature", nullptr);
-  }
-
-  TicketCrypter* GetTicketCrypter() override { return nullptr; }
-};
-
-P2PQuicCryptoConfigFactoryImpl::P2PQuicCryptoConfigFactoryImpl(
-    quic::QuicRandom* const random_generator)
-    : random_generator_(random_generator) {}
-
-std::unique_ptr<quic::QuicCryptoClientConfig>
-P2PQuicCryptoConfigFactoryImpl::CreateClientCryptoConfig() {
-  std::unique_ptr<quic::ProofVerifier> proof_verifier(
-      new InsecureProofVerifier);
-  return std::make_unique<quic::QuicCryptoClientConfig>(
-      std::move(proof_verifier));
-}
-
-std::unique_ptr<quic::QuicCryptoServerConfig>
-P2PQuicCryptoConfigFactoryImpl::CreateServerCryptoConfig() {
-  // Generate a random source address token secret every time since this is
-  // a transient client.
-  char source_address_token_secret[kInputKeyingMaterialLength];
-  random_generator_->RandBytes(source_address_token_secret,
-                               kInputKeyingMaterialLength);
-  std::unique_ptr<quic::ProofSource> proof_source(new DummyProofSource);
-  return std::make_unique<quic::QuicCryptoServerConfig>(
-      std::string(source_address_token_secret, kInputKeyingMaterialLength),
-      random_generator_, std::move(proof_source),
-      quic::KeyExchangeSource::Default());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h
deleted file mode 100644
index 349a6690..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.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 THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_IMPL_H_
-
-#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h"
-#include "third_party/webrtc/rtc_base/rtc_certificate.h"
-
-namespace blink {
-
-// An abstraction for building the crypto configurations to be used by the
-// P2PQuicTransport.
-class MODULES_EXPORT P2PQuicCryptoConfigFactoryImpl final
-    : public P2PQuicCryptoConfigFactory {
- public:
-  P2PQuicCryptoConfigFactoryImpl(
-      quic::QuicRandom* const random_generator);
-
-  ~P2PQuicCryptoConfigFactoryImpl() override {}
-
-  // P2PQuicCryptoConfigFactory overrides.
-  //
-  // Creates a client config that accepts any remote certificate.
-  std::unique_ptr<quic::QuicCryptoClientConfig> CreateClientCryptoConfig()
-      override;
-  // Creates a server config with a DummyProofSource.
-  std::unique_ptr<quic::QuicCryptoServerConfig> CreateServerCryptoConfig()
-      override;
-
- private:
-  // TODO(crbug.com/874296): Add certificate(s) to create a proof source
-  // that comes from the self signed certificate given to the RTCQuicTransport.
-  quic::QuicRandom* const random_generator_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_CONFIG_FACTORY_IMPL_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory.h
deleted file mode 100644
index c4516cf..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory.h
+++ /dev/null
@@ -1,34 +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_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_STREAM_FACTORY_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_STREAM_FACTORY_H_
-
-#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
-#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h"
-
-namespace blink {
-
-// Builds the crypto stream to be used by the P2PQuicTransport.
-class P2PQuicCryptoStreamFactory {
- public:
-  virtual ~P2PQuicCryptoStreamFactory() = default;
-
-  virtual std::unique_ptr<quic::QuicCryptoClientStream>
-  CreateClientCryptoStream(
-      quic::QuicSession* session,
-      quic::QuicCryptoClientConfig* crypto_config,
-      quic::QuicCryptoClientStream::ProofHandler* proof_handler) = 0;
-
-  virtual std::unique_ptr<quic::QuicCryptoServerStreamBase>
-  CreateServerCryptoStream(
-      const quic::QuicCryptoServerConfig* crypto_config,
-      quic::QuicCompressedCertsCache* compressed_certs_cache,
-      quic::QuicSession* session,
-      quic::QuicCryptoServerStreamBase::Helper* helper) = 0;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_STREAM_FACTORY_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory_impl.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory_impl.cc
deleted file mode 100644
index 29550e82..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory_impl.cc
+++ /dev/null
@@ -1,37 +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/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory_impl.h"
-#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h"
-
-namespace blink {
-
-std::unique_ptr<quic::QuicCryptoClientStream>
-P2PQuicCryptoStreamFactoryImpl::CreateClientCryptoStream(
-    quic::QuicSession* session,
-    quic::QuicCryptoClientConfig* crypto_config,
-    quic::QuicCryptoClientStream::ProofHandler* proof_handler) {
-  // The QuicServerId is not important since we are communicating with a peer
-  // endpoint and the connection is on top of ICE.
-  quic::QuicServerId server_id(
-      /*host=*/"",
-      /*port=*/0,
-      /*privacy_mode_enabled=*/false);
-  return std::make_unique<quic::QuicCryptoClientStream>(
-      server_id, session,
-      crypto_config->proof_verifier()->CreateDefaultContext(), crypto_config,
-      proof_handler, /*has_application_state = */ true);
-}
-
-std::unique_ptr<quic::QuicCryptoServerStreamBase>
-P2PQuicCryptoStreamFactoryImpl::CreateServerCryptoStream(
-    const quic::QuicCryptoServerConfig* crypto_config,
-    quic::QuicCompressedCertsCache* compressed_certs_cache,
-    quic::QuicSession* session,
-    quic::QuicCryptoServerStreamBase::Helper* helper) {
-  return quic::CreateCryptoServerStream(crypto_config, compressed_certs_cache,
-                                        session, helper);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory_impl.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory_impl.h
deleted file mode 100644
index e5ef3fa..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory_impl.h
+++ /dev/null
@@ -1,36 +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_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_STREAM_FACTORY_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_STREAM_FACTORY_IMPL_H_
-
-#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory.h"
-
-namespace blink {
-
-// The default factory for creating crypto streams to be used by the
-// P2PQuicTransport.
-class MODULES_EXPORT P2PQuicCryptoStreamFactoryImpl final
-    : public P2PQuicCryptoStreamFactory {
- public:
-  ~P2PQuicCryptoStreamFactoryImpl() override {}
-
-  // P2PQuicCryptoStreamFactory overrides.
-  std::unique_ptr<quic::QuicCryptoClientStream> CreateClientCryptoStream(
-      quic::QuicSession* session,
-      quic::QuicCryptoClientConfig* crypto_config,
-      quic::QuicCryptoClientStream::ProofHandler* proof_handler) override;
-
-  std::unique_ptr<quic::QuicCryptoServerStreamBase> CreateServerCryptoStream(
-      const quic::QuicCryptoServerConfig* crypto_config,
-      quic::QuicCompressedCertsCache* compressed_certs_cache,
-      quic::QuicSession* session,
-      quic::QuicCryptoServerStreamBase::Helper* helper) override;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_CRYPTO_STREAM_FACTORY_IMPL_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h
deleted file mode 100644
index 9157ce8..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h
+++ /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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_PACKET_TRANSPORT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_PACKET_TRANSPORT_H_
-
-#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
-
-namespace blink {
-
-// This is the interface for the underlying packet transport used by the
-// P2PQuicTransport for receiving and writing data. The standard
-// implementation of this interface uses an ICE transport.
-//
-// This object should be run entirely on the webrtc worker thread.
-class P2PQuicPacketTransport {
- public:
-  // This is subclassed by the P2PQuicTransport so that it can receive incoming
-  // data. The standard case is for this to be the P2PQuicTransport.
-  // The P2PQuicPacketTransport will outlive the ReceiveDelegate.
-  class ReceiveDelegate {
-   public:
-    virtual ~ReceiveDelegate() = default;
-    virtual void OnPacketDataReceived(const char* data, size_t data_len) = 0;
-  };
-
-  // This is subclassed by the Writer, so that it is aware when the
-  // P2PQuicPacketTransport is ready to write data. The
-  // P2PQuicPacketTransport will outlive the WriteObserver.
-  class WriteObserver {
-   public:
-    virtual ~WriteObserver() = default;
-    virtual void OnCanWrite() = 0;
-  };
-
-  struct QuicPacket {
-    // This is taken from the quic::QuicConnection, and 0 means that it is not
-    // set. Packet numbers are used to provide metadata to the implementation of
-    // the P2PQuicPacketTransport, but this number is not used by the QUIC
-    // library itself.
-    uint64_t packet_number;
-    const char* buffer;
-    size_t buf_len;
-  };
-
-  virtual ~P2PQuicPacketTransport() = default;
-
-  // Called by the P2PQuicPacketWriter (in quic_transport_factory_impl.cc) when
-  // writing QUIC packets to the network. Return the number of written bytes.
-  // Return 0 if the write is blocked.
-  virtual int WritePacket(const QuicPacket& packet) = 0;
-  // Sets the ReceiveDelegate for receiving packets.
-  // Since the ReceiveDelegate has a shorter lifetime than the
-  // P2PQuicPacketTransport, it must unset itself upon destruction.
-  virtual void SetReceiveDelegate(ReceiveDelegate* receive_delegate) = 0;
-  // Sets the WriteObserver for obsererving when it can write to the
-  // P2PQuicPacketTransport. Since the WriteObserver has a shorter lifetime than
-  // the P2PQuicPacketTransport, it must unset itself upon destruction.
-  virtual void SetWriteObserver(WriteObserver* write_observer) = 0;
-  // Returns true if the P2PQuicPacketTransport can write.
-  virtual bool Writable() = 0;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_PACKET_TRANSPORT_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h
deleted file mode 100644
index c3ce1dfe..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h
+++ /dev/null
@@ -1,87 +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_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_H_
-
-#include <stdint.h>
-
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-// The bidirectional QUIC stream object to be used by the RTCQuicStream Web
-// API. See: https://w3c.github.io/webrtc-quic/#quicstream*
-//
-// Lifetime: The P2PQuicStream is owned by the P2PQuicTransport, and can be
-// deleted after the stream is closed for reading and writing. This can happen
-// in 3 ways: 1) OnRemoteReset has been fired. 2) Calling Reset(). 3) Both
-// a FIN bit has been sent with WriteData(_, true) and OnRemoteFinish has been
-// fired.
-class P2PQuicStream {
- public:
-  // Receives callbacks for receiving RST_STREAM frames or a STREAM_FRAME with
-  // the FIN bit set. The Delegate should be subclassed by an object that can
-  // post the task to the main JS thread. The delegate's lifetime should outlive
-  // this P2PQuicStream.
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
-
-    // Called when the stream receives a RST_STREAM frame from the remote side.
-    // This means the stream is closed and can no longer read or write, and is
-    // deleted by the quic::QuicSession.
-    virtual void OnRemoteReset() {}
-
-    // Called when the P2PQuicStream has received data from the remote side.
-    // If |fin| is set to true that means that the FIN bit has been received
-    // and the Delegate will no longer receive data with OnDataReceived.
-    // If the stream has already finished writing, then upon receiving the FIN
-    // bit the stream can no longer read or write and is deleted by the
-    // quic::QuicSession.
-    virtual void OnDataReceived(Vector<uint8_t> data, bool fin) {}
-
-    // Called when data written with WriteData() has been consumed by QUIC.
-    //
-    // This will happen immediately after calling WriteData(), unless QUIC has
-    // buffered the data in which case it will be fired when the stream is no
-    // longer write blocked and the data is consumed. |amount| specifies how
-    // much data was consumed in bytes.
-    virtual void OnWriteDataConsumed(uint32_t amount) {}
-  };
-
-  virtual ~P2PQuicStream() = default;
-
-  // Sends a RST_STREAM frame to the remote side. This closes the P2PQuicStream
-  // for reading & writing and it will be deleted by the quic::QuicSession. When
-  // the remote side receives the RST_STREAM frame it will close the stream for
-  // reading and writing and send a RST_STREAM frame back. Calling Reset() will
-  // not trigger OnRemoteReset to be called locally when the RST_STREAM frame is
-  // received from the remote side, because the local stream is already closed.
-  virtual void Reset() = 0;
-
-  // Marks received data of size |amount| as being consumed by the Delegate.
-  // This is used in conjuction with Delegate::OnDataReceived, to let the
-  // P2PQuicStream know that received data has been consumed. This allows the
-  // P2PQuicStream to send back pressure to the send side, if the Delegate
-  // cannot receive more data.
-  virtual void MarkReceivedDataConsumed(uint32_t amount) = 0;
-
-  // Writes |data| to a STREAM frame and gives it to QUIC to be buffered or sent
-  // to the remote endpoint. Once that data has been sent Delegate::OnDataSent()
-  // will be fired. Specifying |fin| to true will mark the STREAM frame with the
-  // FIN bit set, which notifies the remote side that this stream is done
-  // writing. After sending the FIN bit, the P2PQuicStream can no longer write.
-  // Once the P2PQuicStream has sent AND received the FIN bit it will be closed
-  // for reading and writing and deleted by the quic::QuicSession.
-  virtual void WriteData(Vector<uint8_t> data, bool fin) = 0;
-
-  // Sets the delegate object. In the case that the Delegate does not outlive
-  // the P2PQuicStream object, it must unset itself before destructing.
-  virtual void SetDelegate(Delegate* delegate) = 0;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc
deleted file mode 100644
index 4f234cb..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.cc
+++ /dev/null
@@ -1,168 +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/modules/peerconnection/adapters/p2p_quic_stream_impl.h"
-
-#include <utility>
-#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
-#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
-
-namespace blink {
-
-P2PQuicStreamImpl::P2PQuicStreamImpl(quic::QuicStreamId id,
-                                     quic::QuicSession* session,
-                                     uint32_t delegate_read_buffer_size,
-                                     uint32_t write_buffer_size)
-    : quic::QuicStream(id, session, /*is_static=*/false, quic::BIDIRECTIONAL),
-      delegate_read_buffer_size_(delegate_read_buffer_size),
-      write_buffer_size_(write_buffer_size) {
-  DCHECK_GT(delegate_read_buffer_size_, 0u);
-  DCHECK_GT(write_buffer_size_, 0u);
-}
-
-P2PQuicStreamImpl::P2PQuicStreamImpl(quic::PendingStream* pending,
-                                     quic::QuicSession* session,
-                                     uint32_t delegate_read_buffer_size,
-                                     uint32_t write_buffer_size)
-    : quic::QuicStream(pending,
-                       session,
-                       quic::BIDIRECTIONAL,
-                       /*is_static=*/false),
-      delegate_read_buffer_size_(delegate_read_buffer_size),
-      write_buffer_size_(write_buffer_size) {
-  DCHECK_GT(delegate_read_buffer_size_, 0u);
-  DCHECK_GT(write_buffer_size_, 0u);
-}
-
-P2PQuicStreamImpl::~P2PQuicStreamImpl() {}
-
-void P2PQuicStreamImpl::OnDataAvailable() {
-  if (!sequencer()->HasBytesToRead() && sequencer()->IsClosed()) {
-    // We have consumed all data from the sequencer up to the FIN bit. This can
-    // only occur by receiving an empty STREAM frame with the FIN bit set.
-    quic::QuicStream::OnFinRead();
-    consumed_fin_ = true;
-    if (delegate_) {
-      delegate_->OnDataReceived({}, /*fin=*/true);
-    }
-  }
-
-  uint32_t delegate_read_buffer_available =
-      delegate_read_buffer_size_ - delegate_read_buffered_amount_;
-  uint32_t total_read_amount =
-      std::min(static_cast<uint32_t>(sequencer()->ReadableBytes()),
-               delegate_read_buffer_available);
-  // Nothing to do if the delegate's read buffer can't fit anymore data,
-  // or the sequencer doesn't have any data available to be read.
-  if (total_read_amount == 0 || consumed_fin_) {
-    return;
-  }
-  Vector<uint8_t> data(total_read_amount);
-  uint32_t current_data_offset = 0;
-  struct iovec iov;
-
-  // Read data from the quic::QuicStreamSequencer until we have exhausted the
-  // data, or have read at least the amount of the delegate's read buffer size.
-  while (sequencer()->GetReadableRegion(&iov)) {
-    uint32_t read_amount = static_cast<uint32_t>(iov.iov_len);
-    if (read_amount == 0) {
-      // Read everything available from the quic::QuicStreamSequencer.
-      DCHECK_EQ(current_data_offset, total_read_amount);
-      break;
-    }
-    // Limit the |consume_amount| by the amount available in the delegate's read
-    // buffer.
-    uint32_t consume_amount = std::min(
-        read_amount, delegate_read_buffer_available - current_data_offset);
-    memcpy(data.data() + current_data_offset, iov.iov_base, consume_amount);
-    sequencer()->MarkConsumed(consume_amount);
-    current_data_offset += consume_amount;
-    if (read_amount > consume_amount) {
-      // The delegate cannot store more data in its read buffer.
-      DCHECK_EQ(current_data_offset, total_read_amount);
-      break;
-    }
-  }
-
-  bool fin = !sequencer()->HasBytesToRead() && sequencer()->IsClosed();
-  delegate_read_buffered_amount_ += data.size();
-  DCHECK(delegate_read_buffer_size_ >= delegate_read_buffered_amount_);
-  if (fin) {
-    quic::QuicStream::OnFinRead();
-    consumed_fin_ = fin;
-  }
-  if (delegate_) {
-    delegate_->OnDataReceived(std::move(data), fin);
-  }
-}
-
-void P2PQuicStreamImpl::OnStreamDataConsumed(
-    quic::QuicByteCount bytes_consumed) {
-  // We should never consume more than has been written.
-  DCHECK_GE(write_buffered_amount_, bytes_consumed);
-  QuicStream::OnStreamDataConsumed(bytes_consumed);
-  if (bytes_consumed > 0) {
-    write_buffered_amount_ -= bytes_consumed;
-    if (delegate_) {
-      delegate_->OnWriteDataConsumed(SafeCast<uint32_t>(bytes_consumed));
-    }
-  }
-}
-
-void P2PQuicStreamImpl::Reset() {
-  if (rst_sent()) {
-    // No need to reset twice. This could have already been sent as consequence
-    // of receiving a RST_STREAM frame.
-    return;
-  }
-  quic::QuicStream::Reset(quic::QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED);
-}
-
-void P2PQuicStreamImpl::MarkReceivedDataConsumed(uint32_t amount) {
-  DCHECK_GE(delegate_read_buffered_amount_, amount);
-  delegate_read_buffered_amount_ -= amount;
-  if (sequencer()->HasBytesToRead() || !consumed_fin_) {
-    OnDataAvailable();
-  }
-}
-
-void P2PQuicStreamImpl::WriteData(Vector<uint8_t> data, bool fin) {
-  // It is up to the delegate to not write more data than the
-  // |write_buffer_size_|.
-  DCHECK_GE(write_buffer_size_, data.size() + write_buffered_amount_);
-  write_buffered_amount_ += data.size();
-  QuicStream::WriteOrBufferData(
-      quiche::QuicheStringPiece(reinterpret_cast<const char*>(data.data()),
-                                data.size()),
-      fin, nullptr);
-}
-
-void P2PQuicStreamImpl::SetDelegate(P2PQuicStream::Delegate* delegate) {
-  delegate_ = delegate;
-}
-
-void P2PQuicStreamImpl::OnStreamReset(const quic::QuicRstStreamFrame& frame) {
-  // Calling this on the QuicStream will ensure that the stream is closed
-  // for reading and writing and we send a RST frame to the remote side if
-  // we have not already.
-  quic::QuicStream::OnStreamReset(frame);
-  if (delegate_) {
-    delegate_->OnRemoteReset();
-  }
-}
-
-void P2PQuicStreamImpl::OnClose() {
-  closed_ = true;
-  quic::QuicStream::OnClose();
-}
-
-bool P2PQuicStreamImpl::IsClosedForTesting() {
-  return closed_;
-}
-
-uint32_t P2PQuicStreamImpl::DelegateReadBufferedAmountForTesting() {
-  return delegate_read_buffered_amount_;
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h
deleted file mode 100644
index d5a8e98..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h
+++ /dev/null
@@ -1,102 +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_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_IMPL_H_
-
-#include "net/third_party/quiche/src/quic/core/quic_session.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h"
-
-namespace blink {
-
-class MODULES_EXPORT P2PQuicStreamImpl final : public quic::QuicStream,
-                                               public P2PQuicStream {
- public:
-  P2PQuicStreamImpl(quic::QuicStreamId id,
-                    quic::QuicSession* session,
-                    uint32_t delegate_read_buffer_size,
-                    uint32_t write_buffer_size);
-  P2PQuicStreamImpl(quic::PendingStream* pending,
-                    quic::QuicSession* session,
-                    uint32_t delegate_read_buffer_size,
-                    uint32_t write_buffer_size);
-  ~P2PQuicStreamImpl() override;
-  // P2PQuicStream overrides
-  void SetDelegate(P2PQuicStream::Delegate* delegate) override;
-
-  void Reset() override;
-
-  void WriteData(Vector<uint8_t> data, bool fin) override;
-
-  void MarkReceivedDataConsumed(uint32_t amount) override;
-
-  // For testing purposes. This is returns true after quic::QuicStream::OnClose
-  bool IsClosedForTesting();
-
-  // For testing purposes. This exposes the amount of received data that the
-  // P2PQuicStream is aware is buffered by the delegate.
-  uint32_t DelegateReadBufferedAmountForTesting();
-
-  // quic::QuicStream overrides.
-  //
-  // Right now this marks the data as consumed and drops it.
-  // TODO(https://crbug.com/874296): We need to update this function for
-  // reading and consuming data properly while the main JavaScript thread is
-  // busy. See:
-  // https://w3c.github.io/webrtc-quic/#dom-rtcquicstream-waitforreadable
-  void OnDataAvailable() override;
-  // Called by the quic::QuicSession when receiving a RST_STREAM frame from the
-  // remote side. This closes the stream for reading & writing (if not already
-  // closed), and sends a RST_STREAM frame if one has not been sent yet.
-  void OnStreamReset(const quic::QuicRstStreamFrame& frame) override;
-  //  Called by the quic::QuicSession. This means the stream is closed for
-  //  reading
-  // and writing, and can now be deleted by the quic::QuicSession.
-  void OnClose() override;
-
- protected:
-  // quic::QuicStream overrides.
-  //
-  // Called when written data (from WriteData()) is consumed by QUIC. This means
-  // the data has either been sent across the wire, or it has been turned into a
-  // packet and queued if the socket is unexpectedly blocked.
-  void OnStreamDataConsumed(quic::QuicByteCount bytes_consumed) override;
-
- private:
-  using quic::QuicStream::Reset;
-
-  // Must either outlive the P2PQuicStream or unset itself upon destruction.
-  Delegate* delegate_;
-
-  // The read buffer size of the delegate. The |delegate_read_buffered_amount_|
-  // must never exceed this value (enforced by the P2PQuicStreamImpl).
-  const uint32_t delegate_read_buffer_size_;
-  // The maximum size allowed to be buffered write side. The
-  // |write_buffered_amount_| must never exceed this value, and it is up
-  // to the delegate to enforce this.
-  const uint32_t write_buffer_size_;
-  // How much total data has been received and given to the delegate,
-  // but not yet consumed by the delegate. This value gets increased when data
-  // is received from the QUIC library in OnDataAvailable() and and decreased
-  // when the delegate updates that data has been read with
-  // MarkReceivedDataConsumed().
-  uint32_t delegate_read_buffered_amount_ = 0;
-  // How much data is buffered by the QUIC library, but has not yet
-  // been sent. This value gets increased when WriteData() is called
-  // and decreased when OnDataConsumed() gets called by the QUIC library,
-  // due to the data being sent.
-  uint32_t write_buffered_amount_ = 0;
-
-  // Set after OnClose gets called.
-  bool closed_ = false;
-
-  // This is set after the sequencer is closed due to the P2PQuicStream
-  // consuming all of the sequencer's data up to the FIN bit.
-  bool consumed_fin_ = false;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_STREAM_IMPL_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc
deleted file mode 100644
index 844c5bb..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_unittest.cc
+++ /dev/null
@@ -1,566 +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/modules/peerconnection/adapters/p2p_quic_stream.h"
-#include "net/test/gtest_util.h"
-#include "net/third_party/quiche/src/quic/core/quic_data_writer.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream_delegate.h"
-
-namespace blink {
-
-namespace {
-
-using testing::_;
-using testing::ElementsAre;
-using testing::ElementsAreArray;
-using testing::Invoke;
-using testing::InvokeWithoutArgs;
-
-const uint32_t kDefaultStreamWriteBufferSize = 1024;
-const uint32_t kDefaultStreamDelegateReadBufferSize = 1024;
-const quic::QuicStreamId kStreamId = 5;
-const uint8_t kSomeData[] = {'h', 'o', 'w', 'd', 'y'};
-const uint8_t kMoreData[] = {'m', 'o', 'r', 'e'};
-
-}  // namespace
-
-// Unit tests for the P2PQuicStream, using a mock QuicSession, which allows
-// us to isolate testing the behaviors of reading a writing.
-class P2PQuicStreamTest : public testing::Test {
- public:
-  P2PQuicStreamTest() {
-    // TODO(crbug/1070747): Fix tests for IETF QUIC.
-    quic::test::DisableQuicVersionsWithTls();
-    connection_ = new quic::test::MockQuicConnection(
-        &connection_helper_, &alarm_factory_, quic::Perspective::IS_CLIENT);
-    session_ = std::make_unique<quic::test::MockQuicSession>(connection_);
-    session_->Initialize();
-    // DCHECKS get hit when the clock is at 0.
-    connection_helper_.AdvanceTime(quic::QuicTime::Delta::FromSeconds(1));
-  }
-
-  ~P2PQuicStreamTest() override {}
-
-  void InitializeStream(
-      uint32_t delegate_read_buffer_size = kDefaultStreamDelegateReadBufferSize,
-      uint32_t write_buffer_size = kDefaultStreamWriteBufferSize) {
-    stream_ =
-        new P2PQuicStreamImpl(kStreamId, session_.get(),
-                              delegate_read_buffer_size, write_buffer_size);
-    stream_->SetDelegate(&delegate_);
-    // The session takes the ownership of the stream.
-    session_->ActivateStream(std::unique_ptr<P2PQuicStreamImpl>(stream_));
-  }
-
-  template <wtf_size_t Size>
-  static quiche::QuicheStringPiece StringPieceFromArray(
-      const uint8_t (&array)[Size]) {
-    return quiche::QuicheStringPiece(reinterpret_cast<const char*>(array),
-                                     Size);
-  }
-
-  template <wtf_size_t Size>
-  static Vector<uint8_t> VectorFromArray(const uint8_t (&array)[Size]) {
-    Vector<uint8_t> vector;
-    vector.Append(array, Size);
-    return vector;
-  }
-
-  quic::test::MockQuicConnectionHelper connection_helper_;
-  quic::test::MockAlarmFactory alarm_factory_;
-  // Owned by the |session_|.
-  quic::test::MockQuicConnection* connection_;
-  // The MockQuicSession allows us to see data that is being written and control
-  // whether the data is being "sent across" or blocked.
-  std::unique_ptr<quic::test::MockQuicSession> session_;
-  MockP2PQuicStreamDelegate delegate_;
-  // Owned by |session_|.
-  P2PQuicStreamImpl* stream_;
-};
-
-TEST_F(P2PQuicStreamTest, StreamSendsFinAndCanNoLongerWrite) {
-  InitializeStream();
-  EXPECT_CALL(*session_,
-              WritevData(kStreamId, 0u, 0u, quic::StreamSendingState::FIN,
-                         quic::NOT_RETRANSMISSION, _))
-      .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 0u, 0u,
-                                     quic::StreamSendingState::FIN,
-                                     quic::NOT_RETRANSMISSION, QUICHE_NULLOPT);
-      }));
-
-  stream_->WriteData({}, /*fin=*/true);
-
-  EXPECT_TRUE(stream_->fin_sent());
-  EXPECT_TRUE(stream_->write_side_closed());
-  EXPECT_FALSE(stream_->reading_stopped());
-}
-
-TEST_F(P2PQuicStreamTest, StreamResetSendsRst) {
-  InitializeStream();
-  EXPECT_CALL(*session_, SendRstStream(kStreamId, _, _, _));
-  stream_->Reset();
-  EXPECT_TRUE(stream_->rst_sent());
-}
-
-// Tests that when a stream receives a stream frame with the FIN bit set it
-// will fire the appropriate callback and close the stream for reading.
-TEST_F(P2PQuicStreamTest, StreamOnStreamFrameWithFin) {
-  InitializeStream();
-  EXPECT_CALL(delegate_, OnDataReceived(_, /*fin=*/true));
-
-  quic::QuicStreamFrame fin_frame(kStreamId, /*fin=*/true, 0, 0);
-  stream_->OnStreamFrame(fin_frame);
-
-  EXPECT_TRUE(stream_->reading_stopped());
-  EXPECT_FALSE(stream_->write_side_closed());
-}
-
-// Tests that when a stream receives a stream frame with the FIN bit set after
-// it has written the FIN bit, then the stream will close.
-TEST_F(P2PQuicStreamTest, StreamClosedAfterSendingThenReceivingFin) {
-  InitializeStream();
-  EXPECT_CALL(*session_,
-              WritevData(kStreamId, 0u, 0u, _, quic::NOT_RETRANSMISSION, _))
-      .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 0u, 0u,
-                                     quic::StreamSendingState::FIN,
-                                     quic::NOT_RETRANSMISSION, QUICHE_NULLOPT);
-      }));
-
-  stream_->WriteData({}, /*fin=*/true);
-  EXPECT_FALSE(stream_->IsClosedForTesting());
-
-  quic::QuicStreamFrame fin_frame(stream_->id(), /*fin=*/true, 0, 0);
-  stream_->OnStreamFrame(fin_frame);
-
-  EXPECT_TRUE(stream_->reading_stopped());
-  EXPECT_TRUE(stream_->write_side_closed());
-  EXPECT_TRUE(stream_->IsClosedForTesting());
-}
-
-// Tests that when a stream writes a FIN bit after receiving a stream frame with
-// the FIN bit then the stream will close.
-TEST_F(P2PQuicStreamTest, StreamClosedAfterReceivingThenSendingFin) {
-  InitializeStream();
-  quic::QuicStreamFrame fin_frame(stream_->id(), /*fin=*/true, 0, 0);
-  stream_->OnStreamFrame(fin_frame);
-  EXPECT_FALSE(stream_->IsClosedForTesting());
-
-  EXPECT_CALL(*session_,
-              WritevData(kStreamId, 0u, 0u, quic::StreamSendingState::FIN,
-                         quic::NOT_RETRANSMISSION, _))
-      .WillOnce(InvokeWithoutArgs([this]() {
-        return session_->ConsumeData(stream_->id(), 0u, 0u,
-                                     quic::StreamSendingState::FIN,
-                                     quic::NOT_RETRANSMISSION, QUICHE_NULLOPT);
-      }));
-
-  stream_->WriteData({}, /*fin=*/true);
-
-  EXPECT_TRUE(stream_->IsClosedForTesting());
-}
-
-// Tests that when a stream writes some data with the FIN bit set, and receives
-// data with the FIN bit set it will become closed.
-TEST_F(P2PQuicStreamTest, StreamClosedAfterWritingAndReceivingDataWithFin) {
-  InitializeStream();
-  EXPECT_CALL(*session_,
-              WritevData(kStreamId,
-                         /*write_length=*/base::size(kSomeData), _, _, _, _))
-      .WillOnce(Invoke(
-          [this](quic::QuicStreamId id, size_t write_length,
-                 quic::QuicStreamOffset offset, quic::StreamSendingState state,
-                 quic::TransmissionType type,
-                 quiche::QuicheOptional<quic::EncryptionLevel> level) {
-            // WritevData does not pass the data. The data is saved to the
-            // stream, so we must grab it before it's consumed, in order to
-            // check that it's what was written.
-            std::string data_consumed_by_quic(write_length, 'a');
-            quic::QuicDataWriter writer(write_length, &data_consumed_by_quic[0],
-                                        quiche::NETWORK_BYTE_ORDER);
-            stream_->WriteStreamData(offset, write_length, &writer);
-
-            EXPECT_THAT(data_consumed_by_quic, ElementsAreArray(kSomeData));
-            EXPECT_EQ(quic::StreamSendingState::FIN, state);
-            return quic::QuicConsumedData(
-                write_length, state != quic::StreamSendingState::NO_FIN);
-          }));
-
-  stream_->WriteData(VectorFromArray(kSomeData),
-                     /*fin=*/true);
-  EXPECT_FALSE(stream_->IsClosedForTesting());
-
-  quic::QuicStreamFrame fin_frame_with_data(stream_->id(), /*fin=*/true, 0,
-                                            StringPieceFromArray(kSomeData));
-  stream_->OnStreamFrame(fin_frame_with_data);
-
-  EXPECT_TRUE(stream_->reading_stopped());
-  EXPECT_TRUE(stream_->write_side_closed());
-  EXPECT_TRUE(stream_->IsClosedForTesting());
-}
-
-// Tests that when a stream receives a RST_STREAM frame it will fire the
-// appropriate callback and the stream will become closed.
-TEST_F(P2PQuicStreamTest, StreamClosedAfterReceivingReset) {
-  InitializeStream();
-  EXPECT_CALL(delegate_, OnRemoteReset());
-
-  quic::QuicRstStreamFrame rst_frame(quic::kInvalidControlFrameId, kStreamId,
-                                     quic::QUIC_STREAM_CANCELLED, 0);
-  if (!VersionHasIetfQuicFrames(connection_->version().transport_version)) {
-    // Google RST_STREAM closes the stream in both directions. A RST_STREAM
-    // is then sent to the peer to communicate the final byte offset.
-    EXPECT_CALL(*session_,
-                SendRstStream(kStreamId, quic::QUIC_RST_ACKNOWLEDGEMENT, 0, _));
-  }
-  stream_->OnStreamReset(rst_frame);
-  if (VersionHasIetfQuicFrames(connection_->version().transport_version)) {
-    // In IETF QUIC, the RST_STREAM only closes the stream in one direction.
-    // A STOP_SENDING frame in require to induce the a RST_STREAM being
-    // send to close the other direction.
-    EXPECT_CALL(*connection_, SendControlFrame(_));
-    EXPECT_CALL(*connection_, OnStreamReset(kStreamId, testing::_));
-    quic::QuicStopSendingFrame stop_sending_frame(
-        quic::kInvalidControlFrameId, kStreamId, quic::QUIC_STREAM_NO_ERROR);
-    session_->OnStopSendingFrame(stop_sending_frame);
-  }
-
-  EXPECT_TRUE(stream_->IsClosedForTesting());
-}
-
-// Tests that data written to the P2PQuicStream will appropriately get written
-// to the underlying QUIC library.
-TEST_F(P2PQuicStreamTest, StreamWritesData) {
-  InitializeStream();
-  EXPECT_CALL(*session_,
-              WritevData(kStreamId,
-                         /*write_length=*/base::size(kSomeData), _, _, _, _))
-      .WillOnce(Invoke(
-          [this](quic::QuicStreamId id, size_t write_length,
-                 quic::QuicStreamOffset offset, quic::StreamSendingState state,
-                 quic::TransmissionType type,
-                 quiche::QuicheOptional<quic::EncryptionLevel> level) {
-            // quic::QuicSession::WritevData does not pass the data. The data is
-            // saved to the stream, so we must grab it before it's consumed, in
-            // order to check that it's what was written.
-            std::string data_consumed_by_quic(write_length, 'a');
-            quic::QuicDataWriter writer(write_length, &data_consumed_by_quic[0],
-                                        quiche::NETWORK_BYTE_ORDER);
-            stream_->WriteStreamData(offset, write_length, &writer);
-
-            EXPECT_THAT(data_consumed_by_quic, ElementsAreArray(kSomeData));
-            EXPECT_EQ(quic::StreamSendingState::NO_FIN, state);
-            return quic::QuicConsumedData(
-                write_length, state != quic::StreamSendingState::NO_FIN);
-          }));
-  EXPECT_CALL(delegate_, OnWriteDataConsumed(base::size(kSomeData)));
-
-  stream_->WriteData(VectorFromArray(kSomeData), /*fin=*/false);
-}
-
-// Tests that data written to the P2PQuicStream will appropriately get written
-// to the underlying QUIC library with the FIN bit set.
-TEST_F(P2PQuicStreamTest, StreamWritesDataWithFin) {
-  InitializeStream();
-  EXPECT_CALL(*session_,
-              WritevData(kStreamId,
-                         /*write_length=*/base::size(kSomeData), _, _, _, _))
-      .WillOnce(Invoke(
-          [this](quic::QuicStreamId id, size_t write_length,
-                 quic::QuicStreamOffset offset, quic::StreamSendingState state,
-                 quic::TransmissionType type,
-                 quiche::QuicheOptional<quic::EncryptionLevel> level) {
-            // WritevData does not pass the data. The data is saved to the
-            // stream, so we must grab it before it's consumed, in order to
-            // check that it's what was written.
-            std::string data_consumed_by_quic(write_length, 'a');
-            quic::QuicDataWriter writer(write_length, &data_consumed_by_quic[0],
-                                        quiche::NETWORK_BYTE_ORDER);
-            stream_->WriteStreamData(offset, write_length, &writer);
-
-            EXPECT_THAT(data_consumed_by_quic, ElementsAreArray(kSomeData));
-            EXPECT_EQ(quic::StreamSendingState::FIN, state);
-            return quic::QuicConsumedData(
-                write_length, state != quic::StreamSendingState::NO_FIN);
-          }));
-  EXPECT_CALL(delegate_, OnWriteDataConsumed(base::size(kSomeData)));
-
-  stream_->WriteData(VectorFromArray(kSomeData), /*fin=*/true);
-}
-
-// Tests that when written data is not consumed by QUIC (due to buffering),
-// the OnWriteDataConsumed will not get fired.
-TEST_F(P2PQuicStreamTest, StreamWritesDataAndNotConsumedByQuic) {
-  InitializeStream();
-  EXPECT_CALL(delegate_, OnWriteDataConsumed(_)).Times(0);
-  EXPECT_CALL(*session_,
-              WritevData(kStreamId,
-                         /*write_length=*/base::size(kSomeData), _, _, _, _))
-      .WillOnce(Invoke([](quic::QuicStreamId id, size_t write_length,
-                          quic::QuicStreamOffset offset,
-                          quic::StreamSendingState state,
-                          quic::TransmissionType type,
-                          quiche::QuicheOptional<quic::EncryptionLevel> level) {
-        // We mock that the QUIC library is not consuming the data, meaning it's
-        // being buffered. In this case, the OnWriteDataConsumed() callback
-        // should not be called.
-        return quic::QuicConsumedData(/*bytes_consumed=*/0,
-                                      quic::StreamSendingState::NO_FIN);
-      }));
-
-  stream_->WriteData(VectorFromArray(kSomeData), /*fin=*/true);
-}
-
-// Tests that OnWriteDataConsumed() is fired with the amount consumed by QUIC.
-// This tests the case when amount consumed by QUIC is less than what is written
-// with P2PQuicStream::WriteData. This can happen when QUIC is receiving back
-// pressure from the receive side, and its "send window" is smaller than the
-// amount attempted to be written.
-TEST_F(P2PQuicStreamTest, StreamWritesDataAndPartiallyConsumedByQuic) {
-  InitializeStream();
-  size_t amount_consumed_by_quic = 2;
-  EXPECT_CALL(delegate_, OnWriteDataConsumed(amount_consumed_by_quic));
-  EXPECT_CALL(*session_,
-              WritevData(kStreamId,
-                         /*write_length=*/base::size(kSomeData), _, _, _, _))
-      .WillOnce(Invoke(
-          [&amount_consumed_by_quic](
-              quic::QuicStreamId id, size_t write_length,
-              quic::QuicStreamOffset offset, quic::StreamSendingState state,
-              quic::TransmissionType type,
-              quiche::QuicheOptional<quic::EncryptionLevel> level) {
-            // We mock that the QUIC library is only consuming some of the data,
-            // meaning the rest is being buffered.
-            return quic::QuicConsumedData(
-                /*bytes_consumed=*/amount_consumed_by_quic,
-                quic::StreamSendingState::NO_FIN);
-          }));
-
-  stream_->WriteData(VectorFromArray(kSomeData), /*fin=*/true);
-}
-
-// Tests if a P2PQuicStream receives data it will appropriately fire the
-// OnDataReceived callback to the delegate.
-TEST_F(P2PQuicStreamTest, StreamReceivesData) {
-  InitializeStream();
-  quic::QuicStreamFrame stream_frame(stream_->id(), /*fin=*/false, 0,
-                                     StringPieceFromArray(kSomeData));
-
-  EXPECT_CALL(delegate_, OnDataReceived(VectorFromArray(kSomeData),
-                                        /*fin=*/false));
-
-  stream_->OnStreamFrame(stream_frame);
-}
-
-// Tests that when received data is marked consumed it is appropriately
-// reflected in the P2PQuicStream's view of the delegate read buffer size.
-TEST_F(P2PQuicStreamTest, MarkConsumedData) {
-  InitializeStream();
-  quic::QuicStreamFrame stream_frame(stream_->id(), /*fin=*/false, 0,
-                                     StringPieceFromArray(kSomeData));
-
-  EXPECT_CALL(delegate_, OnDataReceived(_, _));
-  stream_->OnStreamFrame(stream_frame);
-  // At this point the application has received data but not marked is as
-  // consumed, so from the P2PQuicStream perspective that data has been
-  // buffered.
-  EXPECT_EQ(base::size(kSomeData),
-            stream_->DelegateReadBufferedAmountForTesting());
-
-  stream_->MarkReceivedDataConsumed(base::size(kSomeData));
-  EXPECT_EQ(0u, stream_->DelegateReadBufferedAmountForTesting());
-}
-
-// Tests that if the delegate's read buffer is "full" from the
-// P2PQuicStream's perspective, then getting more data will not fire the
-// OnDataReceived callback.
-TEST_F(P2PQuicStreamTest, StreamReceivesDataWithFullReadBuffer) {
-  // The P2PQuicStream is created with a delegate read buffer size equal
-  // to the size of the data that is being received.
-  InitializeStream(/*delegate_read_buffer_size=*/base::size(kSomeData));
-  quic::QuicStreamFrame stream_frame(stream_->id(), /*fin=*/false, 0,
-                                     StringPieceFromArray(kSomeData));
-
-  EXPECT_CALL(delegate_, OnDataReceived(_, _)).Times(1);
-  stream_->OnStreamFrame(stream_frame);
-  EXPECT_EQ(base::size(kSomeData),
-            stream_->DelegateReadBufferedAmountForTesting());
-
-  // Delegate read buffer is now full. Receiving more data should not fire the
-  // callback.
-  quic::QuicStreamFrame new_stream_frame(stream_->id(), /*fin=*/false,
-                                         /*offset=*/base::size(kSomeData),
-                                         StringPieceFromArray(kMoreData));
-  stream_->OnStreamFrame(new_stream_frame);
-  EXPECT_EQ(base::size(kSomeData),
-            stream_->DelegateReadBufferedAmountForTesting());
-}
-
-// Tests that if the delegate's read buffer is "full" from the
-// P2PQuicStream's perspective, and then getting an empty STREAM frame with the
-// FIN bit set, will fire Delegate::OnDataReceived with fin set to true.
-TEST_F(P2PQuicStreamTest, StreamReceivesFinWithFullReadBuffer) {
-  // The P2PQuicStream is created with a delegate read buffer size equal
-  // to the size of the data that is being received.
-  InitializeStream(/*delegate_read_buffer_size=*/base::size(kSomeData));
-  quic::QuicStreamFrame stream_frame(stream_->id(), /*fin=*/false, 0,
-                                     StringPieceFromArray(kSomeData));
-
-  EXPECT_CALL(delegate_, OnDataReceived(ElementsAreArray(kSomeData),
-                                        /*fin=*/false))
-      .Times(1);
-  stream_->OnStreamFrame(stream_frame);
-  EXPECT_EQ(base::size(kSomeData),
-            stream_->DelegateReadBufferedAmountForTesting());
-
-  // Delegate read buffer is now full, but because the STREAM frame with the FIN
-  // bit doesn't contain any data, it means that all data has been consumed from
-  // the sequencer up to the FIN bit. This fires OnDataReceived with the
-  // fin=true.
-  EXPECT_CALL(delegate_, OnDataReceived(_, true)).Times(1);
-  quic::QuicStreamFrame new_stream_frame(stream_->id(), /*fin=*/true,
-                                         /*offset=*/base::size(kSomeData), 0);
-  stream_->OnStreamFrame(new_stream_frame);
-  EXPECT_EQ(base::size(kSomeData),
-            stream_->DelegateReadBufferedAmountForTesting());
-}
-
-// Tests that when the delegate's read buffer is "full" from the
-// P2PQuicStream's perspective, the Delegate::OnDataReceived callback is
-// fired after the received data is marked as consumed by the delegate.
-TEST_F(P2PQuicStreamTest, StreamDataConsumedWithFullDelegateReadBuffer) {
-  // The P2PQuicStream is created with a delegate read buffer size equal
-  // to the size of the data that is being received.
-  InitializeStream(/*delegate_read_buffer_size=*/base::size(kSomeData));
-  quic::QuicStreamFrame stream_frame(stream_->id(), /*fin=*/false, 0,
-                                     StringPieceFromArray(kSomeData));
-
-  EXPECT_CALL(delegate_, OnDataReceived(ElementsAreArray(kSomeData),
-                                        /*fin=*/false))
-      .Times(1);
-  stream_->OnStreamFrame(stream_frame);
-  EXPECT_EQ(base::size(kSomeData),
-            stream_->DelegateReadBufferedAmountForTesting());
-
-  // Delegate read buffer is now full. Receiving more data should not fire the
-  // callback.
-  quic::QuicStreamFrame new_stream_frame(stream_->id(), /*fin=*/true,
-                                         /*offset=*/base::size(kSomeData),
-                                         StringPieceFromArray(kMoreData));
-  stream_->OnStreamFrame(new_stream_frame);
-  EXPECT_EQ(base::size(kSomeData),
-            stream_->DelegateReadBufferedAmountForTesting());
-
-  // Marking the original data as consumed should fire the new data to be
-  // received.
-  EXPECT_CALL(delegate_, OnDataReceived(ElementsAreArray(kMoreData),
-                                        /*fin=*/true))
-      .Times(1);
-  stream_->MarkReceivedDataConsumed(base::size(kSomeData));
-  EXPECT_EQ(base::size(kMoreData),
-            stream_->DelegateReadBufferedAmountForTesting());
-}
-
-// Tests that when receiving more data than available in the delegate read
-// buffer, that the delegate will get an OnDataReceived callback for the amount
-// available in its buffer. Then later when the delegate marks the data as
-// consumed it will get another OnDataReceived callback.
-TEST_F(P2PQuicStreamTest, StreamReceivesMoreDataThanDelegateReadBufferSize) {
-  const uint8_t kData[] = {'s', 'o', 'm', 'e', 'd', 'a', 't', 'a'};
-  // The P2PQuicStream is created with a delegate read buffer size equal
-  // to half of the data being sent.
-  InitializeStream(/*delegate_read_buffer_size=*/4);
-  quic::QuicStreamFrame stream_frame(stream_->id(), /*fin=*/true, 0,
-                                     StringPieceFromArray(kData));
-
-  // Upon receiving the stream frame the Delegate should receive "some", because
-  // that's all it has space to buffer.
-  EXPECT_CALL(delegate_, OnDataReceived(ElementsAre('s', 'o', 'm', 'e'),
-                                        /*fin=*/false))
-      .Times(1);
-  stream_->OnStreamFrame(stream_frame);
-  EXPECT_EQ(4u, stream_->DelegateReadBufferedAmountForTesting());
-
-  // Upon consuming 2 bytes of data, the delegate should receive the next part
-  // of the message - "da".
-  EXPECT_CALL(delegate_, OnDataReceived(ElementsAre('d', 'a'), /*fin=*/false))
-      .Times(1);
-  stream_->MarkReceivedDataConsumed(2);
-  EXPECT_EQ(4u, stream_->DelegateReadBufferedAmountForTesting());
-
-  // After consuming 4 bytes of data (all received data thus far), the delegate
-  // should receive the next part of the message - "ta" and the FIN bit.
-  EXPECT_CALL(delegate_, OnDataReceived(ElementsAre('t', 'a'), /*fin=*/true))
-      .Times(1);
-  stream_->MarkReceivedDataConsumed(4);
-  // Just the last data received ("ta") is held in the delegate's read buffer.
-  EXPECT_EQ(2u, stream_->DelegateReadBufferedAmountForTesting());
-}
-
-// Tests that after a delegate unsets itself, it will no longer receive the
-// OnWriteDataConsumed callback.
-TEST_F(P2PQuicStreamTest, UnsetDelegateDoesNotFireOnWriteDataConsumed) {
-  InitializeStream();
-  stream_->SetDelegate(nullptr);
-  // Mock out the QuicSession to get the QuicStream::OnStreamDataConsumed
-  // callback to fire.
-  EXPECT_CALL(*session_,
-              WritevData(kStreamId,
-                         /*write_length=*/base::size(kSomeData), _, _, _, _))
-      .WillOnce(Invoke([](quic::QuicStreamId id, size_t write_length,
-                          quic::QuicStreamOffset offset,
-                          quic::StreamSendingState state,
-                          quic::TransmissionType type,
-                          quiche::QuicheOptional<quic::EncryptionLevel> level) {
-        return quic::QuicConsumedData(
-            write_length, state != quic::StreamSendingState::NO_FIN);
-      }));
-
-  EXPECT_CALL(delegate_, OnWriteDataConsumed(_)).Times(0);
-
-  stream_->WriteData(VectorFromArray(kSomeData), /*fin=*/false);
-}
-
-// Tests that after a delegate unsets itself, it will no longer receive the
-// OnRemoteReset callback.
-TEST_F(P2PQuicStreamTest, UnsetDelegateDoesNotFireOnRemoteReset) {
-  InitializeStream();
-  stream_->SetDelegate(nullptr);
-  EXPECT_CALL(delegate_, OnRemoteReset()).Times(0);
-
-  quic::QuicRstStreamFrame rst_frame(quic::kInvalidControlFrameId, kStreamId,
-                                     quic::QUIC_STREAM_CANCELLED, 0);
-  stream_->OnStreamReset(rst_frame);
-}
-
-// Tests that after a delegate unsets itself, it will no longer receive the
-// OnDataReceived callback when receiving a stream frame with data and no FIN
-// bit.
-TEST_F(P2PQuicStreamTest, UnsetDelegateDoesNotFireOnDataReceivedWithData) {
-  InitializeStream();
-  stream_->SetDelegate(nullptr);
-
-  EXPECT_CALL(delegate_, OnDataReceived(_, _)).Times(0);
-
-  quic::QuicStreamFrame stream_frame(stream_->id(), /*fin=*/false, 0,
-                                     StringPieceFromArray(kSomeData));
-  stream_->OnStreamFrame(stream_frame);
-}
-
-// Tests that after a delegate unsets itself, it will no longer receive the
-// OnDataReceived callback when receiving a stream frame with the FIN bit.
-TEST_F(P2PQuicStreamTest, UnsetDelegateDoesNotFireOnDataReceivedWithFin) {
-  InitializeStream();
-  stream_->SetDelegate(nullptr);
-
-  EXPECT_CALL(delegate_, OnDataReceived(_, _)).Times(0);
-
-  quic::QuicStreamFrame stream_frame(stream_->id(), /*fin=*/true, 0, {});
-  stream_->OnStreamFrame(stream_frame);
-}
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h
deleted file mode 100644
index a93498d..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h
+++ /dev/null
@@ -1,142 +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_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_H_
-
-#include "base/check_op.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-#include "third_party/webrtc/rtc_base/ssl_fingerprint.h"
-
-namespace blink {
-
-class P2PQuicStream;
-
-// Includes any relevant parameters that were negotiated in the QUIC handshake.
-// Used in the P2PQuicTransport::Delegate::OnConnected callback.
-struct P2PQuicNegotiatedParams final {
-  // If datagrams were negotiated to be supported.
-  bool datagrams_supported() const { return max_datagram_length_.has_value(); }
-
-  void set_max_datagram_length(uint16_t max_datagram_length) {
-    DCHECK_GT(max_datagram_length, 0);
-    max_datagram_length_ = max_datagram_length;
-  }
-
-  uint16_t max_datagram_length() const {
-    DCHECK(datagrams_supported());
-    return max_datagram_length_.value_or(0);
-  }
-
- private:
-  // According to draft-pauly-quic-datagram-02#section-3, this should be
-  // negotiated as a transport parameter, although in the QUICHE implementation
-  // it is based upon the QUIC version (determines packet header size) and
-  // default max packet size (1350 bytes).
-  base::Optional<uint16_t> max_datagram_length_;
-};
-
-// Used by the RTCQuicTransport Web API. This transport creates and manages
-// streams, handles negotiation, state changes and errors. Every
-// P2PQuicTransport function maps directly to a method in the RTCQuicTransport
-// Web API, i.e. RTCQuicTransport::stop() -->
-// P2PQuicTransport::Stop(). This allows posting just one task across
-// thread boundaries to execute a function.
-//
-// This object should be run entirely on the webrtc worker thread.
-class P2PQuicTransport {
-  USING_FAST_MALLOC(P2PQuicTransport);
-
- public:
-  // A config used when starting the QUIC handshake.
-  struct StartConfig final {
-    explicit StartConfig(
-        Vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints_in)
-        : remote_fingerprints(std::move(remote_fingerprints_in)) {
-      DCHECK_GT(remote_fingerprints.size(), 0u);
-    }
-
-    explicit StartConfig(const std::string pre_shared_key_in)
-        : pre_shared_key(pre_shared_key_in) {
-      DCHECK(!pre_shared_key.empty());
-    }
-
-    // These fingerprints are used to verify the self signed remote certificate
-    // used in the QUIC handshake. See:
-    // https://w3c.github.io/webrtc-quic/#quic-transport*
-    Vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints;
-
-    // The pre shared key to be used in the handshake.
-    const std::string pre_shared_key;
-  };
-
-  // Used for receiving callbacks from the P2PQuicTransport regarding QUIC
-  // connection changes, handshake success/failures and new QuicStreams being
-  // added from the remote side.
-  class Delegate {
-   public:
-    virtual ~Delegate() = default;
-    // Called when receiving a close frame from the remote side, due to
-    // calling P2PQuicTransport::Stop().
-    virtual void OnRemoteStopped() {}
-    // Called when the connection is closed due to a QUIC error. This can happen
-    // locally by the framer, or remotely by the peer.
-    virtual void OnConnectionFailed(const std::string& error_details,
-                                    bool from_remote) {}
-    // Called when the crypto handshake has completed and fingerprints have been
-    // verified.
-    virtual void OnConnected(P2PQuicNegotiatedParams negotiated_params) {}
-
-    // Called when the datagram has been consumed by the QUIC library and sent
-    // on the network.
-    virtual void OnDatagramSent() {}
-
-    // Called when we receive a datagram from the remote side.
-    virtual void OnDatagramReceived(Vector<uint8_t> datagram) {}
-
-    // Called when an incoming stream is received from the remote side. This
-    // stream is owned by the P2PQuicTransport. Its lifetime is managed by the
-    // P2PQuicTransport, and can be deleted when:
-    // - The P2PQuicStream becomes closed for reading and writing.
-    // - Stop() is called.
-    // - The P2PQuicTransport is deleted.
-    virtual void OnStream(P2PQuicStream* stream) {}
-  };
-
-  virtual ~P2PQuicTransport() = default;
-
-  // Closes the QuicConnection and sends a close frame to the remote side.
-  // This will trigger P2PQuicTransport::Delegate::OnRemoteClosed() on the
-  // remote side. This must not be called before Start().
-  virtual void Stop() = 0;
-
-  // Starts the QUIC handshake negotiation. If this is a client perspective
-  // this means initiating the QUIC handshake with a CHLO, while for
-  // a server perspective this means now listening and responding to a CHLO.
-  virtual void Start(StartConfig config) = 0;
-
-  // Creates a new outgoing stream. This stream is owned by the
-  // P2PQuicTransport. Its lifetime is managed by the P2PQuicTransport,
-  // and can be deleted when:
-  // - The P2PQuicStream becomes closed for reading and writing.
-  // - Stop() is called.
-  // - The P2PQuicTransport is deleted.
-  virtual P2PQuicStream* CreateStream() = 0;
-
-  // Gets the associated stats. These are QUIC connection level stats.
-  virtual P2PQuicTransportStats GetStats() const = 0;
-
-  // Sends datagram. If the QUIC connection is write blocked due to congestion
-  // control the message will be buffered and sent once it is unblocked. Once
-  // the datagram has been sent, Delegate::OnDatagramSent will be called.
-  virtual void SendDatagram(Vector<uint8_t> datagram) = 0;
-
-  // TODO(https://crbug.com/874296): Consider adding a getter for the
-  // local fingerprints of the certificate(s) set in the constructor.
-};
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h
deleted file mode 100644
index 7c65328b..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h
+++ /dev/null
@@ -1,75 +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_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_H_
-
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/webrtc/api/scoped_refptr.h"
-#include "third_party/webrtc/rtc_base/rtc_certificate.h"
-
-namespace blink {
-
-// A simple config object for creating a P2PQuicTransport. Its constructor
-// guarantees that the required configuration for creating a P2PQuicTransport
-// are part of the P2PQuicTransportConfig.
-struct P2PQuicTransportConfig final {
-  // This object is only moveable.
-  explicit P2PQuicTransportConfig(
-      quic::Perspective perspective,
-      const Vector<rtc::scoped_refptr<rtc::RTCCertificate>> certificates_in,
-      uint32_t stream_delegate_read_buffer_size_in,
-      uint32_t stream_write_buffer_size_in)
-      : perspective(perspective),
-        certificates(certificates_in),
-        stream_delegate_read_buffer_size(stream_delegate_read_buffer_size_in),
-        stream_write_buffer_size(stream_write_buffer_size_in) {
-    DCHECK_GT(stream_delegate_read_buffer_size, 0u);
-    DCHECK_GT(stream_write_buffer_size, 0u);
-  }
-
-  // Client or server.
-  quic::Perspective perspective;
-  // The certificates are owned by the P2PQuicTransport. These come from
-  // blink::RTCCertificates: https://www.w3.org/TR/webrtc/#dom-rtccertificate
-  // This can be empty if pre shared keys are being used to establish a
-  // connection.
-  const Vector<rtc::scoped_refptr<rtc::RTCCertificate>> certificates;
-  // The amount that the delegate can store in its read buffer. This is a
-  // mandatory field that must be set to ensure that the
-  // P2PQuicStream::Delegate will not give the delegate more data than it can
-  // store.
-  const uint32_t stream_delegate_read_buffer_size;
-  // The amount that the P2PQuicStream will allow to buffer. This is a mandatory
-  // field that must be set to ensure that the client of the P2PQuicStream does
-  // not write more data than can be buffered.
-  const uint32_t stream_write_buffer_size;
-};
-
-// For creating a P2PQuicTransport. This factory should be injected into
-// whichever object plans to own and use a P2PQuicTransport. The
-// P2PQuicTransportFactory needs to outlive the P2PQuicTransport it creates.
-//
-// This object should be run entirely on the webrtc worker thread.
-class P2PQuicTransportFactory {
- public:
-  virtual ~P2PQuicTransportFactory() = default;
-
-  // Creates the P2PQuicTransport. This should be called on the same
-  // thread that the P2PQuicTransport will be used on.
-  // |delegate| receives callbacks from the P2PQuicTransport on the same thread.
-  //     It must outlive the P2PQuicTransport.
-  // |packet_transport| is used to send and receive UDP packets. It must outlive
-  //     the P2PQuicTransport.
-  virtual std::unique_ptr<P2PQuicTransport> CreateQuicTransport(
-      P2PQuicTransport::Delegate* delegate,
-      P2PQuicPacketTransport* packet_transport,
-      const P2PQuicTransportConfig& config) = 0;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc
deleted file mode 100644
index 6954e02..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc
+++ /dev/null
@@ -1,41 +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/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h"
-#include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
-#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h"
-#include "third_party/webrtc/rtc_base/rtc_certificate.h"
-
-namespace blink {
-
-P2PQuicTransportFactoryImpl::P2PQuicTransportFactoryImpl(
-    quic::QuicClock* clock,
-    std::unique_ptr<quic::QuicAlarmFactory> alarm_factory)
-    : clock_(clock), alarm_factory_(std::move(alarm_factory)) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-// The P2PQuicTransportImpl is created with Chromium specific QUIC objects:
-// QuicClock, QuicRandom, QuicConnectionHelper and QuicAlarmFactory.
-std::unique_ptr<P2PQuicTransport>
-P2PQuicTransportFactoryImpl::CreateQuicTransport(
-    P2PQuicTransport::Delegate* delegate,
-    P2PQuicPacketTransport* packet_transport,
-    const P2PQuicTransportConfig& config) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(delegate);
-  DCHECK(packet_transport);
-
-  quic::QuicRandom* quic_random = quic::QuicRandom::GetInstance();
-  return P2PQuicTransportImpl::Create(
-      clock_, alarm_factory_.get(), quic_random, delegate, packet_transport,
-      std::move(config),
-      std::make_unique<P2PQuicCryptoConfigFactoryImpl>(quic_random),
-      std::make_unique<P2PQuicCryptoStreamFactoryImpl>());
-}
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h
deleted file mode 100644
index ec9fcc7c..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h
+++ /dev/null
@@ -1,45 +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_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_IMPL_H_
-
-#include "net/third_party/quiche/src/quic/core/quic_connection.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h"
-
-namespace blink {
-
-// For creating a P2PQuicTransportImpl to be used for the blink Web API -
-// RTCQuicTransport.
-//
-// This object should be run entirely on the webrtc worker thread.
-class MODULES_EXPORT P2PQuicTransportFactoryImpl final
-    : public P2PQuicTransportFactory {
- public:
-  P2PQuicTransportFactoryImpl(
-      quic::QuicClock* clock,
-      std::unique_ptr<quic::QuicAlarmFactory> alarm_factory);
-  ~P2PQuicTransportFactoryImpl() override {}
-
-  // QuicTransportFactoryInterface override.
-  std::unique_ptr<P2PQuicTransport> CreateQuicTransport(
-      P2PQuicTransport::Delegate* delegate,
-      P2PQuicPacketTransport* packet_transport,
-      const P2PQuicTransportConfig& config) override;
-
- private:
-  // This is used to create a QuicChromiumConnectionHelper for the session.
-  // Should outlive the P2PQuicTransportFactoryImpl.
-  quic::QuicClock* clock_;
-  // Used for alarms that drive the underlying QUIC library. Should use the same
-  // clock as |clock_|.
-  std::unique_ptr<quic::QuicAlarmFactory> alarm_factory_;
-  THREAD_CHECKER(thread_checker_);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_FACTORY_IMPL_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc
deleted file mode 100644
index 54053d6a..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.cc
+++ /dev/null
@@ -1,620 +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/modules/peerconnection/adapters/p2p_quic_transport_impl.h"
-
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
-#include "net/third_party/quiche/src/quic/core/quic_config.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
-#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h"
-#include "net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h"
-
-namespace blink {
-
-namespace {
-
-static const char kClosingDetails[] = "Application closed connection.";
-
-// QUIC's default is 100. Setting this value to 10000 allows room for QUIC to
-// not refuse new incoming streams in the case that an application wants to send
-// a small chunk of data per stream (and immediately close) unreliably.
-uint32_t kMaxIncomingDynamicStreams = 10000;
-
-// The P2PQuicPacketWriter is a private helper class that implements the
-// QuicPacketWriter using a P2PQuicPacketTransport. This allows us to
-// connect our own packet transport for writing into the QuicConnection.
-// The normal case is using an ICE transport (packet_transport) for writing.
-class P2PQuicPacketWriter : public quic::QuicPacketWriter,
-                            public P2PQuicPacketTransport::WriteObserver {
- public:
-  P2PQuicPacketWriter(P2PQuicPacketTransport* packet_transport)
-      : packet_transport_(packet_transport) {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK(packet_transport_);
-    packet_transport_->SetWriteObserver(this);
-  }
-
-  // This way the packet transport knows it no longer has a write observer and
-  // can DCHECK this on destruction.
-  ~P2PQuicPacketWriter() override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    packet_transport_->SetWriteObserver(nullptr);
-  }
-
-  // Sets the QuicConnection (which owns this packet writer). This allows us
-  // to get the packet numbers of QUIC packets we write. The QuicConnection
-  // is created with a quic::QuicPacketWriter, so we can't set the connection
-  // in the constructor.
-  void InitializeWithQuicConnection(quic::QuicConnection* connection) {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK(connection);
-    if (packet_transport_->Writable()) {
-      SetWritable();
-    }
-    connection_ = connection;
-  }
-
-  // quic::QuicPacketWriter overrides.
-
-  // Writes a QUIC packet to the network with the packet number as additional
-  // packet  info.
-  quic::WriteResult WritePacket(const char* buffer,
-                                size_t buf_len,
-                                const quic::QuicIpAddress& self_address,
-                                const quic::QuicSocketAddress& peer_address,
-                                quic::PerPacketOptions* options) override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK(connection_);
-    if (IsWriteBlocked()) {
-      return quic::WriteResult(quic::WRITE_STATUS_BLOCKED, EWOULDBLOCK);
-    }
-
-    P2PQuicPacketTransport::QuicPacket packet;
-    packet.packet_number =
-        connection_->packet_creator().packet_number().ToUint64();
-    packet.buffer = buffer;
-    packet.buf_len = buf_len;
-    int bytes_written = packet_transport_->WritePacket(packet);
-    if (bytes_written <= 0) {
-      writable_ = false;
-      return quic::WriteResult(quic::WRITE_STATUS_BLOCKED, EWOULDBLOCK);
-    }
-    return quic::WriteResult(quic::WRITE_STATUS_OK, bytes_written);
-  }
-
-  bool IsWriteBlocked() const override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    return !writable_;
-  }
-
-  quic::QuicByteCount GetMaxPacketSize(
-      const quic::QuicSocketAddress& peer_address) const override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    // This can be configured later.
-    return 1200;
-  }
-
-  void SetWritable() override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    writable_ = true;
-  }
-
-  bool SupportsReleaseTime() const override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    return false;
-  }
-
-  bool IsBatchMode() const override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    return false;
-  }
-
-  quic::QuicPacketBuffer GetNextWriteLocation(
-      const quic::QuicIpAddress& self_address,
-      const quic::QuicSocketAddress& peer_address) override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    return {nullptr, nullptr};
-  }
-
-  quic::WriteResult Flush() override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    return quic::WriteResult(quic::WRITE_STATUS_OK, 0);
-  }
-
-  // P2PQuicPacketTransport::WriteDelegate override.
-  void OnCanWrite() override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    SetWritable();
-    connection_->OnCanWrite();
-  }
-
- private:
-  // The packet transport is owned by the P2PQuicSession, not the
-  // BlinkPacketWriter.
-  P2PQuicPacketTransport* packet_transport_;
-  // The QuicConnection owns this packet writer and will outlive it.
-  quic::QuicConnection* connection_;
-
-  bool writable_ = false;
-  THREAD_CHECKER(thread_checker_);
-};
-
-// Creates the QuicConnection for the QuicSession. Currently this connection
-// uses a dummy address and ID. The |packet_writer| is a basic implementation
-// using the QuicTransportConfig::packet_transport for writing. The |helper|
-// and |alarm_factory| should be chromium specific implementations.
-std::unique_ptr<quic::QuicConnection> CreateQuicConnection(
-    quic::Perspective perspective,
-    quic::QuicConnectionHelperInterface* helper,
-    quic::QuicPacketWriter* packet_writer,
-    quic::QuicAlarmFactory* alarm_factory) {
-  quic::QuicIpAddress ip;
-  ip.FromString("0.0.0.0");
-  quic::QuicSocketAddress dummy_address(ip, 0 /* Port */);
-  quic::QuicConnectionId dummy_connection_id;
-  char connection_id_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
-  dummy_connection_id =
-      quic::QuicConnectionId(connection_id_bytes, sizeof(connection_id_bytes));
-  return std::make_unique<quic::QuicConnection>(
-      dummy_connection_id, quic::QuicSocketAddress(), dummy_address, helper,
-      alarm_factory, packet_writer, /* owns_writer */ true, perspective,
-      quic::ParsedQuicVersionVector{quic::CurrentSupportedVersions()[0]});
-}
-
-// A dummy helper for a server crypto stream that accepts all client hellos
-// and generates a random connection ID.
-class DummyCryptoServerStreamHelper
-    : public quic::QuicCryptoServerStreamBase::Helper {
- public:
-  explicit DummyCryptoServerStreamHelper(quic::QuicRandom* random) {}
-
-  ~DummyCryptoServerStreamHelper() override {}
-
-  bool CanAcceptClientHello(const quic::CryptoHandshakeMessage& message,
-                            const quic::QuicSocketAddress& client_address,
-                            const quic::QuicSocketAddress& peer_address,
-                            const quic::QuicSocketAddress& self_address,
-                            std::string* error_details) const override {
-    return true;
-  }
-};
-}  // namespace
-
-std::unique_ptr<P2PQuicTransportImpl> P2PQuicTransportImpl::Create(
-    quic::QuicClock* clock,
-    quic::QuicAlarmFactory* alarm_factory,
-    quic::QuicRandom* quic_random,
-    P2PQuicTransport::Delegate* delegate,
-    P2PQuicPacketTransport* packet_transport,
-    const P2PQuicTransportConfig& config,
-    std::unique_ptr<P2PQuicCryptoConfigFactory> crypto_config_factory,
-    std::unique_ptr<P2PQuicCryptoStreamFactory> crypto_stream_factory) {
-  DCHECK(delegate);
-  DCHECK(packet_transport);
-  DCHECK(crypto_config_factory);
-  DCHECK(crypto_stream_factory);
-
-  // The P2PQuicSession owns these chromium specific objects required
-  // by the QuicConnection. These outlive the QuicConnection itself.
-  std::unique_ptr<net::QuicChromiumConnectionHelper> helper =
-      std::make_unique<net::QuicChromiumConnectionHelper>(clock, quic_random);
-
-  P2PQuicPacketWriter* packet_writer =
-      new P2PQuicPacketWriter(packet_transport);
-  std::unique_ptr<quic::QuicConnection> quic_connection = CreateQuicConnection(
-      config.perspective, helper.get(), packet_writer, alarm_factory);
-  // It's okay for the quic::QuicConnection to have a P2PQuicPacketWriter before
-  // the P2PQuicPacketWriter is initialized, because the P2QuicPacketWriter
-  // won't be writable until this occurs.
-  packet_writer->InitializeWithQuicConnection(quic_connection.get());
-
-  // QUIC configurations for the session are specified here.
-  // TODO(shampson): Consider setting larger initial flow control window sizes
-  // so that the default limit doesn't cause initial undersending.
-  quic::QuicConfig quic_config;
-  quic_config.SetMaxBidirectionalStreamsToSend(kMaxIncomingDynamicStreams);
-  quic_config.SetMaxUnidirectionalStreamsToSend(kMaxIncomingDynamicStreams);
-  // The handshake network timeouts are configured to large values to prevent
-  // the QUIC connection from being closed on a slow connection. This can occur
-  // if signaling is slow and one side begins the handshake early.
-  // See ICE related bug: bugs.webrtc.org/9869.
-  //
-  // This timeout is from time of creation of the quic::QuicConnection object to
-  // the completion of the handshake. It must be larger than the idle time.
-  quic_config.set_max_time_before_crypto_handshake(
-      quic::QuicTime::Delta::FromSeconds(50));
-  // This is the timeout for idle time in the handshake. This value allows
-  // time for slow signaling to complete.
-  quic_config.set_max_idle_time_before_crypto_handshake(
-      quic::QuicTime::Delta::FromSeconds(30));
-  return std::make_unique<P2PQuicTransportImpl>(
-      delegate, packet_transport, std::move(config), std::move(helper),
-      std::move(quic_connection), quic_config, std::move(crypto_config_factory),
-      std::move(crypto_stream_factory), clock);
-}
-
-P2PQuicTransportImpl::P2PQuicTransportImpl(
-    Delegate* delegate,
-    P2PQuicPacketTransport* packet_transport,
-    const P2PQuicTransportConfig& p2p_transport_config,
-    std::unique_ptr<quic::QuicConnectionHelperInterface> helper,
-    std::unique_ptr<quic::QuicConnection> connection,
-    const quic::QuicConfig& quic_config,
-    std::unique_ptr<P2PQuicCryptoConfigFactory> crypto_config_factory,
-    std::unique_ptr<P2PQuicCryptoStreamFactory> crypto_stream_factory,
-    quic::QuicClock* clock)
-    : quic::QuicSession(connection.get(),
-                        nullptr /* visitor */,
-                        quic_config,
-                        quic::CurrentSupportedVersions(),
-                        /*expected_num_static_unidirectional_streams = */ 0),
-      helper_(std::move(helper)),
-      connection_(std::move(connection)),
-      crypto_config_factory_(std::move(crypto_config_factory)),
-      crypto_stream_factory_(std::move(crypto_stream_factory)),
-      perspective_(p2p_transport_config.perspective),
-      packet_transport_(packet_transport),
-      delegate_(delegate),
-      clock_(clock),
-      stream_delegate_read_buffer_size_(
-          p2p_transport_config.stream_delegate_read_buffer_size),
-      stream_write_buffer_size_(p2p_transport_config.stream_write_buffer_size) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(delegate_);
-  DCHECK(crypto_config_factory_);
-  DCHECK(crypto_stream_factory_);
-  DCHECK(clock_);
-  DCHECK(packet_transport_);
-  DCHECK_GT(stream_delegate_read_buffer_size_, 0u);
-  DCHECK_GT(stream_write_buffer_size_, 0u);
-  if (!p2p_transport_config.certificates.IsEmpty()) {
-    // TODO(https://crbug.com/874296): The web API accepts multiple
-    // certificates, and we might want to pass these down to let QUIC decide on
-    // what to use.
-    certificate_ = p2p_transport_config.certificates[0];
-  }
-  switch (perspective_) {
-    case quic::Perspective::IS_CLIENT: {
-      crypto_client_config_ =
-          crypto_config_factory_->CreateClientCryptoConfig();
-      break;
-    }
-    case quic::Perspective::IS_SERVER: {
-      crypto_server_config_ =
-          crypto_config_factory_->CreateServerCryptoConfig();
-      break;
-    }
-    default:
-      NOTREACHED();
-      break;
-  }
-}
-
-P2PQuicTransportImpl::~P2PQuicTransportImpl() {
-  packet_transport_->SetReceiveDelegate(nullptr);
-}
-
-void P2PQuicTransportImpl::Stop() {
-  // This shouldn't be called before Start().
-  DCHECK(crypto_stream_);
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (IsClosed()) {
-    return;
-  }
-  // The error code used for the connection closing is
-  // quic::QUIC_CONNECTION_CANCELLED. This allows us to distinguish that the
-  // application closed the connection, as opposed to it closing from a
-  // failure/error.
-  connection_->CloseConnection(
-      quic::QuicErrorCode::QUIC_CONNECTION_CANCELLED, kClosingDetails,
-      quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-}
-
-void P2PQuicTransportImpl::Start(StartConfig config) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // Either the remote fingerprints are being verified or a pre shared key is
-  // set.
-  DCHECK((certificate_ && !config.remote_fingerprints.IsEmpty()) ||
-         !config.pre_shared_key.empty());
-  DCHECK(!crypto_stream_);
-
-  remote_fingerprints_ = std::move(config.remote_fingerprints);
-  switch (perspective_) {
-    case quic::Perspective::IS_CLIENT: {
-      crypto_client_config_->set_pre_shared_key(config.pre_shared_key);
-      break;
-    }
-    case quic::Perspective::IS_SERVER: {
-      crypto_server_config_->set_pre_shared_key(config.pre_shared_key);
-      break;
-    }
-    default:
-      NOTREACHED();
-      break;
-  }
-
-  InitializeCryptoStream();
-
-  if (perspective_ == quic::Perspective::IS_CLIENT) {
-    quic::QuicCryptoClientStream* client_crypto_stream =
-        static_cast<quic::QuicCryptoClientStream*>(crypto_stream_.get());
-    client_crypto_stream->CryptoConnect();
-  }
-  // Now that crypto streams are setup we are ready to receive QUIC packets.
-  packet_transport_->SetReceiveDelegate(this);
-}
-
-void P2PQuicTransportImpl::OnPacketDataReceived(const char* data,
-                                                size_t data_len) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // Received data from the |packet_transport_|. Create a QUIC packet and send
-  // it to be processed by the QuicSession/Connection.
-  quic::QuicReceivedPacket packet(data, data_len, clock_->Now());
-  ProcessUdpPacket(connection()->self_address(), connection()->peer_address(),
-                   packet);
-}
-
-quic::QuicCryptoStream* P2PQuicTransportImpl::GetMutableCryptoStream() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return crypto_stream_.get();
-}
-
-const quic::QuicCryptoStream* P2PQuicTransportImpl::GetCryptoStream() const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return crypto_stream_.get();
-}
-
-P2PQuicStreamImpl* P2PQuicTransportImpl::CreateStream() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return CreateOutgoingBidirectionalStream();
-}
-
-P2PQuicTransportStats P2PQuicTransportImpl::GetStats() const {
-  P2PQuicTransportStats stats(connection_->GetStats());
-  stats.num_incoming_streams_created = num_incoming_streams_created_;
-  stats.num_outgoing_streams_created = num_outgoing_streams_created_;
-  stats.num_datagrams_lost = num_datagrams_lost_;
-  return stats;
-}
-
-void P2PQuicTransportImpl::SendDatagram(Vector<uint8_t> datagram) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(CanSendDatagram());
-  DCHECK_LT(datagram.size(),
-            quic::QuicSession::GetCurrentLargestMessagePayload());
-
-  if (!datagram_buffer_.empty()) {
-    // We are currently write blocked, just add to the buffer.
-    datagram_buffer_.push(std::move(datagram));
-    return;
-  }
-  if (!TrySendDatagram(datagram)) {
-    datagram_buffer_.push(std::move(datagram));
-  }
-}
-
-bool P2PQuicTransportImpl::CanSendDatagram() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return IsEncryptionEstablished() &&
-         (connection()->version().SupportsMessageFrames()) && !IsClosed();
-}
-
-P2PQuicStreamImpl* P2PQuicTransportImpl::CreateOutgoingBidirectionalStream() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  num_outgoing_streams_created_++;
-  P2PQuicStreamImpl* stream =
-      CreateStreamInternal(GetNextOutgoingBidirectionalStreamId());
-  ActivateStream(std::unique_ptr<P2PQuicStreamImpl>(stream));
-  return stream;
-}
-
-P2PQuicStreamImpl* P2PQuicTransportImpl::CreateIncomingStream(
-    quic::QuicStreamId id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  num_incoming_streams_created_++;
-  P2PQuicStreamImpl* stream = CreateStreamInternal(id);
-  ActivateStream(std::unique_ptr<P2PQuicStreamImpl>(stream));
-  delegate_->OnStream(stream);
-  return stream;
-}
-
-P2PQuicStreamImpl* P2PQuicTransportImpl::CreateIncomingStream(
-    quic::PendingStream* pending) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  num_incoming_streams_created_++;
-  P2PQuicStreamImpl* stream = CreateStreamInternal(pending);
-  ActivateStream(std::unique_ptr<P2PQuicStreamImpl>(stream));
-  delegate_->OnStream(stream);
-  return stream;
-}
-
-P2PQuicStreamImpl* P2PQuicTransportImpl::CreateStreamInternal(
-    quic::QuicStreamId id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(crypto_stream_);
-  DCHECK(IsEncryptionEstablished());
-  DCHECK(!IsClosed());
-  return new P2PQuicStreamImpl(id, this, stream_delegate_read_buffer_size_,
-                               stream_write_buffer_size_);
-}
-
-P2PQuicStreamImpl* P2PQuicTransportImpl::CreateStreamInternal(
-    quic::PendingStream* pending) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(crypto_stream_);
-  DCHECK(IsEncryptionEstablished());
-  DCHECK(!IsClosed());
-  return new P2PQuicStreamImpl(pending, this, stream_delegate_read_buffer_size_,
-                               stream_write_buffer_size_);
-}
-
-bool P2PQuicTransportImpl::TrySendDatagram(Vector<uint8_t>& datagram) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(CanSendDatagram());
-  DCHECK_LT(datagram.size(),
-            quic::QuicSession::GetCurrentLargestMessagePayload());
-
-  struct iovec iov = {datagram.data(), datagram.size()};
-  quic::QuicMemSliceStorage storage(
-      &iov, 1, connection()->helper()->GetStreamSendBufferAllocator(),
-      datagram.size());
-  quic::MessageResult result = QuicSession::SendMessage(storage.ToSpan());
-  switch (result.status) {
-    case quic::MESSAGE_STATUS_BLOCKED:
-      return false;
-    case quic::MESSAGE_STATUS_SUCCESS:
-      delegate_->OnDatagramSent();
-      return true;
-    case quic::MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED:
-    case quic::MESSAGE_STATUS_INTERNAL_ERROR:
-    case quic::MESSAGE_STATUS_TOO_LARGE:
-    case quic::MESSAGE_STATUS_UNSUPPORTED:
-      break;
-  }
-  // Anything besides blocked/success should never happen.
-  LOG(ERROR) << "Unexpected result with QuicSession::SendMessage: "
-             << result.status;
-  NOTREACHED();
-  return false;
-}
-
-void P2PQuicTransportImpl::InitializeCryptoStream() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!crypto_stream_);
-  // TODO(shampson): If the P2PQuicTransportImpl is subclassed into a client
-  // and server class we can call this as a virtual function and not need this
-  // switch statement.
-  switch (perspective_) {
-    case quic::Perspective::IS_CLIENT: {
-      DCHECK(crypto_client_config_);
-      crypto_stream_ = crypto_stream_factory_->CreateClientCryptoStream(
-          /*QuicSession=*/this, crypto_client_config_.get(),
-          /*ProofHandler=*/this);
-      QuicSession::Initialize();
-      break;
-    }
-    case quic::Perspective::IS_SERVER: {
-      DCHECK(crypto_server_config_);
-      // Provide server with serialized config string to prove ownership.
-      quic::QuicCryptoServerConfig::ConfigOptions options;
-      // The |message| is used to handle the return value of AddDefaultConfig
-      // which is raw pointer of the CryptoHandshakeMessage.
-      std::unique_ptr<quic::CryptoHandshakeMessage> message(
-          crypto_server_config_->AddDefaultConfig(
-              helper_->GetRandomGenerator(), helper_->GetClock(), options));
-      compressed_certs_cache_.reset(new quic::QuicCompressedCertsCache(
-          quic::QuicCompressedCertsCache::kQuicCompressedCertsCacheSize));
-      server_stream_helper_ = std::make_unique<DummyCryptoServerStreamHelper>(
-          helper_->GetRandomGenerator());
-
-      crypto_stream_ = crypto_stream_factory_->CreateServerCryptoStream(
-          crypto_server_config_.get(), compressed_certs_cache_.get(), this,
-          server_stream_helper_.get());
-      QuicSession::Initialize();
-      break;
-    }
-    default:
-      NOTREACHED();
-      break;
-  }
-}
-
-void P2PQuicTransportImpl::SetDefaultEncryptionLevel(
-    quic::EncryptionLevel level) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  QuicSession::SetDefaultEncryptionLevel(level);
-  if (level == quic::ENCRYPTION_FORWARD_SECURE) {
-    DCHECK(IsEncryptionEstablished());
-    DCHECK(OneRttKeysAvailable());
-    P2PQuicNegotiatedParams negotiated_params;
-    // The guaranteed largest message payload will not change throughout the
-    // connection.
-    uint16_t max_datagram_length =
-        quic::QuicSession::GetGuaranteedLargestMessagePayload();
-    if (max_datagram_length > 0) {
-      // Datagrams are supported in this case.
-      negotiated_params.set_max_datagram_length(max_datagram_length);
-    }
-    delegate_->OnConnected(negotiated_params);
-  }
-}
-
-void P2PQuicTransportImpl::OnTlsHandshakeComplete() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  QuicSession::OnTlsHandshakeComplete();
-  DCHECK(IsEncryptionEstablished());
-  DCHECK(OneRttKeysAvailable());
-  P2PQuicNegotiatedParams negotiated_params;
-  // The guaranteed largest message payload will not change throughout the
-  // connection.
-  uint16_t max_datagram_length =
-      quic::QuicSession::GetGuaranteedLargestMessagePayload();
-  if (max_datagram_length > 0) {
-    // Datagrams are supported in this case.
-    negotiated_params.set_max_datagram_length(max_datagram_length);
-  }
-  delegate_->OnConnected(negotiated_params);
-}
-
-void P2PQuicTransportImpl::OnCanWrite() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  while (!datagram_buffer_.empty()) {
-    if (TrySendDatagram(datagram_buffer_.front())) {
-      datagram_buffer_.pop();
-    } else {
-      // Keep the message in the buffer to be written when we can write again.
-      return;
-    }
-  }
-
-  // We have successfully sent all buffered datagrams.
-  QuicSession::OnCanWrite();
-}
-
-void P2PQuicTransportImpl::OnMessageReceived(
-    quiche::QuicheStringPiece message) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // This will never overflow because of the datagram size limit.
-  Vector<uint8_t> datagram(static_cast<wtf_size_t>(message.size()));
-  memcpy(datagram.data(), message.data(), message.size());
-  delegate_->OnDatagramReceived(std::move(datagram));
-}
-
-void P2PQuicTransportImpl::OnMessageLost(quic::QuicMessageId message_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  num_datagrams_lost_++;
-}
-
-void P2PQuicTransportImpl::OnConnectionClosed(
-    const quic::QuicConnectionCloseFrame& frame,
-    quic::ConnectionCloseSource source) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  const quic::QuicErrorCode error = frame.quic_error_code;
-  const std::string& error_details = frame.error_details;
-  quic::QuicSession::OnConnectionClosed(frame, source);
-  if (error != quic::QuicErrorCode::QUIC_CONNECTION_CANCELLED) {
-    delegate_->OnConnectionFailed(
-        error_details, source == quic::ConnectionCloseSource::FROM_PEER);
-  } else if (source == quic::ConnectionCloseSource::FROM_PEER) {
-    // This connection was closed by the application of the remote side.
-    delegate_->OnRemoteStopped();
-  }
-}
-
-bool P2PQuicTransportImpl::ShouldKeepConnectionAlive() const {
-  return GetNumActiveStreams() > 0;
-}
-
-bool P2PQuicTransportImpl::IsClosed() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return !connection_->connected();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h
deleted file mode 100644
index 37c38e3..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h
+++ /dev/null
@@ -1,231 +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_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_IMPL_H_
-
-#include <queue>
-#include "base/threading/thread_checker.h"
-#include "net/quic/quic_chromium_connection_helper.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
-#include "net/third_party/quiche/src/quic/core/quic_connection.h"
-#include "net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h"
-#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream_base.h"
-#include "net/third_party/quiche/src/quic/core/quic_packet_writer.h"
-#include "net/third_party/quiche/src/quic/core/quic_session.h"
-#include "net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h"
-#include "third_party/webrtc/rtc_base/rtc_certificate.h"
-
-namespace blink {
-
-// The P2PQuicTransportImpl subclasses the quic::QuicSession in order to expose
-// QUIC as a P2P transport. This specific subclass implements the crypto
-// handshake for a peer to peer connection, which requires verifying the remote
-// certificate's fingerprint, but otherwise exposes a raw quic::QuicSession.
-//
-// At a high level, the quic::QuicConnection manages the actual connection
-// between two endpoints, while the quic::QuicSession owns and manages the
-// quic::QuicStreams. The quic::QuicSession also handles the negotiation between
-// endpoints, session control (reset, window updates, control frames, etc.), and
-// callbacks from either the connection (quic::QuicConnectionVisitorInterface),
-// frames being acked or lost (quic::SessionNotifierInterface), or handshake
-// state changes.
-//
-// This object should be run entirely on the webrtc worker thread.
-class MODULES_EXPORT P2PQuicTransportImpl final
-    : public quic::QuicSession,
-      public P2PQuicTransport,
-      public P2PQuicPacketTransport::ReceiveDelegate,
-      public quic::QuicCryptoClientStream::ProofHandler {
- public:
-  // Creates the necessary QUIC and Chromium specific objects before
-  // creating P2PQuicTransportImpl.
-  static std::unique_ptr<P2PQuicTransportImpl> Create(
-      quic::QuicClock* clock,
-      quic::QuicAlarmFactory* alarm_factory,
-      quic::QuicRandom* quic_random,
-      Delegate* delegate,
-      P2PQuicPacketTransport* packet_transport,
-      const P2PQuicTransportConfig& config,
-      std::unique_ptr<P2PQuicCryptoConfigFactory> crypto_config_factory,
-      std::unique_ptr<P2PQuicCryptoStreamFactory> crypto_stream_factory);
-
-  P2PQuicTransportImpl(
-      Delegate* delegate,
-      P2PQuicPacketTransport* packet_transport,
-      const P2PQuicTransportConfig& p2p_transport_config,
-      std::unique_ptr<quic::QuicConnectionHelperInterface> helper,
-      std::unique_ptr<quic::QuicConnection> connection,
-      const quic::QuicConfig& quic_config,
-      std::unique_ptr<P2PQuicCryptoConfigFactory> crypto_config_factory,
-      std::unique_ptr<P2PQuicCryptoStreamFactory> crypto_stream_factory,
-      quic::QuicClock* clock);
-
-  ~P2PQuicTransportImpl() override;
-
-  // P2PQuicTransport overrides.
-  void Stop() override;
-  // This handshake is currently insecure in the case of using remote
-  // fingerprints to verify the remote certificate. For a secure handshake, set
-  // the pre_shared_key attribute of the |config| before calling this. This
-  // function must be called before creating any streams.
-  //
-  // TODO(https://crbug.com/874300): Verify both the client and server
-  // certificates with the signaled remote fingerprints. Until the TLS 1.3
-  // handshake is supported in the QUIC core library we can only verify the
-  // server's certificate, but not the client's.
-  void Start(StartConfig config) override;
-  // Creates an outgoing stream that is owned by the quic::QuicSession.
-  P2PQuicStreamImpl* CreateStream() override;
-  P2PQuicTransportStats GetStats() const override;
-  // This should not be called until the transport has become connected, and
-  // cannot be called with a |datagram| larger than the maximum size given in
-  // GetGuaranteedLargestMessagePayload(). Once the datagram has been sent,
-  // Delegate::OnDatagramSent will be called. If Delegate::OnDatagramSent is not
-  // immediately called, it can be assumed that the datagram is buffered due to
-  // congestion control.
-  void SendDatagram(Vector<uint8_t> datagram) override;
-
-  // Returns true if a datagram can be sent on the transport.
-  bool CanSendDatagram();
-
-  // quic::QuicSession override.
-  void OnMessageReceived(quiche::QuicheStringPiece message) override;
-  void OnMessageLost(quic::QuicMessageId message_id) override;
-  void OnCanWrite() override;
-
-  // P2PQuicPacketTransport::Delegate override.
-  void OnPacketDataReceived(const char* data, size_t data_len) override;
-
-  // quic::QuicCryptoClientStream::ProofHandler overrides used in a client
-  // connection to get certificate verification details.
-
-  // Called when the proof verification completes. This information is used
-  // for 0 RTT handshakes, which isn't relevant for our P2P handshake.
-  void OnProofValid(
-      const quic::QuicCryptoClientConfig::CachedState& cached) override {}
-
-  // Called when proof verification become available.
-  void OnProofVerifyDetailsAvailable(
-      const quic::ProofVerifyDetails& verify_details) override {}
-
-  // quic::QuicConnectionVisitorInterface overrides.
-  void OnConnectionClosed(const quic::QuicConnectionCloseFrame& frame,
-                          quic::ConnectionCloseSource source) override;
-  bool ShouldKeepConnectionAlive() const override;
-
- protected:
-  // quic::QuicSession overrides.
-  // Creates a new stream initiated from the remote side. The caller does not
-  // own the stream, so the stream is activated and ownership is moved to the
-  // quic::QuicSession.
-  P2PQuicStreamImpl* CreateIncomingStream(
-      quic::QuicStreamId id) override;
-  P2PQuicStreamImpl* CreateIncomingStream(
-      quic::PendingStream* pending) override;
-
-  // Creates a new outgoing stream. The caller does not own the
-  // stream, so the stream is activated and ownership is moved to the
-  // quic::QuicSession.
-  P2PQuicStreamImpl* CreateOutgoingBidirectionalStream();
-
-  void SetDefaultEncryptionLevel(quic::EncryptionLevel level) override;
-  void OnTlsHandshakeComplete() override;
-
- private:
-  // This is for testing connection failures and handshake failures.
-  friend class P2PQuicTransportTest;
-
-  // These functions are used for testing.
-  //
-  // Returns true if the quic::QuicConnection has been closed remotely or
-  // locally.
-  bool IsClosed();
-  quic::QuicConnection* connection() { return connection_.get(); }
-
-  // quic::QuicSession overrides.
-  const quic::QuicCryptoStream* GetCryptoStream() const override;
-  quic::QuicCryptoStream* GetMutableCryptoStream() override;
-
-  // Creates the crypto stream necessary for handshake negotiation, and
-  // initializes the parent class (quic::QuicSession). This must be called on
-  // both sides before communicating between endpoints (Start, Close, etc.).
-  void InitializeCryptoStream();
-
-  // Creates a new stream. This helper function is used when we need to create
-  // a new incoming stream or outgoing stream.
-  P2PQuicStreamImpl* CreateStreamInternal(quic::QuicStreamId id);
-  P2PQuicStreamImpl* CreateStreamInternal(quic::PendingStream* pending);
-
-  // Returns true if datagram was sent, false if it was not because of
-  // congestion control blocking.
-  bool TrySendDatagram(Vector<uint8_t>& datagram);
-
-  // The server_config and client_config are used for setting up the crypto
-  // connection. The ownership of these objects or the objects they own
-  // (quic::ProofSource, quic::ProofVerifier, etc.), are not passed on to the
-  // QUIC library for the handshake, so we must own them here. A client
-  // |perspective_| will not have a crypto_server_config and vice versa.
-  std::unique_ptr<quic::QuicCryptoServerConfig> crypto_server_config_;
-  std::unique_ptr<quic::QuicCryptoClientConfig> crypto_client_config_;
-  // Used by server |crypto_stream_| to track most recently compressed certs.
-  std::unique_ptr<quic::QuicCompressedCertsCache> compressed_certs_cache_;
-  std::unique_ptr<quic::QuicCryptoServerStreamBase::Helper>
-      server_stream_helper_;
-  // Owned by the P2PQuicTransportImpl. |helper_| is placed before
-  // |connection_| to ensure it outlives it.
-  std::unique_ptr<quic::QuicConnectionHelperInterface> helper_;
-
-  std::unique_ptr<quic::QuicConnection> connection_;
-
-  // Used to create either a crypto client or server config.
-  std::unique_ptr<P2PQuicCryptoConfigFactory> crypto_config_factory_;
-  // Used to create a client or server crypto stream.
-  std::unique_ptr<P2PQuicCryptoStreamFactory> crypto_stream_factory_;
-
-  std::unique_ptr<quic::QuicCryptoStream> crypto_stream_;
-  // Crypto certificate information. Note that currently the handshake is
-  // insecure and these are not used...
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
-  Vector<std::unique_ptr<rtc::SSLFingerprint>> remote_fingerprints_;
-
-  bool pre_shared_key_set_ = false;
-
-  quic::Perspective perspective_;
-  // Outlives the P2PQuicTransport.
-  P2PQuicPacketTransport* packet_transport_;
-  P2PQuicTransport::Delegate* delegate_ = nullptr;
-  // Owned by whatever creates the P2PQuicTransportImpl. The |clock_| needs to
-  // outlive the P2PQuicTransportImpl.
-  quic::QuicClock* clock_ = nullptr;
-  // The size of the stream delegate's read buffer, used when creating
-  // P2PQuicStreams.
-  uint32_t stream_delegate_read_buffer_size_;
-  // Determines the size of the write buffer when P2PQuicStreams.
-  uint32_t stream_write_buffer_size_;
-
-  // For stats:
-  uint32_t num_outgoing_streams_created_ = 0;
-  uint32_t num_incoming_streams_created_ = 0;
-  // The number reported lost on the network by the quic::QuicSession.
-  uint32_t num_datagrams_lost_ = 0;
-
-  // Datagrams not yet sent due to congestion control blocking.
-  std::queue<Vector<uint8_t>> datagram_buffer_;
-
-  THREAD_CHECKER(thread_checker_);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_IMPL_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.cc
deleted file mode 100644
index edc88dd..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.cc
+++ /dev/null
@@ -1,37 +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/modules/peerconnection/adapters/p2p_quic_transport_stats.h"
-
-namespace blink {
-
-P2PQuicTransportStats::P2PQuicTransportStats()
-    : timestamp(base::TimeTicks::Now()) {}
-
-P2PQuicTransportStats::P2PQuicTransportStats(
-    const quic::QuicConnectionStats& quic_stats)
-    : timestamp(base::TimeTicks::Now()),
-      bytes_sent(quic_stats.bytes_sent),
-      packets_sent(quic_stats.packets_sent),
-      stream_bytes_sent(quic_stats.stream_bytes_sent),
-      stream_bytes_received(quic_stats.stream_bytes_received),
-      bytes_received(quic_stats.bytes_received),
-      packets_received(quic_stats.packets_received),
-      packets_processed(quic_stats.packets_processed),
-      bytes_retransmitted(quic_stats.bytes_retransmitted),
-      packets_retransmitted(quic_stats.packets_retransmitted),
-      packets_lost(quic_stats.packets_lost),
-      packets_dropped(quic_stats.packets_dropped),
-      crypto_retransmit_count(quic_stats.crypto_retransmit_count),
-      min_rtt_us(quic_stats.min_rtt_us),
-      srtt_us(quic_stats.srtt_us),
-      max_packet_size(quic_stats.max_packet_size),
-      max_received_packet_size(quic_stats.max_received_packet_size),
-      estimated_bandwidth_bps(quic_stats.estimated_bandwidth.ToBitsPerSecond()),
-      packets_reordered(quic_stats.packets_reordered),
-      blocked_frames_received(quic_stats.blocked_frames_received),
-      blocked_frames_sent(quic_stats.blocked_frames_sent),
-      connectivity_probing_packets_received(
-          quic_stats.num_connectivity_probing_received) {}
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h
deleted file mode 100644
index 0a4d2d4..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h
+++ /dev/null
@@ -1,81 +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_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_STATS_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_STATS_H_
-
-#include "base/time/time.h"
-#include "net/third_party/quiche/src/quic/core/quic_connection_stats.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-
-namespace blink {
-
-// These are stats associated with the P2PQuicTransport object. These
-// stats are mostly copied from quic::QuicConnectionStats, which includes
-// stats for a quic::QuicConnection. These are connection level stats.
-// Currently QUIC does not have stats at the stream level.
-struct MODULES_EXPORT P2PQuicTransportStats {
-  P2PQuicTransportStats();
-  // Note: The following stats are ignored from the QuicConnectionStats:
-  //       -packets_spuriously_retransmitted
-  //       -bytes_spuriously_retransmitted
-  //       -slowstart_packets_sent
-  //       -slowstart_packets_lost
-  //       -slowstart_bytes_lost
-  //       -loss_timeout_count
-  //       -tlp_count
-  //       -rto_count
-  //       -max_sequence_reordering
-  //       -max_time_reordering_us
-  //       -tcp_loss_events
-  //       -connection_creation_time
-  explicit P2PQuicTransportStats(const quic::QuicConnectionStats& stats);
-  ~P2PQuicTransportStats() = default;
-
-  base::TimeTicks timestamp;
-  // |bytes_sent| includes retransmissions.
-  uint64_t bytes_sent = 0;
-  uint64_t packets_sent = 0;
-  // |stream_bytes_sent| does not include retransmissions.
-  uint64_t stream_bytes_sent = 0;
-  uint64_t stream_bytes_received = 0;
-
-  // These include version negotiation and public reset packets.
-  //
-  // |bytes_received| includes duplicate data for a stream.
-  uint64_t bytes_received = 0;
-  // |packets_received| includes packets which were not processable.
-  uint64_t packets_received = 0;
-  uint64_t packets_processed = 0;
-
-  uint64_t bytes_retransmitted = 0;
-  uint64_t packets_retransmitted = 0;
-  // Number of packets abandoned as lost by the loss detection algorithm.
-  uint64_t packets_lost = 0;
-  uint64_t packets_dropped = 0;
-  size_t crypto_retransmit_count = 0;
-  // Minimum RTT in microseconds.
-  uint64_t min_rtt_us = 0;
-  // Smoothed RTT in microseconds.
-  uint64_t srtt_us = 0;
-  uint64_t max_packet_size = 0;
-  uint64_t max_received_packet_size = 0;
-  // Bits per second.
-  uint64_t estimated_bandwidth_bps = 0;
-  // Reordering stats for received packets.
-  // Number of packets received out of packet number order.
-  uint64_t packets_reordered = 0;
-  uint64_t blocked_frames_received = 0;
-  uint64_t blocked_frames_sent = 0;
-  // Number of connectivity probing packets received by this connection.
-  uint64_t connectivity_probing_packets_received = 0;
-
-  // The following are stats not taken directly from QuicConnectionStats:
-  uint32_t num_outgoing_streams_created = 0;
-  uint32_t num_incoming_streams_created = 0;
-  uint32_t num_datagrams_lost = 0;
-};
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_P2P_QUIC_TRANSPORT_STATS_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc
deleted file mode 100644
index e6a4615..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_test.cc
+++ /dev/null
@@ -1,1538 +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/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "base/bind.h"
-#include "net/quic/mock_crypto_client_stream.h"
-#include "net/quic/mock_crypto_client_stream_factory.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "net/quic/test_task_runner.h"
-#include "net/test/gtest_util.h"
-#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
-#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_compressed_certs_cache.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
-#include "net/third_party/quiche/src/quic/core/quic_circular_deque.h"
-#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
-#include "net/third_party/quiche/src/quic/core/quic_session.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_span.h"
-#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
-#include "third_party/blink/public/platform/web_vector.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_config_factory_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_crypto_stream_factory_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_packet_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream_delegate.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport_delegate.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/webrtc/rtc_base/rtc_certificate.h"
-#include "third_party/webrtc/rtc_base/ssl_fingerprint.h"
-#include "third_party/webrtc/rtc_base/ssl_identity.h"
-
-namespace blink {
-
-namespace {
-
-using testing::_;
-using testing::ElementsAreArray;
-using testing::Eq;
-using testing::Invoke;
-using testing::InvokeWithoutArgs;
-using ::testing::MakePolymorphicAction;
-using ::testing::PolymorphicAction;
-using testing::Property;
-using testing::ResultOf;
-using testing::Return;
-
-const uint8_t kTriggerRemoteStreamPhrase[] = {'o', 'p', 'e', 'n', ' ', 's',
-                                              'e', 's', 'a', 'm', 'e'};
-const uint8_t kMessage[] = {'h', 'o', 'w', 'd', 'y'};
-const uint8_t kMessage2[] = {'p', 'a', 'r', 't', 'n', 'e', 'r'};
-const uint8_t kClientMessage[] = {'h', 'o', 'w', 'd', 'y'};
-const uint8_t kServerMessage[] = {'p', 'a', 'r', 't', 'n', 'e', 'r'};
-const uint32_t kTransportWriteBufferSize = 100 * 1024;
-const uint32_t kTransportDelegateReadBufferSize = 100 * 1024;
-
-template <wtf_size_t Size>
-static Vector<uint8_t> VectorFromArray(const uint8_t (&array)[Size]) {
-  Vector<uint8_t> vector;
-  vector.Append(array, Size);
-  return vector;
-}
-
-// A custom gmock Action that fires the given callback. This is used in
-// conjuction with the CallbackRunLoop in order to drive the TestTaskRunner
-// until callbacks are fired. For example:
-//   CallbackRunLoop run_loop(runner());
-//   EXPECT_CALL(&object, foo())
-//       .WillOnce(FireCallback(run_loop.CreateCallback()));
-//   run_loop.RunUntilCallbacksFired(task_runner);
-class FireCallbackAction {
-  STACK_ALLOCATED();
-
- public:
-  FireCallbackAction(base::RepeatingCallback<void()> callback)
-      : callback_(callback) {}
-
-  template <typename Result, typename ArgumentTuple>
-  Result Perform(const ArgumentTuple& args) const {
-    callback_.Run();
-  }
-
- private:
-  base::RepeatingCallback<void()> callback_;
-};
-
-// Returns the custom gmock PolymorphicAction created from the
-// FireCallbackAction above.
-PolymorphicAction<FireCallbackAction> FireCallback(
-    base::RepeatingCallback<void()> callback) {
-  return MakePolymorphicAction(FireCallbackAction(callback));
-}
-
-// A helper object that can drive a TestTaskRunner's tasks, until
-// callbacks are fired.
-//
-// TODO(https://crbug.com/874296): If the test files get moved to the platform
-// directory we will run the tests in a different test environment. In that
-// case it will make more sense to use the TestCompletionCallback and the
-// RunLoop for driving the test.
-class CallbackRunLoop {
-  STACK_ALLOCATED();
-
- public:
-  CallbackRunLoop(scoped_refptr<net::test::TestTaskRunner> task_runner)
-      : task_runner_(task_runner) {}
-
-  // Drives the run loop until all created callbacks have been fired.
-  // This is done using the |task_runner_|, which runs the tasks
-  // in the correct order and then advances the quic::MockClock to the time the
-  // task is run.
-  void RunUntilCallbacksFired() {
-    while (callback_counter_ != 0) {
-      ASSERT_GT(task_runner_->GetPostedTasks().size(), 0u);
-      task_runner_->RunNextTask();
-    }
-  }
-
-  // Creates a callback and increments the |callback_counter_|. The callback,
-  // when fired, will decrement the counter. This callback must only
-  // be Run() once (it is a RepeatingCallback because MakePolymorphicAction()
-  // requires that the action is COPYABLE).
-  base::RepeatingCallback<void()> CreateCallback() {
-    callback_counter_++;
-    return base::BindRepeating(&CallbackRunLoop::OnCallbackFired,
-                               base::Unretained(this));
-  }
-
- private:
-  void OnCallbackFired() { callback_counter_--; }
-
-  scoped_refptr<net::test::TestTaskRunner> task_runner_;
-  // Incremented when a callback is created and decremented when the returned
-  // callback is later Run().
-  size_t callback_counter_ = 0;
-};
-
-// This is a fake packet transport to be used by the P2PQuicTransportImpl. It
-// allows to easily connect two packet transports together. We send packets
-// asynchronously, by using the same alarm factory that is being used for the
-// underlying QUIC library.
-class FakePacketTransport : public P2PQuicPacketTransport,
-                            public quic::QuicAlarm::Delegate {
- public:
-  FakePacketTransport(quic::QuicAlarmFactory* alarm_factory,
-                      quic::MockClock* clock)
-      : alarm_(alarm_factory->CreateAlarm(new AlarmDelegate(this))),
-        clock_(clock) {}
-  ~FakePacketTransport() override {
-    // The write observer should be unset when it is destroyed.
-    DCHECK(!write_observer_);
-  }
-
-  // Called by QUIC for writing data to the other side. The flow for writing a
-  // packet is P2PQuicTransportImpl --> quic::QuicConnection -->
-  // quic::QuicPacketWriter --> FakePacketTransport. In this case the
-  // FakePacketTransport just writes directly to the FakePacketTransport on the
-  // other side.
-  int WritePacket(const QuicPacket& packet) override {
-    // For the test there should always be a peer_packet_transport_ connected at
-    // this point.
-    if (!peer_packet_transport_) {
-      return 0;
-    }
-    last_packet_num_ = packet.packet_number;
-    packet_queue_.emplace_back(packet.buffer, packet.buf_len);
-    alarm_->Cancel();
-    // We don't want get 0 RTT.
-    alarm_->Set(clock_->Now() + quic::QuicTime::Delta::FromMicroseconds(10));
-
-    return packet.buf_len;
-  }
-
-  // Sets the P2PQuicTransportImpl as the delegate.
-  void SetReceiveDelegate(
-      P2PQuicPacketTransport::ReceiveDelegate* delegate) override {
-    // We can't set two ReceiveDelegates for one packet transport.
-    DCHECK(!delegate_ || !delegate);
-    delegate_ = delegate;
-  }
-
-  void SetWriteObserver(
-      P2PQuicPacketTransport::WriteObserver* write_observer) override {
-    // We can't set two WriteObservers for one packet transport.
-    DCHECK(!write_observer_ || !write_observer);
-    write_observer_ = write_observer;
-  }
-
-  bool Writable() override { return true; }
-
-  // Connects the other FakePacketTransport, so we can write to the peer.
-  void ConnectPeerTransport(FakePacketTransport* peer_packet_transport) {
-    DCHECK(!peer_packet_transport_);
-    peer_packet_transport_ = peer_packet_transport;
-  }
-
-  // Disconnects the delegate, so we no longer write to it. The test must call
-  // this before destructing either of the packet transports!
-  void DisconnectPeerTransport(FakePacketTransport* peer_packet_transport) {
-    DCHECK(peer_packet_transport_ == peer_packet_transport);
-    peer_packet_transport_ = nullptr;
-  }
-
-  // The callback used in order for us to communicate between
-  // FakePacketTransports.
-  void OnDataReceivedFromPeer(const char* data, size_t data_len) {
-    DCHECK(delegate_);
-    delegate_->OnPacketDataReceived(data, data_len);
-  }
-
-  uint64_t last_packet_num() { return last_packet_num_; }
-
- private:
-  // Wraps the FakePacketTransport so that we can pass in a raw pointer that can
-  // be reference counted when calling CreateAlarm().
-  class AlarmDelegate : public quic::QuicAlarm::Delegate {
-   public:
-    explicit AlarmDelegate(FakePacketTransport* packet_transport)
-        : packet_transport_(packet_transport) {}
-
-    void OnAlarm() override { packet_transport_->OnAlarm(); }
-
-   private:
-    FakePacketTransport* packet_transport_;
-  };
-
-  // Called when we should write any buffered data.
-  void OnAlarm() override {
-    // Send the data to the peer at this point.
-    peer_packet_transport_->OnDataReceivedFromPeer(
-        packet_queue_.front().c_str(), packet_queue_.front().length());
-    packet_queue_.pop_front();
-
-    // If there's more packets to be sent out, reset the alarm to send it as the
-    // next task.
-    if (!packet_queue_.empty()) {
-      alarm_->Cancel();
-      alarm_->Set(clock_->Now());
-    }
-  }
-  // If async, packets are queued here to send.
-  quic::QuicCircularDeque<std::string> packet_queue_;
-  // Alarm used to send data asynchronously.
-  quic::QuicArenaScopedPtr<quic::QuicAlarm> alarm_;
-  // The P2PQuicTransportImpl, which sets itself as the delegate in its
-  // constructor. After receiving data it forwards it along to QUIC.
-  P2PQuicPacketTransport::ReceiveDelegate* delegate_ = nullptr;
-
-  // The P2PQuicPacketWriter, which sets itself as a write observer
-  // during the P2PQuicTransportFactoryImpl::CreateQuicTransport. It is
-  // owned by the QuicConnection and will
-  P2PQuicPacketTransport::WriteObserver* write_observer_ = nullptr;
-
-  // The other FakePacketTransport that we are writing to. It's the
-  // responsibility of the test to disconnect this delegate
-  // (set_delegate(nullptr);) before it is destructed.
-  FakePacketTransport* peer_packet_transport_ = nullptr;
-  uint64_t last_packet_num_;
-  quic::MockClock* clock_;
-};
-
-// A helper class to bundle test objects together. It keeps track of the
-// P2PQuicTransport, P2PQuicStream and the associated delegate objects. This
-// also keeps track of when callbacks are expected on the delegate objects,
-// which allows running the TestTaskRunner tasks until they have been fired.
-class QuicPeerForTest {
-  USING_FAST_MALLOC(QuicPeerForTest);
-
- public:
-  QuicPeerForTest(
-      std::unique_ptr<FakePacketTransport> packet_transport,
-      std::unique_ptr<MockP2PQuicTransportDelegate> quic_transport_delegate,
-      std::unique_ptr<P2PQuicTransportImpl> quic_transport,
-      rtc::scoped_refptr<rtc::RTCCertificate> certificate)
-      : packet_transport_(std::move(packet_transport)),
-        quic_transport_delegate_(std::move(quic_transport_delegate)),
-        quic_transport_(std::move(quic_transport)),
-        certificate_(certificate) {}
-
-  // A helper that creates a stream and creates and attaches a delegate.
-  void CreateStreamWithDelegate() {
-    stream_ = quic_transport_->CreateStream();
-    stream_delegate_ = std::make_unique<MockP2PQuicStreamDelegate>();
-    stream_->SetDelegate(stream_delegate_.get());
-    stream_id_ = stream_->id();
-  }
-
-  // When a remote stream is created via P2PQuicTransport::Delegate::OnStream,
-  // this is called to set the stream.
-  void SetStreamAndDelegate(
-      P2PQuicStreamImpl* stream,
-      std::unique_ptr<MockP2PQuicStreamDelegate> stream_delegate) {
-    DCHECK(stream);
-    stream_ = stream;
-    stream_id_ = stream->id();
-    stream_delegate_ = std::move(stream_delegate);
-  }
-
-  FakePacketTransport* packet_transport() { return packet_transport_.get(); }
-
-  MockP2PQuicTransportDelegate* quic_transport_delegate() {
-    return quic_transport_delegate_.get();
-  }
-
-  P2PQuicTransportImpl* quic_transport() { return quic_transport_.get(); }
-
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate() { return certificate_; }
-
-  P2PQuicStreamImpl* stream() const { return stream_; }
-
-  MockP2PQuicStreamDelegate* stream_delegate() const {
-    return stream_delegate_.get();
-  }
-
-  quic::QuicStreamId stream_id() const { return stream_id_; }
-
- private:
-  std::unique_ptr<FakePacketTransport> packet_transport_;
-  std::unique_ptr<MockP2PQuicTransportDelegate> quic_transport_delegate_;
-  // The corresponding delegate to |stream_|.
-  std::unique_ptr<MockP2PQuicStreamDelegate> stream_delegate_ = nullptr;
-  // Created as a result of CreateStreamWithDelegate() or RemoteStreamCreated().
-  // Owned by the |quic_transport_|.
-  P2PQuicStreamImpl* stream_ = nullptr;
-  // The corresponding ID for |stream_|. This can be used to check if the stream
-  // is closed at the transport level (after the stream object could be
-  // deleted).
-  quic::QuicStreamId stream_id_;
-  std::unique_ptr<P2PQuicTransportImpl> quic_transport_;
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate_;
-};
-
-rtc::scoped_refptr<rtc::RTCCertificate> CreateTestCertificate() {
-  rtc::KeyParams params;
-
-  return rtc::RTCCertificate::Create(
-      rtc::SSLIdentity::Create("dummy_certificate", params));
-}
-
-// Allows faking a failing handshake.
-class FailingProofVerifierStub : public quic::ProofVerifier {
- public:
-  FailingProofVerifierStub() {}
-  ~FailingProofVerifierStub() override {}
-
-  // ProofVerifier override.
-  quic::QuicAsyncStatus VerifyProof(
-      const std::string& hostname,
-      const uint16_t port,
-      const std::string& server_config,
-      quic::QuicTransportVersion transport_version,
-      quiche::QuicheStringPiece chlo_hash,
-      const std::vector<std::string>& certs,
-      const std::string& cert_sct,
-      const std::string& signature,
-      const quic::ProofVerifyContext* context,
-      std::string* error_details,
-      std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
-      std::unique_ptr<quic::ProofVerifierCallback> callback) override {
-    return quic::QUIC_FAILURE;
-  }
-
-  quic::QuicAsyncStatus VerifyCertChain(
-      const std::string& hostname,
-      const uint16_t port,
-      const std::vector<std::string>& certs,
-      const std::string& ocsp_response,
-      const std::string& cert_sct,
-      const quic::ProofVerifyContext* context,
-      std::string* error_details,
-      std::unique_ptr<quic::ProofVerifyDetails>* details,
-      std::unique_ptr<quic::ProofVerifierCallback> callback) override {
-    return quic::QUIC_FAILURE;
-  }
-
-  std::unique_ptr<quic::ProofVerifyContext> CreateDefaultContext() override {
-    return nullptr;
-  }
-};
-
-// A dummy implementation of a quic::ProofSource.
-class ProofSourceStub : public quic::ProofSource {
- public:
-  ProofSourceStub() {}
-  ~ProofSourceStub() override {}
-
-  // ProofSource override.
-  void GetProof(const quic::QuicSocketAddress& server_addr,
-                const quic::QuicSocketAddress& client_addr,
-                const std::string& hostname,
-                const std::string& server_config,
-                quic::QuicTransportVersion transport_version,
-                quiche::QuicheStringPiece chlo_hash,
-                std::unique_ptr<Callback> callback) override {
-    quic::QuicCryptoProof proof;
-    proof.signature = "Test signature";
-    proof.leaf_cert_scts = "Test timestamp";
-    callback->Run(true, GetCertChain(server_addr, client_addr, hostname), proof,
-                  nullptr /* details */);
-  }
-
-  quic::QuicReferenceCountedPointer<Chain> GetCertChain(
-      const quic::QuicSocketAddress& server_address,
-      const quic::QuicSocketAddress& client_address,
-      const std::string& hostname) override {
-    WebVector<std::string> certs;
-    certs.emplace_back("Test cert");
-    return quic::QuicReferenceCountedPointer<Chain>(
-        new ProofSource::Chain(certs.ReleaseVector()));
-  }
-  void ComputeTlsSignature(
-      const quic::QuicSocketAddress& server_address,
-      const quic::QuicSocketAddress& client_address,
-      const std::string& hostname,
-      uint16_t signature_algorithm,
-      quiche::QuicheStringPiece in,
-      std::unique_ptr<SignatureCallback> callback) override {
-    callback->Run(true, "Test signature", nullptr);
-  }
-
-  TicketCrypter* GetTicketCrypter() override { return nullptr; }
-};
-
-// Creates crypto configs that will fail a QUIC handshake.
-class FailingQuicCryptoConfigFactory final : public P2PQuicCryptoConfigFactory {
- public:
-  FailingQuicCryptoConfigFactory(quic::QuicRandom* quic_random)
-      : quic_random_(quic_random) {}
-
-  std::unique_ptr<quic::QuicCryptoClientConfig> CreateClientCryptoConfig()
-      override {
-    return std::make_unique<quic::QuicCryptoClientConfig>(
-        std::make_unique<FailingProofVerifierStub>());
-  }
-
-  std::unique_ptr<quic::QuicCryptoServerConfig> CreateServerCryptoConfig()
-      override {
-    return std::make_unique<quic::QuicCryptoServerConfig>(
-        quic::QuicCryptoServerConfig::TESTING, quic_random_,
-        std::make_unique<ProofSourceStub>(),
-        quic::KeyExchangeSource::Default());
-  }
-
- private:
-  quic::QuicRandom* quic_random_;
-};
-
-// A CryptoClientStream that bypasses the QUIC handshake and becomes connected.
-class ConnectedCryptoClientStream final : public quic::QuicCryptoClientStream {
- public:
-  ConnectedCryptoClientStream(
-      const quic::QuicServerId& server_id,
-      quic::QuicSession* session,
-      std::unique_ptr<quic::ProofVerifyContext> verify_context,
-      quic::QuicCryptoClientConfig* crypto_config,
-      quic::QuicCryptoClientStream::ProofHandler* proof_handler)
-      : quic::QuicCryptoClientStream(server_id,
-                                     session,
-                                     std::move(verify_context),
-                                     crypto_config,
-                                     proof_handler,
-                                     /*has_application_state = */ true),
-        session_(session) {}
-  ~ConnectedCryptoClientStream() override {}
-
-  bool CryptoConnect() override {
-    encryption_established_ = true;
-    handshake_confirmed_ = true;
-    // quic::QuicSession checks that its config has been negotiated after the
-    // handshake has been confirmed. The easiest way to fake negotiated values
-    // is to have the config object process a hello message.
-    quic::QuicConfig config;
-    config.SetBytesForConnectionIdToSend(quic::PACKET_8BYTE_CONNECTION_ID);
-    config.SetMaxBidirectionalStreamsToSend(
-        quic::kDefaultMaxStreamsPerConnection / 2);
-    config.SetMaxUnidirectionalStreamsToSend(
-        quic::kDefaultMaxStreamsPerConnection / 2);
-    quic::CryptoHandshakeMessage message;
-    config.ToHandshakeMessage(&message,
-                              session()->connection()->transport_version());
-    std::string error_details;
-    session()->config()->ProcessPeerHello(message, quic::CLIENT,
-                                          &error_details);
-    session()->OnConfigNegotiated();
-    if (session()->version().UsesTls()) {
-      session()->OnTlsHandshakeComplete();
-    } else {
-      session()->SetDefaultEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
-    }
-    session()->DiscardOldEncryptionKey(quic::ENCRYPTION_INITIAL);
-    session()->NeuterHandshakeData();
-    return true;
-  }
-
-  quic::QuicSession* session() { return session_; }
-
-  bool encryption_established() const override {
-    return encryption_established_;
-  }
-
-  bool one_rtt_keys_available() const override { return handshake_confirmed_; }
-
- private:
-  bool encryption_established_ = false;
-  bool handshake_confirmed_ = false;
-  // Outlives this object.
-  quic::QuicSession* session_;
-};
-
-// A P2PQuicCryptoStream factory that uses a ConnectedCryptoClientStream
-// test object that can fake a successful connection.
-class ConnectedCryptoClientStreamFactory final
-    : public P2PQuicCryptoStreamFactory {
- public:
-  ~ConnectedCryptoClientStreamFactory() override {}
-
-  std::unique_ptr<quic::QuicCryptoClientStream> CreateClientCryptoStream(
-      quic::QuicSession* session,
-      quic::QuicCryptoClientConfig* crypto_config,
-      quic::QuicCryptoClientStream::ProofHandler* proof_handler) override {
-    quic::QuicServerId server_id("dummy_host", 12345);
-    return std::make_unique<ConnectedCryptoClientStream>(
-        server_id, session,
-        crypto_config->proof_verifier()->CreateDefaultContext(), crypto_config,
-        proof_handler);
-  }
-
-  // Creates a real quic::QuiCryptoServerStream.
-  std::unique_ptr<quic::QuicCryptoServerStreamBase> CreateServerCryptoStream(
-      const quic::QuicCryptoServerConfig* crypto_config,
-      quic::QuicCompressedCertsCache* compressed_certs_cache,
-      quic::QuicSession* session,
-      quic::QuicCryptoServerStreamBase::Helper* helper) override {
-    return quic::CreateCryptoServerStream(crypto_config, compressed_certs_cache,
-                                          session, helper);
-  }
-};
-
-}  // namespace
-
-// Unit tests for the P2PQuicTransport, using an underlying fake packet
-// transport that sends packets directly between endpoints. This also tests
-// P2PQuicStreams for test cases that involve two streams connected between
-// separate endpoints. This is because the P2PQuicStream is highly coupled to
-// the P2PQuicSession for communicating between endpoints, so we would like to
-// test it with the real session object.
-//
-// The test is driven using the quic::TestTaskRunner to run posted tasks until
-// callbacks have been fired.
-class P2PQuicTransportTest : public testing::Test {
- public:
-  P2PQuicTransportTest() {
-    // TODO(crbug/1070747): Fix tests for IETF QUIC.
-    quic::test::DisableQuicVersionsWithTls();
-    // Quic crashes if packets are sent at time 0, and the clock defaults to 0.
-    clock_.AdvanceTime(quic::QuicTime::Delta::FromMilliseconds(1000));
-    quic_random_ = quic::QuicRandom::GetInstance();
-    runner_ = base::MakeRefCounted<net::test::TestTaskRunner>(&clock_);
-    alarm_factory_ =
-        std::make_unique<net::QuicChromiumAlarmFactory>(runner_.get(), &clock_);
-  }
-
-  ~P2PQuicTransportTest() override {
-    // This must be done before desctructing the transports so that we don't
-    // have any dangling pointers.
-    client_peer_->packet_transport()->DisconnectPeerTransport(
-        server_peer_->packet_transport());
-    server_peer_->packet_transport()->DisconnectPeerTransport(
-        client_peer_->packet_transport());
-  }
-
-  // Supplying the |client_crypto_factory| and |server_crypto_factory| allows
-  // testing a failing QUIC handshake. The |client_certificate| and
-  // |server_certificate| must be the same certificates used in the crypto
-  // factories.
-  void Initialize(
-      std::unique_ptr<P2PQuicCryptoConfigFactory> client_crypto_factory,
-      std::unique_ptr<P2PQuicCryptoConfigFactory> server_crypto_factory) {
-    auto client_packet_transport =
-        std::make_unique<FakePacketTransport>(alarm_factory_.get(), &clock_);
-    auto server_packet_transport =
-        std::make_unique<FakePacketTransport>(alarm_factory_.get(), &clock_);
-    // Connect the transports so that they can speak to each other.
-    client_packet_transport->ConnectPeerTransport(
-        server_packet_transport.get());
-    server_packet_transport->ConnectPeerTransport(
-        client_packet_transport.get());
-
-    rtc::scoped_refptr<rtc::RTCCertificate> client_certificate =
-        CreateTestCertificate();
-    auto client_quic_transport_delegate =
-        std::make_unique<MockP2PQuicTransportDelegate>();
-    P2PQuicTransportConfig client_config(
-        quic::Perspective::IS_CLIENT, {client_certificate},
-        kTransportDelegateReadBufferSize, kTransportWriteBufferSize);
-
-    std::unique_ptr<P2PQuicTransportImpl> client_quic_transport =
-        P2PQuicTransportImpl::Create(
-            &clock_, alarm_factory_.get(), quic_random_,
-            client_quic_transport_delegate.get(), client_packet_transport.get(),
-            client_config, std::move(client_crypto_factory),
-            std::make_unique<P2PQuicCryptoStreamFactoryImpl>());
-
-    client_peer_ = std::make_unique<QuicPeerForTest>(
-        std::move(client_packet_transport),
-        std::move(client_quic_transport_delegate),
-        std::move(client_quic_transport), client_certificate);
-
-    auto server_quic_transport_delegate =
-        std::make_unique<MockP2PQuicTransportDelegate>();
-
-    rtc::scoped_refptr<rtc::RTCCertificate> server_certificate =
-        CreateTestCertificate();
-    P2PQuicTransportConfig server_config(
-        quic::Perspective::IS_SERVER, {server_certificate},
-        kTransportDelegateReadBufferSize, kTransportWriteBufferSize);
-
-    std::unique_ptr<P2PQuicTransportImpl> server_quic_transport =
-        P2PQuicTransportImpl::Create(
-            &clock_, alarm_factory_.get(), quic_random_,
-            server_quic_transport_delegate.get(), server_packet_transport.get(),
-            server_config, std::move(server_crypto_factory),
-            std::make_unique<P2PQuicCryptoStreamFactoryImpl>());
-
-    server_peer_ = std::make_unique<QuicPeerForTest>(
-        std::move(server_packet_transport),
-        std::move(server_quic_transport_delegate),
-        std::move(server_quic_transport), server_certificate);
-  }
-
-  // Connects both peer's underlying packet transports and creates both
-  // P2PQuicTransportImpls.
-  void Initialize() {
-    Initialize(std::make_unique<P2PQuicCryptoConfigFactoryImpl>(quic_random_),
-               std::make_unique<P2PQuicCryptoConfigFactoryImpl>(quic_random_));
-  }
-
-  // Uses a crypto config factory that returns a client configuration that
-  // will reject the QUIC handshake. This lets us simulate a failng handshake.
-  void InitializeWithFailingProofVerification() {
-    Initialize(std::make_unique<FailingQuicCryptoConfigFactory>(quic_random_),
-               std::make_unique<FailingQuicCryptoConfigFactory>(quic_random_));
-  }
-
-  // Drives the test by running the current tasks that are posted.
-  void RunCurrentTasks() {
-    size_t posted_tasks_size = runner_->GetPostedTasks().size();
-    for (size_t i = 0; i < posted_tasks_size; ++i) {
-      runner_->RunNextTask();
-    }
-  }
-
-  // Sets up an initial handshake and connection between peers.
-  // This is done using a pre shared key.
-  void Connect() {
-    CallbackRunLoop run_loop(runner());
-    EXPECT_CALL(*client_peer_->quic_transport_delegate(), OnConnected(_))
-        .WillOnce(FireCallback(run_loop.CreateCallback()));
-    EXPECT_CALL(*server_peer_->quic_transport_delegate(), OnConnected(_))
-        .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-    server_peer_->quic_transport()->Start(
-        P2PQuicTransport::StartConfig("foobar"));
-    client_peer_->quic_transport()->Start(
-        P2PQuicTransport::StartConfig("foobar"));
-    run_loop.RunUntilCallbacksFired();
-  }
-
-  // Creates a P2PQuicStreamImpl on both the client and server side that are
-  // connected to each other. The client's stream is created with
-  // P2PQuicTransport::CreateStream, while the server's stream is initiated from
-  // the remote (client) side, with P2PQuicStream::Delegate::OnStream. This
-  // allows us to test at an integration level with connected streams.
-  void SetupConnectedStreams() {
-    CallbackRunLoop run_loop(runner());
-    // We must already have a secure connection before streams are created.
-    ASSERT_TRUE(client_peer_->quic_transport()->IsEncryptionEstablished());
-    ASSERT_TRUE(server_peer_->quic_transport()->IsEncryptionEstablished());
-
-    client_peer_->CreateStreamWithDelegate();
-    ASSERT_TRUE(client_peer_->stream());
-    ASSERT_TRUE(client_peer_->stream_delegate());
-
-    // Send some data to trigger the remote side (server side) to get an
-    // incoming stream. We capture the stream and set it's delegate when
-    // OnStream gets called on the mock object.
-    base::RepeatingCallback<void()> callback = run_loop.CreateCallback();
-    QuicPeerForTest* server_peer_ptr = server_peer_.get();
-    MockP2PQuicStreamDelegate* stream_delegate =
-        new MockP2PQuicStreamDelegate();
-    P2PQuicStream* server_stream;
-    EXPECT_CALL(*server_peer_->quic_transport_delegate(), OnStream(_))
-        .WillOnce(Invoke([&callback, &server_stream,
-                          &stream_delegate](P2PQuicStream* stream) {
-          stream->SetDelegate(stream_delegate);
-          server_stream = stream;
-          callback.Run();
-        }));
-
-    client_peer_->stream()->WriteData(
-        VectorFromArray(kTriggerRemoteStreamPhrase),
-        /*fin=*/false);
-    run_loop.RunUntilCallbacksFired();
-    // Set the stream and delegate to the |server_peer_|, so that it can be
-    // accessed by tests later.
-    server_peer_ptr->SetStreamAndDelegate(
-        static_cast<P2PQuicStreamImpl*>(server_stream),
-        std::unique_ptr<MockP2PQuicStreamDelegate>(stream_delegate));
-    ASSERT_TRUE(client_peer_->stream());
-    ASSERT_TRUE(client_peer_->stream_delegate());
-  }
-
-  void ExpectConnectionNotEstablished() {
-    EXPECT_FALSE(client_peer_->quic_transport()->IsEncryptionEstablished());
-    EXPECT_FALSE(client_peer_->quic_transport()->OneRttKeysAvailable());
-    EXPECT_FALSE(server_peer_->quic_transport()->OneRttKeysAvailable());
-    EXPECT_FALSE(server_peer_->quic_transport()->IsEncryptionEstablished());
-  }
-
-  void ExpectTransportsClosed() {
-    EXPECT_TRUE(client_peer_->quic_transport()->IsClosed());
-    EXPECT_TRUE(server_peer_->quic_transport()->IsClosed());
-  }
-
-  // Expects that streams of both the server and client transports are
-  // closed.
-  void ExpectStreamsClosed() {
-    EXPECT_EQ(0u, client_peer_->quic_transport()->GetNumActiveStreams());
-    EXPECT_TRUE(client_peer_->quic_transport()->IsClosedStream(
-        client_peer()->stream_id()));
-
-    EXPECT_EQ(0u, server_peer_->quic_transport()->GetNumActiveStreams());
-    EXPECT_TRUE(server_peer()->quic_transport()->IsClosedStream(
-        server_peer()->stream_id()));
-  }
-
-  // Exposes these private functions to the test.
-  bool IsClientClosed() { return client_peer_->quic_transport()->IsClosed(); }
-  bool IsServerClosed() { return server_peer_->quic_transport()->IsClosed(); }
-
-  QuicPeerForTest* client_peer() { return client_peer_.get(); }
-
-  quic::QuicConnection* client_connection() {
-    return client_peer_->quic_transport()->connection();
-  }
-
-  QuicPeerForTest* server_peer() { return server_peer_.get(); }
-
-  quic::QuicConnection* server_connection() {
-    return server_peer_->quic_transport()->connection();
-  }
-
-  scoped_refptr<net::test::TestTaskRunner> runner() { return runner_; }
-
- private:
-  quic::MockClock clock_;
-  quic::QuicRandom* quic_random_;
-  // The TestTaskRunner is used by the QUIC library for setting/firing alarms.
-  // We are able to explicitly run these tasks ourselves with the
-  // TestTaskRunner.
-  scoped_refptr<net::test::TestTaskRunner> runner_;
-  // This is eventually passed down to the QUIC library.
-  std::unique_ptr<net::QuicChromiumAlarmFactory> alarm_factory_;
-
-  std::unique_ptr<P2PQuicTransportFactoryImpl> quic_transport_factory_;
-  std::unique_ptr<QuicPeerForTest> client_peer_;
-  std::unique_ptr<QuicPeerForTest> server_peer_;
-};
-
-// Tests that we can connect two quic transports using pre shared keys.
-TEST_F(P2PQuicTransportTest, HandshakeConnectsPeersWithPreSharedKeys) {
-  Initialize();
-
-  CallbackRunLoop run_loop(runner());
-  // Datagrams should be supported.
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(),
-              OnConnected(Property(
-                  &P2PQuicNegotiatedParams::datagrams_supported, Eq(true))))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(),
-              OnConnected(Property(
-                  &P2PQuicNegotiatedParams::datagrams_supported, Eq(true))))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  server_peer()->quic_transport()->Start(
-      P2PQuicTransport::StartConfig("foobar"));
-  client_peer()->quic_transport()->Start(
-      P2PQuicTransport::StartConfig("foobar"));
-  run_loop.RunUntilCallbacksFired();
-
-  EXPECT_TRUE(client_peer()->quic_transport()->IsEncryptionEstablished());
-  EXPECT_TRUE(client_peer()->quic_transport()->OneRttKeysAvailable());
-  EXPECT_TRUE(server_peer()->quic_transport()->OneRttKeysAvailable());
-  EXPECT_TRUE(server_peer()->quic_transport()->IsEncryptionEstablished());
-}
-
-// Tests that we can connect two quic transports using remote certificate
-// fingerprints. Note that the fingerprints aren't currently used for
-// verification.
-TEST_F(P2PQuicTransportTest, HandshakeConnectsPeersWithRemoteCertificates) {
-  Initialize();
-
-  CallbackRunLoop run_loop(runner());
-  // Datagrams should be supported.
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(),
-              OnConnected(Property(
-                  &P2PQuicNegotiatedParams::datagrams_supported, Eq(true))))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(),
-              OnConnected(Property(
-                  &P2PQuicNegotiatedParams::datagrams_supported, Eq(true))))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  // Start the handshake with the remote fingerprints.
-  Vector<std::unique_ptr<rtc::SSLFingerprint>> server_fingerprints;
-  server_fingerprints.push_back(rtc::SSLFingerprint::CreateUnique(
-      "sha-256", *server_peer()->certificate()->identity()));
-  server_peer()->quic_transport()->Start(
-      P2PQuicTransport::StartConfig(std::move(server_fingerprints)));
-
-  Vector<std::unique_ptr<rtc::SSLFingerprint>> client_fingerprints;
-  client_fingerprints.push_back(rtc::SSLFingerprint::CreateUnique(
-      "sha-256", *client_peer()->certificate()->identity()));
-  client_peer()->quic_transport()->Start(
-      P2PQuicTransport::StartConfig(std::move(client_fingerprints)));
-
-  run_loop.RunUntilCallbacksFired();
-
-  EXPECT_TRUE(client_peer()->quic_transport()->IsEncryptionEstablished());
-  EXPECT_TRUE(client_peer()->quic_transport()->OneRttKeysAvailable());
-  EXPECT_TRUE(server_peer()->quic_transport()->OneRttKeysAvailable());
-  EXPECT_TRUE(server_peer()->quic_transport()->IsEncryptionEstablished());
-}
-
-// Tests the standard case for the server side closing the connection.
-TEST_F(P2PQuicTransportTest, ServerStops) {
-  Initialize();
-  Connect();
-  CallbackRunLoop run_loop(runner());
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(), OnRemoteStopped())
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnRemoteStopped())
-      .Times(0);
-
-  server_peer()->quic_transport()->Stop();
-  run_loop.RunUntilCallbacksFired();
-
-  ExpectTransportsClosed();
-}
-
-// Tests the standard case for the client side closing the connection.
-TEST_F(P2PQuicTransportTest, ClientStops) {
-  Initialize();
-  Connect();
-  CallbackRunLoop run_loop(runner());
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnRemoteStopped())
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(), OnRemoteStopped())
-      .Times(0);
-
-  client_peer()->quic_transport()->Stop();
-  run_loop.RunUntilCallbacksFired();
-
-  ExpectTransportsClosed();
-}
-
-// Tests that if either side tries to close the connection a second time, it
-// will be ignored because the connection has already been closed.
-TEST_F(P2PQuicTransportTest, StopAfterStopped) {
-  Initialize();
-  Connect();
-  CallbackRunLoop run_loop(runner());
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnRemoteStopped())
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  client_peer()->quic_transport()->Stop();
-  run_loop.RunUntilCallbacksFired();
-
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnRemoteStopped())
-      .Times(0);
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(), OnRemoteStopped())
-      .Times(0);
-
-  client_peer()->quic_transport()->Stop();
-  server_peer()->quic_transport()->Stop();
-  RunCurrentTasks();
-
-  ExpectTransportsClosed();
-}
-
-// Tests that the appropriate callbacks are fired when the handshake fails.
-TEST_F(P2PQuicTransportTest, HandshakeFailure) {
-  InitializeWithFailingProofVerification();
-  CallbackRunLoop run_loop(runner());
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(),
-              OnConnectionFailed(_, _))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(),
-              OnConnectionFailed(_, _))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  server_peer()->quic_transport()->Start(
-      P2PQuicTransport::StartConfig("foobar"));
-  client_peer()->quic_transport()->Start(
-      P2PQuicTransport::StartConfig("foobar"));
-  run_loop.RunUntilCallbacksFired();
-
-  ExpectConnectionNotEstablished();
-  ExpectTransportsClosed();
-}
-
-// Tests that the handshake fails if the pre shared keys don't match.
-// In this case the handshake finishes, but the connection fails because packets
-// can't be decrypted.
-TEST_F(P2PQuicTransportTest, HandshakeFailsBecauseKeysDontMatch) {
-  Initialize();
-  CallbackRunLoop run_loop(runner());
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(),
-              OnConnectionFailed(_, _))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(),
-              OnConnectionFailed(_, _))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  server_peer()->quic_transport()->Start(
-      P2PQuicTransport::StartConfig("foobar"));
-  client_peer()->quic_transport()->Start(
-      P2PQuicTransport::StartConfig("barfoo"));
-  run_loop.RunUntilCallbacksFired();
-
-  ExpectTransportsClosed();
-}
-
-// Tests that the appropriate callbacks are fired when the client's connection
-// fails after the transports have connected.
-TEST_F(P2PQuicTransportTest, ClientConnectionFailureAfterConnected) {
-  Initialize();
-  Connect();
-  CallbackRunLoop run_loop(runner());
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(),
-              OnConnectionFailed(_, /*from_remote=*/false))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(),
-              OnConnectionFailed(_, /*from_remote=*/true))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  // Close the connection with an internal QUIC error.
-  client_connection()->CloseConnection(
-      quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error",
-      quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-  run_loop.RunUntilCallbacksFired();
-
-  ExpectTransportsClosed();
-}
-
-// Tests that the appropriate callbacks are fired when the server's connection
-// fails after the transports have connected.
-TEST_F(P2PQuicTransportTest, ServerConnectionFailureAfterConnected) {
-  Initialize();
-  Connect();
-  CallbackRunLoop run_loop(runner());
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(),
-              OnConnectionFailed(_, /*from_remote=*/true))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(),
-              OnConnectionFailed(_, /*from_remote=*/false))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  server_connection()->CloseConnection(
-      quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error",
-      quic::ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
-  run_loop.RunUntilCallbacksFired();
-
-  ExpectTransportsClosed();
-}
-
-// Tests that a silent failure will only close on one side.
-TEST_F(P2PQuicTransportTest, ConnectionSilentFailure) {
-  Initialize();
-  Connect();
-  CallbackRunLoop run_loop(runner());
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(),
-              OnConnectionFailed(_, _))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(),
-              OnConnectionFailed(_, _))
-      .Times(0);
-
-  client_connection()->CloseConnection(
-      quic::QuicErrorCode::QUIC_INTERNAL_ERROR, "internal error",
-      quic::ConnectionCloseBehavior::SILENT_CLOSE);
-  run_loop.RunUntilCallbacksFired();
-
-  EXPECT_TRUE(IsClientClosed());
-  EXPECT_FALSE(IsServerClosed());
-}
-
-// Tests that the client transport can create a stream and an incoming stream
-// will be created on the remote server.
-TEST_F(P2PQuicTransportTest, ClientCreatesStream) {
-  Initialize();
-  Connect();
-  CallbackRunLoop run_loop(runner());
-  client_peer()->CreateStreamWithDelegate();
-  ASSERT_TRUE(client_peer()->stream());
-
-  RunCurrentTasks();
-
-  EXPECT_TRUE(client_peer()->quic_transport()->ShouldKeepConnectionAlive());
-  EXPECT_FALSE(server_peer()->quic_transport()->ShouldKeepConnectionAlive());
-
-  // After sending data across it will trigger a stream to be created on the
-  // server side.
-  MockP2PQuicStreamDelegate server_stream_delegate;
-  base::RepeatingCallback<void()> callback = run_loop.CreateCallback();
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnStream(_))
-      .WillOnce(
-          Invoke([&callback, &server_stream_delegate](P2PQuicStream* stream) {
-            ASSERT_TRUE(stream);
-            // The Delegate must get immediately set to a new incoming stream.
-            stream->SetDelegate(&server_stream_delegate);
-            // Allows the run loop to run until this is fired.
-            callback.Run();
-          }));
-
-  client_peer()->stream()->WriteData(
-      VectorFromArray(kTriggerRemoteStreamPhrase),
-      /*fin=*/false);
-  run_loop.RunUntilCallbacksFired();
-
-  EXPECT_TRUE(server_peer()->quic_transport()->ShouldKeepConnectionAlive());
-}
-
-// Tests that the server transport can create a stream and an incoming stream
-// will be created on the remote client.
-TEST_F(P2PQuicTransportTest, ServerCreatesStream) {
-  Initialize();
-  Connect();
-  CallbackRunLoop run_loop(runner());
-  server_peer()->CreateStreamWithDelegate();
-  ASSERT_TRUE(server_peer()->stream());
-
-  RunCurrentTasks();
-
-  EXPECT_TRUE(server_peer()->quic_transport()->ShouldKeepConnectionAlive());
-  EXPECT_FALSE(client_peer()->quic_transport()->ShouldKeepConnectionAlive());
-
-  // After sending data across it will trigger a stream to be created on the
-  // server side.
-  MockP2PQuicStreamDelegate client_stream_delegate;
-  base::RepeatingCallback<void()> callback = run_loop.CreateCallback();
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(), OnStream(_))
-      .WillOnce(
-          Invoke([&callback, &client_stream_delegate](P2PQuicStream* stream) {
-            ASSERT_TRUE(stream);
-            // The Delegate must get immediately set to a new incoming stream.
-            stream->SetDelegate(&client_stream_delegate);
-            // Allows the run loop to run until this is fired.
-            callback.Run();
-          }));
-
-  server_peer()->stream()->WriteData(
-      VectorFromArray(kTriggerRemoteStreamPhrase),
-      /*fin=*/false);
-  run_loop.RunUntilCallbacksFired();
-
-  EXPECT_TRUE(client_peer()->quic_transport()->ShouldKeepConnectionAlive());
-}
-
-// Tests that when the client transport calls Stop() it closes its outgoing
-// stream, which, in turn closes the incoming stream on the server quic
-// transport.
-TEST_F(P2PQuicTransportTest, ClientClosingConnectionClosesStreams) {
-  Initialize();
-  Connect();
-  SetupConnectedStreams();
-
-  client_peer()->quic_transport()->Stop();
-  RunCurrentTasks();
-
-  ExpectTransportsClosed();
-  ExpectStreamsClosed();
-}
-
-// Tests that when the server transport calls Stop() it closes its incoming
-// stream, which, in turn closes the outgoing stream on the client quic
-// transport.
-// TODO(crbug.com/1056976): re-enable this test when crbug.com/1056976 is fixed.
-TEST_F(P2PQuicTransportTest, DISABLED_ServerClosingConnectionClosesStreams) {
-  Initialize();
-  Connect();
-  SetupConnectedStreams();
-
-  server_peer()->quic_transport()->Stop();
-  RunCurrentTasks();
-
-  ExpectTransportsClosed();
-  ExpectStreamsClosed();
-}
-
-// Tests that calling Reset() will close both side's streams for reading and
-// writing.
-TEST_F(P2PQuicTransportTest, ClientStreamReset) {
-  Initialize();
-  Connect();
-  SetupConnectedStreams();
-  CallbackRunLoop run_loop(runner());
-
-  EXPECT_CALL(*server_peer()->stream_delegate(), OnRemoteReset())
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  client_peer()->stream()->Reset();
-  run_loop.RunUntilCallbacksFired();
-  ExpectStreamsClosed();
-}
-
-// Tests that calling Reset() will close both side's streams for reading and
-// writing.
-TEST_F(P2PQuicTransportTest, ServerStreamReset) {
-  Initialize();
-  Connect();
-  SetupConnectedStreams();
-  CallbackRunLoop run_loop(runner());
-
-  EXPECT_CALL(*client_peer()->stream_delegate(), OnRemoteReset())
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  server_peer()->stream()->Reset();
-  run_loop.RunUntilCallbacksFired();
-
-  ExpectStreamsClosed();
-}
-
-// Tests the basic case for sending a FIN bit on both sides.
-TEST_F(P2PQuicTransportTest, StreamClosedAfterSendingAndReceivingFin) {
-  Initialize();
-  Connect();
-  SetupConnectedStreams();
-  CallbackRunLoop run_loop(runner());
-
-  EXPECT_CALL(*server_peer()->stream_delegate(),
-              OnDataReceived(_, /*fin=*/true))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  client_peer()->stream()->WriteData({}, /*fin=*/true);
-  run_loop.RunUntilCallbacksFired();
-
-  ASSERT_EQ(1u, server_peer()->quic_transport()->GetNumActiveStreams());
-  ASSERT_EQ(1u, client_peer()->quic_transport()->GetNumActiveStreams());
-  EXPECT_TRUE(client_peer()->stream()->write_side_closed());
-  EXPECT_FALSE(client_peer()->stream()->reading_stopped());
-  EXPECT_FALSE(server_peer()->stream()->write_side_closed());
-  EXPECT_TRUE(server_peer()->stream()->reading_stopped());
-  EXPECT_FALSE(server_peer()->quic_transport()->IsClosedStream(
-      server_peer()->stream_id()));
-  EXPECT_FALSE(client_peer()->quic_transport()->IsClosedStream(
-      client_peer()->stream_id()));
-
-  EXPECT_CALL(*client_peer()->stream_delegate(),
-              OnDataReceived(_, /*fin=*/true))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  server_peer()->stream()->WriteData({}, /*fin=*/true);
-  run_loop.RunUntilCallbacksFired();
-
-  // This is required so that the client acks the FIN back to the server side
-  // and the server side removes its zombie streams.
-  RunCurrentTasks();
-
-  ASSERT_EQ(0u, server_peer()->quic_transport()->GetNumActiveStreams());
-  ASSERT_EQ(0u, client_peer()->quic_transport()->GetNumActiveStreams());
-  EXPECT_TRUE(server_peer()->quic_transport()->IsClosedStream(
-      server_peer()->stream_id()));
-  EXPECT_TRUE(client_peer()->quic_transport()->IsClosedStream(
-      client_peer()->stream_id()));
-}
-
-// Tests that if a Reset() is called after sending a FIN bit, both sides close
-// down properly.
-TEST_F(P2PQuicTransportTest, StreamResetAfterSendingFin) {
-  Initialize();
-  Connect();
-  SetupConnectedStreams();
-  CallbackRunLoop run_loop(runner());
-
-  EXPECT_CALL(*server_peer()->stream_delegate(),
-              OnDataReceived(_, /*fin=*/true))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  client_peer()->stream()->WriteData({}, /*fin=*/true);
-  run_loop.RunUntilCallbacksFired();
-
-  EXPECT_CALL(*server_peer()->stream_delegate(), OnRemoteReset())
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*client_peer()->stream_delegate(), OnRemoteReset()).Times(0);
-
-  client_peer()->stream()->Reset();
-  run_loop.RunUntilCallbacksFired();
-
-  ExpectStreamsClosed();
-}
-
-// Tests that if a Reset() is called after receiving a stream frame with the FIN
-// bit set from the remote side, both sides close down properly.
-TEST_F(P2PQuicTransportTest, StreamResetAfterReceivingFin) {
-  Initialize();
-  Connect();
-  SetupConnectedStreams();
-  CallbackRunLoop run_loop(runner());
-
-  EXPECT_CALL(*server_peer()->stream_delegate(),
-              OnDataReceived(_, /*fin=*/true))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  client_peer()->stream()->WriteData({}, /*fin=*/true);
-  run_loop.RunUntilCallbacksFired();
-
-  EXPECT_CALL(*client_peer()->stream_delegate(), OnRemoteReset())
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*server_peer()->stream_delegate(), OnRemoteReset()).Times(0);
-
-  // The server stream has received its FIN bit from the remote side, and
-  // responds with a Reset() to close everything down.
-  server_peer()->stream()->Reset();
-  run_loop.RunUntilCallbacksFired();
-
-  ExpectStreamsClosed();
-}
-
-// Tests that when datagrams are sent from each side they are received on the
-// other end.
-TEST_F(P2PQuicTransportTest, DatagramsSentReceivedOnRemoteSide) {
-  Initialize();
-  Connect();
-  CallbackRunLoop run_loop(runner());
-
-  // We should get the appropriate message on each end.
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(),
-              OnDatagramReceived(ElementsAreArray(kClientMessage)))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(),
-              OnDatagramReceived(ElementsAreArray(kServerMessage)))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  // The OnDatagramSent callback should fire for each datagram being sent.
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnDatagramSent())
-      .Times(1)
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*client_peer()->quic_transport_delegate(), OnDatagramSent())
-      .Times(1)
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  server_peer()->quic_transport()->SendDatagram(
-      VectorFromArray(kServerMessage));
-  client_peer()->quic_transport()->SendDatagram(
-      VectorFromArray(kClientMessage));
-
-  run_loop.RunUntilCallbacksFired();
-}
-
-// Tests that when data is sent on a stream it is received on the other end.
-TEST_F(P2PQuicTransportTest, StreamDataSentThenReceivedOnRemoteSide) {
-  Initialize();
-  Connect();
-  SetupConnectedStreams();
-  CallbackRunLoop run_loop(runner());
-
-  EXPECT_CALL(*server_peer()->stream_delegate(),
-              OnDataReceived(ElementsAreArray(kMessage), false))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*client_peer()->stream_delegate(),
-              OnWriteDataConsumed(base::size(kMessage)))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  client_peer()->stream()->WriteData(VectorFromArray(kMessage),
-                                     /* fin= */ false);
-  run_loop.RunUntilCallbacksFired();
-}
-
-// Tests that if both sides have a stream that sends data and FIN bit
-// they both close down for reading and writing properly.
-TEST_F(P2PQuicTransportTest, StreamDataSentWithFinClosesStreams) {
-  Initialize();
-  Connect();
-  SetupConnectedStreams();
-  CallbackRunLoop run_loop(runner());
-
-  EXPECT_CALL(*server_peer()->stream_delegate(),
-              OnDataReceived(VectorFromArray(kClientMessage), true))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*server_peer()->stream_delegate(),
-              OnWriteDataConsumed(base::size(kServerMessage)))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  EXPECT_CALL(*client_peer()->stream_delegate(),
-              OnDataReceived(ElementsAreArray(kServerMessage), true))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-  EXPECT_CALL(*client_peer()->stream_delegate(),
-              OnWriteDataConsumed(base::size(kClientMessage)))
-      .WillOnce(FireCallback(run_loop.CreateCallback()));
-
-  client_peer()->stream()->WriteData(VectorFromArray(kClientMessage),
-                                     /*fin=*/true);
-  server_peer()->stream()->WriteData(VectorFromArray(kServerMessage),
-                                     /*fin=*/true);
-  run_loop.RunUntilCallbacksFired();
-
-  ExpectStreamsClosed();
-}
-
-// Tests that the stats returned by the P2PQuicTransportImpl have the correct
-// number of incoming and outgoing streams.
-TEST_F(P2PQuicTransportTest, GetStatsForNumberOfStreams) {
-  Initialize();
-  Connect();
-
-  P2PQuicTransportStats client_stats_1 =
-      client_peer()->quic_transport()->GetStats();
-  EXPECT_EQ(0u, client_stats_1.num_incoming_streams_created);
-  EXPECT_EQ(0u, client_stats_1.num_outgoing_streams_created);
-  P2PQuicTransportStats server_stats_1 =
-      server_peer()->quic_transport()->GetStats();
-  EXPECT_EQ(0u, server_stats_1.num_incoming_streams_created);
-  EXPECT_EQ(0u, server_stats_1.num_outgoing_streams_created);
-
-  // Create a stream on the client side and send some data to trigger a stream
-  // creation on the remote side.
-  client_peer()->CreateStreamWithDelegate();
-  CallbackRunLoop run_loop(runner());
-  base::RepeatingCallback<void()> callback = run_loop.CreateCallback();
-  MockP2PQuicStreamDelegate server_stream_delegate;
-  EXPECT_CALL(*server_peer()->quic_transport_delegate(), OnStream(_))
-      .WillOnce(
-          Invoke([&callback, &server_stream_delegate](P2PQuicStream* stream) {
-            stream->SetDelegate(&server_stream_delegate);
-            callback.Run();
-          }));
-  client_peer()->stream()->WriteData(
-      VectorFromArray(kTriggerRemoteStreamPhrase),
-      /*fin=*/false);
-  run_loop.RunUntilCallbacksFired();
-
-  P2PQuicTransportStats client_stats_2 =
-      client_peer()->quic_transport()->GetStats();
-  EXPECT_EQ(0u, client_stats_2.num_incoming_streams_created);
-  EXPECT_EQ(1u, client_stats_2.num_outgoing_streams_created);
-  EXPECT_GT(client_stats_2.timestamp, client_stats_1.timestamp);
-  P2PQuicTransportStats server_stats_2 =
-      server_peer()->quic_transport()->GetStats();
-  EXPECT_EQ(1u, server_stats_2.num_incoming_streams_created);
-  EXPECT_EQ(0u, server_stats_2.num_outgoing_streams_created);
-  EXPECT_GT(server_stats_2.timestamp, server_stats_1.timestamp);
-}
-
-// P2PQuicTransport tests that use a fake quic::QuicConnection.
-class P2PQuicTransportMockConnectionTest : public testing::Test {
- public:
-  P2PQuicTransportMockConnectionTest() {
-    connection_helper_ = new quic::test::MockQuicConnectionHelper();
-    connection_ = new quic::test::MockQuicConnection(
-        connection_helper_, &alarm_factory_, quic::Perspective::IS_CLIENT);
-
-    rtc::scoped_refptr<rtc::RTCCertificate> certificate =
-        CreateTestCertificate();
-    P2PQuicTransportConfig config(quic::Perspective::IS_CLIENT, {certificate},
-                                  kTransportDelegateReadBufferSize,
-                                  kTransportWriteBufferSize);
-    quic::QuicConfig quic_config;
-    transport_ = std::make_unique<P2PQuicTransportImpl>(
-        &delegate_, &packet_transport_, config,
-        std::unique_ptr<quic::test::MockQuicConnectionHelper>(
-            connection_helper_),
-        std::unique_ptr<quic::test::MockQuicConnection>(connection_),
-        quic_config,
-        std::make_unique<P2PQuicCryptoConfigFactoryImpl>(&quic_random_),
-        std::make_unique<ConnectedCryptoClientStreamFactory>(), &clock_);
-    // Called once in P2PQuicTransportImpl::Start and once in the destructor.
-    EXPECT_CALL(packet_transport_, SetReceiveDelegate(transport())).Times(1);
-    EXPECT_CALL(packet_transport_, SetReceiveDelegate(nullptr)).Times(1);
-    // DCHECKS get hit when the clock is at 0.
-    connection_helper_->AdvanceTime(quic::QuicTime::Delta::FromSeconds(1));
-    transport_->Start(P2PQuicTransport::StartConfig("foobar"));
-  }
-
-  ~P2PQuicTransportMockConnectionTest() override {}
-
-  P2PQuicTransportImpl* transport() { return transport_.get(); }
-
-  MockP2PQuicTransportDelegate* delegate() { return &delegate_; }
-
-  quic::test::MockQuicConnection* connection() { return connection_; }
-
- private:
-  quic::MockClock clock_;
-  MockP2PQuicPacketTransport packet_transport_;
-  quic::test::MockRandom quic_random_;
-  quic::test::MockAlarmFactory alarm_factory_;
-  MockP2PQuicTransportDelegate delegate_;
-  std::unique_ptr<P2PQuicTransportImpl> transport_;
-  // Owned by the |transport_|.
-  quic::test::MockQuicConnection* connection_;
-  quic::test::MockQuicConnectionHelper* connection_helper_;
-};
-
-// Test that when a datagram is received it properly fires the
-// OnDatagramReceived function on the delegate.
-// Flaky on all platforms. See https://crbug.com/1071340
-TEST_F(P2PQuicTransportMockConnectionTest, DISABLED_OnDatagramReceived) {
-  EXPECT_TRUE(transport()->CanSendDatagram());
-  EXPECT_CALL(*delegate(), OnDatagramReceived(ElementsAreArray(kMessage)));
-  transport()->OnMessageReceived(quiche::QuicheStringPiece(
-      reinterpret_cast<const char*>(kMessage), sizeof(kMessage)));
-}
-
-// Test that when a datagram is sent that is properly fires the OnDatagramSent
-// function on the delegate.
-// Flaky on all platforms. See https://crbug.com/1071340
-TEST_F(P2PQuicTransportMockConnectionTest, DISABLED_OnDatagramSent) {
-  EXPECT_CALL(*connection(), SendMessage(_, _, _))
-      .WillOnce(Invoke([](quic::QuicMessageId message_id,
-                          quic::QuicMemSliceSpan message, bool flush) {
-        EXPECT_THAT(message.GetData(0), ElementsAreArray(kMessage));
-        return quic::MESSAGE_STATUS_SUCCESS;
-      }));
-  EXPECT_CALL(*delegate(), OnDatagramSent());
-
-  transport()->SendDatagram(VectorFromArray(kMessage));
-}
-
-// Test that when the quic::QuicConnection is congestion control blocked that
-// the datagram gets buffered and not sent.
-// Flaky on all platforms. See https://crbug.com/1071340
-TEST_F(P2PQuicTransportMockConnectionTest, DISABLED_DatagramNotSent) {
-  EXPECT_CALL(*connection(), SendMessage(_, _, _))
-      .WillOnce(Return(quic::MESSAGE_STATUS_BLOCKED));
-  EXPECT_CALL(*delegate(), OnDatagramSent()).Times(0);
-
-  transport()->SendDatagram(VectorFromArray(kMessage));
-}
-
-// Test that when datagrams are buffered they are later sent when the transport
-// is no longer congestion control blocked.
-// Flaky on all platforms. See https://crbug.com/1071340
-TEST_F(P2PQuicTransportMockConnectionTest, DISABLED_BufferedDatagramsSent) {
-  EXPECT_CALL(*connection(), SendMessage(_, _, _))
-      .WillOnce(Return(quic::MESSAGE_STATUS_BLOCKED));
-  transport()->SendDatagram(VectorFromArray(kMessage));
-  transport()->SendDatagram(VectorFromArray(kMessage2));
-
-  EXPECT_CALL(*delegate(), OnDatagramSent()).Times(2);
-  // Need to check equality with the function call matcher, instead of
-  // passing a lamda that checks equality in an Invoke as done in other tests.
-  EXPECT_CALL(*connection(),
-              SendMessage(_,
-                          ResultOf(
-                              [](quic::QuicMemSliceSpan message) {
-                                return message.GetData(0);
-                              },
-                              ElementsAreArray(kMessage)),
-                          _))
-      .WillOnce(Return(quic::MESSAGE_STATUS_SUCCESS));
-  EXPECT_CALL(*connection(),
-              SendMessage(_,
-                          ResultOf(
-                              [](quic::QuicMemSliceSpan message) {
-                                return message.GetData(0);
-                              },
-                              ElementsAreArray(kMessage2)),
-                          _))
-      .WillOnce(Return(quic::MESSAGE_STATUS_SUCCESS));
-
-  transport()->OnCanWrite();
-}
-
-// Tests the following scenario:
-// -Write blocked - datagrams are buffered.
-// -Write unblocked - send buffered datagrams.
-// -Write blocked - keep datagrams buffered.
-// Flaky on all platforms. See https://crbug.com/1071340
-TEST_F(P2PQuicTransportMockConnectionTest,
-       DISABLED_BufferedDatagramRemainBuffered) {
-  EXPECT_CALL(*connection(), SendMessage(_, _, _))
-      .WillOnce(Return(quic::MESSAGE_STATUS_BLOCKED));
-  transport()->SendDatagram(VectorFromArray(kMessage));
-  transport()->SendDatagram(VectorFromArray(kMessage2));
-
-  // The first datagram gets sent off after becoming write unblocked, while the
-  // second datagram is buffered.
-  EXPECT_CALL(*connection(),
-              SendMessage(_,
-                          ResultOf(
-                              [](quic::QuicMemSliceSpan message) {
-                                return message.GetData(0);
-                              },
-                              ElementsAreArray(kMessage)),
-                          _))
-      .WillOnce(Return(quic::MESSAGE_STATUS_SUCCESS));
-  EXPECT_CALL(*connection(),
-              SendMessage(_,
-                          ResultOf(
-                              [](quic::QuicMemSliceSpan message) {
-                                return message.GetData(0);
-                              },
-                              ElementsAreArray(kMessage2)),
-                          _))
-      .WillOnce(Return(quic::MESSAGE_STATUS_BLOCKED));
-  // No callback for the second datagram, as it is still buffered.
-  EXPECT_CALL(*delegate(), OnDatagramSent()).Times(1);
-
-  transport()->OnCanWrite();
-
-  // Sending another datagram at this point should just buffer it.
-  EXPECT_CALL(*connection(), SendMessage(_, _, _)).Times(0);
-  transport()->SendDatagram(VectorFromArray(kMessage));
-}
-
-// Flaky on all platforms. See https://crbug.com/1071340
-TEST_F(P2PQuicTransportMockConnectionTest, DISABLED_LostDatagramUpdatesStats) {
-  // The ID the quic::QuicSession will assign to the datagram that is used for
-  // callbacks, like OnDatagramLost.
-  uint32_t datagram_id;
-  EXPECT_CALL(*connection(), SendMessage(_, _, _))
-      .WillOnce(
-          Invoke([&datagram_id](quic::QuicMessageId message_id,
-                                quic::QuicMemSliceSpan message, bool flush) {
-            datagram_id = message_id;
-            return quic::MESSAGE_STATUS_SUCCESS;
-          }));
-  EXPECT_CALL(*delegate(), OnDatagramSent()).Times(1);
-  transport()->SendDatagram(VectorFromArray(kMessage));
-
-  EXPECT_EQ(0u, transport()->GetStats().num_datagrams_lost);
-  transport()->OnMessageLost(datagram_id);
-
-  EXPECT_EQ(1u, transport()->GetStats().num_datagrams_lost);
-}
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.cc b/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.cc
deleted file mode 100644
index 60230d5..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.cc
+++ /dev/null
@@ -1,84 +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/modules/peerconnection/adapters/quic_packet_transport_adapter.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
-
-namespace blink {
-
-QuicPacketTransportAdapter::QuicPacketTransportAdapter(
-    cricket::IceTransportInternal* ice_transport)
-    : ice_transport_(ice_transport) {
-  DCHECK(ice_transport_);
-  ice_transport_->SignalReadPacket.connect(
-      this, &QuicPacketTransportAdapter::OnReadPacket);
-  ice_transport_->SignalReadyToSend.connect(
-      this, &QuicPacketTransportAdapter::OnReadyToSend);
-}
-
-QuicPacketTransportAdapter::~QuicPacketTransportAdapter() {
-  // Caller is responsible for unsetting the write observer and receive
-  // delegate before destroying this.
-  DCHECK(!write_observer_);
-  DCHECK(!receive_delegate_);
-}
-
-int QuicPacketTransportAdapter::WritePacket(const QuicPacket& packet) {
-  rtc::PacketOptions options;
-  options.packet_id = packet.packet_number;
-  int flags = 0;
-  return ice_transport_->SendPacket(packet.buffer, packet.buf_len, options,
-                                    flags);
-}
-
-void QuicPacketTransportAdapter::SetReceiveDelegate(
-    ReceiveDelegate* receive_delegate) {
-  receive_delegate_ = receive_delegate;
-  if (!cached_client_hello_packet_.empty() && receive_delegate_) {
-    // If a CHLO was received early, give it to the delegate.
-    receive_delegate_->OnPacketDataReceived(cached_client_hello_packet_.c_str(),
-                                            cached_client_hello_packet_.size());
-    cached_client_hello_packet_.clear();
-  }
-}
-
-void QuicPacketTransportAdapter::SetWriteObserver(
-    WriteObserver* write_observer) {
-  write_observer_ = write_observer;
-}
-
-bool QuicPacketTransportAdapter::Writable() {
-  return ice_transport_->writable();
-}
-
-// IceTransportInternal callbacks.
-void QuicPacketTransportAdapter::OnReadPacket(
-    rtc::PacketTransportInternal* packet_transport,
-    const char* buffer,
-    size_t buffer_length,
-    const int64_t& packet_time,
-    int flags) {
-  DCHECK_EQ(packet_transport, ice_transport_);
-  if (!receive_delegate_) {
-    // Cache the early CHLO from the QUIC handshake.
-    // The CHLO is stored in a single packet. All packets before the most recent
-    // can be discarded because they are no longer relevant, since at this point
-    // we have not responded. The packet could also be a connection close packet
-    // in the case that QUIC times out waiting for a response.
-    cached_client_hello_packet_ = std::string(buffer, buffer_length);
-    return;
-  }
-  receive_delegate_->OnPacketDataReceived(buffer, buffer_length);
-}
-
-void QuicPacketTransportAdapter::OnReadyToSend(
-    rtc::PacketTransportInternal* packet_transport) {
-  DCHECK_EQ(packet_transport, ice_transport_);
-  if (!write_observer_) {
-    return;
-  }
-  write_observer_->OnCanWrite();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h b/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h
deleted file mode 100644
index 97689998..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter.h
+++ /dev/null
@@ -1,56 +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_MODULES_PEERCONNECTION_ADAPTERS_QUIC_PACKET_TRANSPORT_ADAPTER_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_PACKET_TRANSPORT_ADAPTER_H_
-
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
-#include "third_party/webrtc/p2p/base/p2p_transport_channel.h"
-
-namespace blink {
-
-// Implementation of P2PQuicPacketTransport backed by a IceTransportInternal.
-// It adapts the underlying ICE transport to be used with the QUIC library.
-// This does not filter packets. It requires that the IceTransportInternal is
-// only being used for QUIC packets.
-class MODULES_EXPORT QuicPacketTransportAdapter : public P2PQuicPacketTransport,
-                                                  public sigslot::has_slots<> {
- public:
-  QuicPacketTransportAdapter(
-      cricket::IceTransportInternal* p2p_transport_channel);
-
-  ~QuicPacketTransportAdapter() override;
-
-  // P2PQuicPacketTransport overrides.
-  int WritePacket(const QuicPacket& packet) override;
-  void SetReceiveDelegate(ReceiveDelegate* receive_delegate) override;
-  void SetWriteObserver(WriteObserver* write_observer) override;
-  bool Writable() override;
-
- private:
-  // IceTransportInternal callbacks.
-  void OnReadPacket(rtc::PacketTransportInternal* packet_transport,
-                    const char* buffer,
-                    size_t buffer_length,
-                    const int64_t& packet_time,
-                    int flags);
-
-  void OnReadyToSend(rtc::PacketTransportInternal* packet_transport);
-
-  // Owned by the IceTransportAdapter and will outlive this object.
-  cricket::IceTransportInternal* ice_transport_;
-  // The ReceiveDelegate and WriteObserver must be unset before
-  // this object is destroyed.
-  ReceiveDelegate* receive_delegate_ = nullptr;
-  WriteObserver* write_observer_ = nullptr;
-  // If the CHLO arrives early it is cached. This can occur if the QUIC
-  // handshake begins on the client side before the remote parameters are
-  // received on the server side.
-  std::string cached_client_hello_packet_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_PACKET_TRANSPORT_ADAPTER_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter_test.cc b/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter_test.cc
deleted file mode 100644
index 2c3785e..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_packet_transport_adapter_test.cc
+++ /dev/null
@@ -1,126 +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/modules/peerconnection/adapters/quic_packet_transport_adapter.h"
-
-#include "net/test/gtest_util.h"
-#include "third_party/webrtc/p2p/base/mock_ice_transport.h"
-
-namespace blink {
-
-namespace {
-using testing::StrEq;
-}  // namespace
-
-class MockWriteObserver : public P2PQuicPacketTransport::WriteObserver {
- public:
-  MOCK_METHOD0(OnCanWrite, void());
-};
-
-class MockReceiveDelegate : public P2PQuicPacketTransport::ReceiveDelegate {
- public:
-  MOCK_METHOD2(OnPacketDataReceived, void(const char*, size_t));
-};
-
-class QuicPacketTransportAdapterTest : public testing::Test {
- public:
-  QuicPacketTransportAdapterTest()
-      : quic_packet_transport_adapter_(&mock_ice_transport_) {}
-
-  ~QuicPacketTransportAdapterTest() override {
-    quic_packet_transport_adapter_.SetReceiveDelegate(nullptr);
-    quic_packet_transport_adapter_.SetWriteObserver(nullptr);
-  }
-
-  cricket::MockIceTransport* mock_ice_transport() {
-    return &mock_ice_transport_;
-  }
-
-  QuicPacketTransportAdapter* quic_packet_transport_adapter() {
-    return &quic_packet_transport_adapter_;
-  }
-
- private:
-  cricket::MockIceTransport mock_ice_transport_;
-  QuicPacketTransportAdapter quic_packet_transport_adapter_;
-};
-
-// Tests that when the underlying ICE transport is ready to send data that
-// the QuicPacketTransportAdapter will tell the WriteObserver.
-TEST_F(QuicPacketTransportAdapterTest, IceTransportReadyTriggersCanWrite) {
-  MockWriteObserver mock_write_observer;
-  quic_packet_transport_adapter()->SetWriteObserver(&mock_write_observer);
-
-  EXPECT_CALL(mock_write_observer, OnCanWrite());
-
-  mock_ice_transport()->SignalReadyToSend(mock_ice_transport());
-}
-
-// Tests that writing a packet to the QuicPacketTransportAdapter will write
-// the data to the underlying ICE transport.
-TEST_F(QuicPacketTransportAdapterTest, WritePacketWritesToIceTransport) {
-  std::string packet("hola");
-
-  EXPECT_CALL(*mock_ice_transport(),
-              SendPacket(StrEq(packet), packet.size(), _, _));
-
-  P2PQuicPacketTransport::QuicPacket quic_packet;
-  quic_packet.buffer = packet.c_str();
-  quic_packet.buf_len = packet.size();
-  quic_packet_transport_adapter()->WritePacket(quic_packet);
-}
-
-// Tests that when the underlying ICE transport receives data it it
-// is passed appropriately to the ReceiveDelegate.
-TEST_F(QuicPacketTransportAdapterTest, ReadPacketGivenToReceiveDelegate) {
-  MockReceiveDelegate mock_receive_delegate;
-  quic_packet_transport_adapter()->SetReceiveDelegate(&mock_receive_delegate);
-
-  std::string packet("hola");
-  EXPECT_CALL(mock_receive_delegate,
-              OnPacketDataReceived(StrEq(packet), packet.size()));
-
-  mock_ice_transport()->SignalReadPacket(mock_ice_transport(), packet.c_str(),
-                                         packet.size(), 0, 0);
-}
-
-// Tests that the most recent packet that was received before the
-// ReceiveDelegate is hooked up will be given to the ReceiveDelegate once it is
-// set. This is used as an optimization in the case that a QUIC CHLO is received
-// early.
-TEST_F(QuicPacketTransportAdapterTest,
-       MostRecentCachedPacketGivenToReceiveDelegate) {
-  std::string packet("hola");
-  std::string latest_packet("bonjour");
-
-  mock_ice_transport()->SignalReadPacket(mock_ice_transport(), packet.c_str(),
-                                         packet.size(), 0, 0);
-  mock_ice_transport()->SignalReadPacket(
-      mock_ice_transport(), latest_packet.c_str(), latest_packet.size(), 0, 0);
-
-  // The receive delegate is set after packets have been received.
-  MockReceiveDelegate mock_receive_delegate;
-  EXPECT_CALL(mock_receive_delegate,
-              OnPacketDataReceived(StrEq(latest_packet), latest_packet.size()));
-
-  quic_packet_transport_adapter()->SetReceiveDelegate(&mock_receive_delegate);
-}
-
-// Tests that the cached packet is not reused once it has been handed off to
-// a set ReceiveDelegate.
-TEST_F(QuicPacketTransportAdapterTest, CachedPacketIsNotReused) {
-  std::string packet("hola");
-  mock_ice_transport()->SignalReadPacket(mock_ice_transport(), packet.c_str(),
-                                         packet.size(), 0, 0);
-
-  MockReceiveDelegate mock_receive_delegate;
-  EXPECT_CALL(mock_receive_delegate, OnPacketDataReceived(_, _));
-  quic_packet_transport_adapter()->SetReceiveDelegate(&mock_receive_delegate);
-
-  MockReceiveDelegate latest_receive_delegate;
-  EXPECT_CALL(latest_receive_delegate, OnPacketDataReceived(_, _)).Times(0);
-  quic_packet_transport_adapter()->SetReceiveDelegate(&latest_receive_delegate);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc b/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc
deleted file mode 100644
index d701abd..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.cc
+++ /dev/null
@@ -1,107 +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/modules/peerconnection/adapters/quic_stream_host.h"
-
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
-#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-
-namespace blink {
-
-QuicStreamHost::QuicStreamHost() {
-  DETACH_FROM_THREAD(thread_checker_);
-}
-
-QuicStreamHost::~QuicStreamHost() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void QuicStreamHost::set_proxy(base::WeakPtr<QuicStreamProxy> stream_proxy) {
-  DETACH_FROM_THREAD(thread_checker_);
-  stream_proxy_ = stream_proxy;
-}
-
-void QuicStreamHost::Initialize(QuicTransportHost* transport_host,
-                                P2PQuicStream* p2p_stream) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(transport_host);
-  DCHECK(p2p_stream);
-  transport_host_ = transport_host;
-  p2p_stream_ = p2p_stream;
-  p2p_stream_->SetDelegate(this);
-}
-
-scoped_refptr<base::SingleThreadTaskRunner> QuicStreamHost::proxy_thread()
-    const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(transport_host_);
-  return transport_host_->proxy_thread();
-}
-
-void QuicStreamHost::Reset() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(p2p_stream_);
-  p2p_stream_->Reset();
-  Delete();
-}
-
-void QuicStreamHost::MarkReceivedDataConsumed(uint32_t amount) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(p2p_stream_);
-  p2p_stream_->MarkReceivedDataConsumed(amount);
-}
-
-void QuicStreamHost::WriteData(Vector<uint8_t> data, bool fin) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(p2p_stream_);
-  p2p_stream_->WriteData(std::move(data), fin);
-  if (fin) {
-    DCHECK(writable_);
-    writable_ = false;
-    if (!readable_ && !writable_) {
-      Delete();
-    }
-  }
-}
-
-void QuicStreamHost::OnRemoteReset() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  PostCrossThreadTask(
-      *proxy_thread(), FROM_HERE,
-      CrossThreadBindOnce(&QuicStreamProxy::OnRemoteReset, stream_proxy_));
-  Delete();
-}
-
-void QuicStreamHost::OnDataReceived(Vector<uint8_t> data, bool fin) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  PostCrossThreadTask(*proxy_thread(), FROM_HERE,
-                      CrossThreadBindOnce(&QuicStreamProxy::OnDataReceived,
-                                          stream_proxy_, std::move(data), fin));
-  if (fin) {
-    readable_ = false;
-    if (!readable_ && !writable_) {
-      Delete();
-    }
-  }
-}
-
-void QuicStreamHost::OnWriteDataConsumed(uint32_t amount) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  PostCrossThreadTask(*proxy_thread(), FROM_HERE,
-                      CrossThreadBindOnce(&QuicStreamProxy::OnWriteDataConsumed,
-                                          stream_proxy_, amount));
-}
-
-void QuicStreamHost::Delete() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(transport_host_);
-  p2p_stream_->SetDelegate(nullptr);
-  // OnRemoveStream will delete |this|.
-  transport_host_->OnRemoveStream(this);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h b/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h
deleted file mode 100644
index 4607b6c..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h
+++ /dev/null
@@ -1,88 +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_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_HOST_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_HOST_H_
-
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_checker.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h"
-
-namespace blink {
-
-class QuicStreamProxy;
-class QuicTransportHost;
-
-// This class is the host side correspondent to the QuicStreamProxy. See the
-// QuicStreamProxy documentation for background. This class lives on the host
-// thread and proxies calls between the QuicStreamProxy and the P2PQuicStream
-// (which is single-threaded).
-//
-// The QuicStreamHost is owned by the QuicTransportHost and constructed when
-// either a new local QUIC stream is created or when a remote QUIC stream has
-// been created. The stream host will be deleted in the following circumstances:
-// 1) Reset() is called.
-// 2) OnRemoteReset() is indicated.
-// 3) Finish() and OnRemoteFinish() have been called.
-// The QuicStreamHost will instruct the QuicTransportHost to delete it when any
-// condition has been met.
-//
-// Since the QuicStreamHost can be constructed from either the proxy or host
-// thread, initialization happens in three steps:
-// 1) QuicStreamHost is constructed.
-// 2) set_proxy is called when a WeakPtr to the corresponding proxy-thread
-//    object.
-// 3) Initialize is called on the host thread.
-class QuicStreamHost final : public base::SupportsWeakPtr<QuicStreamHost>,
-                             public P2PQuicStream::Delegate {
- public:
-  QuicStreamHost();
-  ~QuicStreamHost() override;
-
-  // Sets a WeakPtr to the corresponding QuicStreamProxy. This is valid on
-  // either the proxy or host thread. Should happen right after construction.
-  void set_proxy(base::WeakPtr<QuicStreamProxy> stream_proxy);
-
-  // Initializes the QuicStreamHost. Must be called on the host thread.
-  // |transport_host| must outlive this object.
-  void Initialize(QuicTransportHost* transport_host, P2PQuicStream* p2p_stream);
-
-  // The remaining methods can only be called from the host thread and must be
-  // preceded by Initialize().
-
-  scoped_refptr<base::SingleThreadTaskRunner> proxy_thread() const;
-
-  void Reset();
-  void MarkReceivedDataConsumed(uint32_t amount);
-  void WriteData(Vector<uint8_t> data, bool fin);
-
- private:
-  // Instruct the QuicTransportHost to remove and delete this stream host.
-  void Delete();
-
-  // P2PQuicStream::Delegate overrides.
-  void OnRemoteReset() override;
-  void OnDataReceived(Vector<uint8_t> data, bool fin) override;
-  void OnWriteDataConsumed(uint32_t amount) override;
-
-  // Up reference. Owned by QuicTransportProxy.
-  QuicTransportHost* transport_host_ = nullptr;
-  // Forward reference. Owned by P2PQuicTransport.
-  P2PQuicStream* p2p_stream_ = nullptr;
-  // Back reference. Owned by QuicTransportProxy.
-  base::WeakPtr<QuicStreamProxy> stream_proxy_;
-
-  // |readable_| transitions to false when OnDataReceived(_, true) is called.
-  bool readable_ = true;
-  // |writable_| transitions to false when WriteData(_, true) is called.
-  bool writable_ = true;
-
-  THREAD_CHECKER(thread_checker_);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_HOST_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.cc b/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.cc
deleted file mode 100644
index fa1f566..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.cc
+++ /dev/null
@@ -1,111 +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/modules/peerconnection/adapters/quic_stream_proxy.h"
-
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
-#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-
-namespace blink {
-
-QuicStreamProxy::QuicStreamProxy() {
-  DETACH_FROM_THREAD(thread_checker_);
-}
-
-QuicStreamProxy::~QuicStreamProxy() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void QuicStreamProxy::set_host(base::WeakPtr<QuicStreamHost> stream_host) {
-  DETACH_FROM_THREAD(thread_checker_);
-  stream_host_ = stream_host;
-}
-
-void QuicStreamProxy::Initialize(QuicTransportProxy* transport_proxy) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(transport_proxy);
-  transport_proxy_ = transport_proxy;
-}
-
-void QuicStreamProxy::set_delegate(Delegate* delegate) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(delegate);
-  delegate_ = delegate;
-}
-
-scoped_refptr<base::SingleThreadTaskRunner> QuicStreamProxy::host_thread()
-    const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(transport_proxy_);
-  return transport_proxy_->host_thread();
-}
-
-void QuicStreamProxy::Reset() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  PostCrossThreadTask(
-      *host_thread(), FROM_HERE,
-      CrossThreadBindOnce(&QuicStreamHost::Reset, stream_host_));
-  Delete();
-}
-
-void QuicStreamProxy::MarkReceivedDataConsumed(uint32_t amount) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  PostCrossThreadTask(
-      *host_thread(), FROM_HERE,
-      CrossThreadBindOnce(&QuicStreamHost::MarkReceivedDataConsumed,
-                          stream_host_, amount));
-}
-
-void QuicStreamProxy::WriteData(Vector<uint8_t> data, bool fin) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  PostCrossThreadTask(*host_thread(), FROM_HERE,
-                      CrossThreadBindOnce(&QuicStreamHost::WriteData,
-                                          stream_host_, std::move(data), fin));
-  if (fin) {
-    writable_ = false;
-    if (!readable_ && !writable_) {
-      Delete();
-    }
-  }
-}
-
-void QuicStreamProxy::OnRemoteReset() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(delegate_);
-  // Need to copy the |delegate_| member since Delete() will destroy |this|.
-  Delegate* delegate_copy = delegate_;
-  Delete();
-  delegate_copy->OnRemoteReset();
-}
-
-void QuicStreamProxy::OnDataReceived(Vector<uint8_t> data, bool fin) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(delegate_);
-  // Need to copy the |delegate_| member since Delete() will destroy |this|.
-  Delegate* delegate_copy = delegate_;
-  if (fin) {
-    readable_ = false;
-    if (!readable_ && !writable_) {
-      Delete();
-    }
-  }
-  delegate_copy->OnDataReceived(std::move(data), fin);
-}
-
-void QuicStreamProxy::OnWriteDataConsumed(uint32_t amount) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(delegate_);
-  delegate_->OnWriteDataConsumed(amount);
-}
-
-void QuicStreamProxy::Delete() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // OnRemoveStream will delete |this|.
-  transport_proxy_->OnRemoveStream(this);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h b/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h
deleted file mode 100644
index 5881aef8..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h
+++ /dev/null
@@ -1,103 +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_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_PROXY_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_PROXY_H_
-
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_checker.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-class QuicStreamHost;
-class QuicTransportProxy;
-
-// This class allows interactions with a QUIC stream that runs on a thread
-// different from which it is controlled. All interactions with the QUIC
-// implementation happen asynchronously.
-//
-// The QuicStreamProxy is owned by the QuicTransportProxy and constructed when
-// either a new local QUIC stream is created or when a remote QUIC stream has
-// been created. The stream proxy will be deleted in the following
-// circumstances:
-// 1) Reset() is called.
-// 2) OnRemoteReset() is indicated.
-// 3) Finish() and OnRemoteFinish() have been called.
-// The client is responsible for knowing when any of these conditions have been
-// met and clearing its reference accordingly.
-//
-// Since the QuicStreamProxy can be constructed from either the proxy or host
-// thread, initialization happens in four steps:
-// 1) QuicStreamProxy is constructed.
-// 2) set_host is called with a WeakPtr to the corresponding host-thread object.
-// 3) Initialize is called on the proxy thread.
-// 4) set_delegate is called on the proxy thread.
-class QuicStreamProxy final : public base::SupportsWeakPtr<QuicStreamProxy> {
- public:
-  class Delegate {
-   public:
-    virtual ~Delegate() = default;
-
-    // Called when the remote side resets the stream.
-    virtual void OnRemoteReset() {}
-    // Called when the remote side receives data and/or the finish bit.
-    virtual void OnDataReceived(Vector<uint8_t> data, bool fin) {}
-    // Called when data written with WriteData() has been consumed by QUIC.
-    virtual void OnWriteDataConsumed(uint32_t amount) {}
-  };
-
-  QuicStreamProxy();
-  ~QuicStreamProxy();
-
-  // Sets a WeakPtr to the corresponding QuicStreamHost. This is valid on either
-  // the proxy or host thread. Should happen right after construction.
-  void set_host(base::WeakPtr<QuicStreamHost> stream_host);
-
-  // Initializes the QuicStreamProxy. Must be called on the proxy thread.
-  // |transport_proxy| must outlive this object.
-  void Initialize(QuicTransportProxy* transport_proxy);
-
-  // Sets the delegate for receiving remote callbacks.
-  void set_delegate(Delegate* delegate);
-
-  // The remaining methods can only be called from the proxy thread and must
-  // be preceded by Initialize().
-
-  scoped_refptr<base::SingleThreadTaskRunner> host_thread() const;
-
-  void Reset();
-  void MarkReceivedDataConsumed(uint32_t amount);
-  void WriteData(Vector<uint8_t> data, bool fin);
-
- private:
-  // Instruct the QuicTransportProxy to remove and delete this stream proxy.
-  void Delete();
-
-  // Callbacks from QuicStreamHost.
-  friend class QuicStreamHost;
-  void OnRemoteReset();
-  void OnDataReceived(Vector<uint8_t> data, bool fin);
-  void OnWriteDataConsumed(uint32_t amount);
-
-  // Up reference. Owned by the QuicTransportProxy client.
-  QuicTransportProxy* transport_proxy_ = nullptr;
-  // Forward reference. Owned by the QuicTransportHost.
-  base::WeakPtr<QuicStreamHost> stream_host_;
-  // Back reference. Owned by the RTCQuicTransport.
-  Delegate* delegate_ = nullptr;
-
-  // |readable_| transitions to false when OnDataReceived(_, true) is called.
-  bool readable_ = true;
-  // |writable_| transitions to false when WriteData(_, true) is called.
-  bool writable_ = true;
-
-  THREAD_CHECKER(thread_checker_);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_STREAM_PROXY_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc
deleted file mode 100644
index 69d8565..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.cc
+++ /dev/null
@@ -1,167 +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/modules/peerconnection/adapters/quic_transport_host.h"
-
-#include <utility>
-
-#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
-#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-
-namespace blink {
-
-QuicTransportHost::QuicTransportHost(
-    base::WeakPtr<QuicTransportProxy> proxy,
-    std::unique_ptr<P2PQuicTransportFactory> quic_transport_factory)
-    : quic_transport_factory_(std::move(quic_transport_factory)),
-      proxy_(std::move(proxy)) {
-  DETACH_FROM_THREAD(thread_checker_);
-  DCHECK(quic_transport_factory_);
-  DCHECK(proxy_);
-}
-
-QuicTransportHost::~QuicTransportHost() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // If the TaskRunner this is getting initialized on is destroyed before
-  // Initialize is called then |ice_transport_host_| may still be null.
-  if (ice_transport_host_) {
-    ice_transport_host_->DisconnectConsumer(this);
-  }
-}
-
-void QuicTransportHost::Initialize(IceTransportHost* ice_transport_host,
-                                   const P2PQuicTransportConfig& config) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(ice_transport_host);
-  DCHECK(!ice_transport_host_);
-  ice_transport_host_ = ice_transport_host;
-  IceTransportAdapter* ice_transport_adapter =
-      ice_transport_host_->ConnectConsumer(this);
-  quic_transport_ = quic_transport_factory_->CreateQuicTransport(
-      /*delegate=*/this, ice_transport_adapter->packet_transport(), config);
-}
-
-scoped_refptr<base::SingleThreadTaskRunner> QuicTransportHost::proxy_thread()
-    const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return ice_transport_host_->proxy_thread();
-}
-
-scoped_refptr<base::SingleThreadTaskRunner> QuicTransportHost::host_thread()
-    const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return ice_transport_host_->host_thread();
-}
-
-void QuicTransportHost::Start(P2PQuicTransport::StartConfig config) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  quic_transport_->Start(std::move(config));
-}
-
-void QuicTransportHost::Stop() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  quic_transport_->Stop();
-}
-
-void QuicTransportHost::CreateStream(
-    std::unique_ptr<QuicStreamHost> stream_host) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  P2PQuicStream* p2p_stream = quic_transport_->CreateStream();
-  stream_host->Initialize(this, p2p_stream);
-  stream_hosts_.insert(stream_host.get(), std::move(stream_host));
-}
-
-void QuicTransportHost::SendDatagram(Vector<uint8_t> datagram) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  quic_transport_->SendDatagram(std::move(datagram));
-}
-
-void QuicTransportHost::GetStats(uint32_t request_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  P2PQuicTransportStats stats = quic_transport_->GetStats();
-  PostCrossThreadTask(*proxy_thread(), FROM_HERE,
-                      CrossThreadBindOnce(&QuicTransportProxy::OnStats, proxy_,
-                                          request_id, stats));
-}
-
-void QuicTransportHost::OnRemoveStream(QuicStreamHost* stream_host_to_remove) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  auto it = stream_hosts_.find(stream_host_to_remove);
-  DCHECK(it != stream_hosts_.end());
-  stream_hosts_.erase(it);
-}
-
-void QuicTransportHost::OnRemoteStopped() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  stream_hosts_.clear();
-  PostCrossThreadTask(
-      *proxy_thread(), FROM_HERE,
-      CrossThreadBindOnce(&QuicTransportProxy::OnRemoteStopped, proxy_));
-}
-
-void QuicTransportHost::OnConnectionFailed(const std::string& error_details,
-                                           bool from_remote) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  stream_hosts_.clear();
-  PostCrossThreadTask(
-      *proxy_thread(), FROM_HERE,
-      CrossThreadBindOnce(&QuicTransportProxy::OnConnectionFailed, proxy_,
-                          error_details, from_remote));
-}
-
-void QuicTransportHost::OnConnected(P2PQuicNegotiatedParams negotiated_params) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  PostCrossThreadTask(*proxy_thread(), FROM_HERE,
-                      CrossThreadBindOnce(&QuicTransportProxy::OnConnected,
-                                          proxy_, negotiated_params));
-}
-
-void QuicTransportHost::OnStream(P2PQuicStream* p2p_stream) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(p2p_stream);
-
-  auto stream_proxy = std::make_unique<QuicStreamProxy>();
-  auto stream_host = std::make_unique<QuicStreamHost>();
-  stream_proxy->set_host(stream_host->AsWeakPtr());
-  stream_host->set_proxy(stream_proxy->AsWeakPtr());
-
-  stream_host->Initialize(this, p2p_stream);
-
-  stream_hosts_.insert(stream_host.get(), std::move(stream_host));
-
-  PostCrossThreadTask(
-      *proxy_thread(), FROM_HERE,
-      CrossThreadBindOnce(&QuicTransportProxy::OnStream, proxy_,
-                          WTF::Passed(std::move(stream_proxy))));
-}
-
-void QuicTransportHost::OnDatagramSent() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  PostCrossThreadTask(
-      *proxy_thread(), FROM_HERE,
-      CrossThreadBindOnce(&QuicTransportProxy::OnDatagramSent, proxy_));
-}
-
-void QuicTransportHost::OnDatagramReceived(Vector<uint8_t> datagram) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  PostCrossThreadTask(
-      *proxy_thread(), FROM_HERE,
-      CrossThreadBindOnce(&QuicTransportProxy::OnDatagramReceived, proxy_,
-                          std::move(datagram)));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h
deleted file mode 100644
index bf6fd6c0..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h
+++ /dev/null
@@ -1,91 +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_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_HOST_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_HOST_H_
-
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_checker.h"
-#include "net/third_party/quiche/src/quic/core/quic_types.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-
-namespace blink {
-
-class IceTransportHost;
-class QuicStreamHost;
-class QuicTransportProxy;
-
-// The host class is the host side correspondent to the QuicTransportProxy. See
-// the QuicTransportProxy documentation for background. This class lives on the
-// host thread and proxies calls between the QuicTransportProxy and the
-// P2PQuicTransport (which is single-threaded).
-//
-//        proxy thread                                host thread
-// +-----------------------+             +-----------------------------------+
-// |                       |             |                                   |
-// |        <-> ICE Proxy  |  =========> |  ICE Host <-> P2PTransportChannel |
-// |               ^       |  <--------- |     ^                ^            |
-// | client        |       |             |     |                |            |
-// |               v       |             |     v                v            |
-// |        <-> QUIC Proxy |  =========> | QUIC Host <-> P2PQuicTransport    |
-// |                       |  <--------- |                                   |
-// +-----------------------+             +-----------------------------------+
-//
-// The QuicTransportHost connects to the underlying IceTransportHost in
-// Initialize and disconnects in the destructor. The IceTransportHost must
-// outlive the QuicTransportHost.
-//
-// The Host can be constructed on any thread but after that point all methods
-// must be called on the host thread.
-class QuicTransportHost final : public P2PQuicTransport::Delegate {
- public:
-  QuicTransportHost(
-      base::WeakPtr<QuicTransportProxy> transport_proxy,
-      std::unique_ptr<P2PQuicTransportFactory> quic_transport_factory);
-  ~QuicTransportHost() override;
-
-  void Initialize(IceTransportHost* ice_transport_host,
-                  const P2PQuicTransportConfig& config);
-
-  scoped_refptr<base::SingleThreadTaskRunner> proxy_thread() const;
-  scoped_refptr<base::SingleThreadTaskRunner> host_thread() const;
-
-  void Start(P2PQuicTransport::StartConfig config);
-  void Stop();
-
-  void CreateStream(std::unique_ptr<QuicStreamHost> stream_host);
-
-  void SendDatagram(Vector<uint8_t> datagram);
-
-  void GetStats(uint32_t request_id);
-
-  // QuicStreamHost callbacks.
-  void OnRemoveStream(QuicStreamHost* stream_host_to_remove);
-
- private:
-  // P2PQuicTransport::Delegate overrides.
-  void OnRemoteStopped() override;
-  void OnConnectionFailed(const std::string& error_details,
-                          bool from_remote) override;
-  void OnConnected(P2PQuicNegotiatedParams negotiated_params) override;
-  void OnStream(P2PQuicStream* stream) override;
-  void OnDatagramSent() override;
-  void OnDatagramReceived(Vector<uint8_t> datagram) override;
-
-  std::unique_ptr<P2PQuicTransportFactory> quic_transport_factory_;
-  std::unique_ptr<P2PQuicTransport> quic_transport_;
-  base::WeakPtr<QuicTransportProxy> proxy_;
-  IceTransportHost* ice_transport_host_ = nullptr;
-  HashMap<QuicStreamHost*, std::unique_ptr<QuicStreamHost>> stream_hosts_;
-
-  THREAD_CHECKER(thread_checker_);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_HOST_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
deleted file mode 100644
index 3af56de..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.cc
+++ /dev/null
@@ -1,184 +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/modules/peerconnection/adapters/quic_transport_proxy.h"
-
-#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_host.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_host.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
-#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-
-namespace blink {
-
-QuicTransportProxy::QuicTransportProxy(
-    Delegate* delegate,
-    IceTransportProxy* ice_transport_proxy,
-    std::unique_ptr<P2PQuicTransportFactory> quic_transport_factory,
-    const P2PQuicTransportConfig& config)
-    : host_(nullptr,
-            base::OnTaskRunnerDeleter(ice_transport_proxy->host_thread())),
-      delegate_(delegate),
-      ice_transport_proxy_(ice_transport_proxy) {
-  DCHECK(delegate_);
-  DCHECK(ice_transport_proxy_);
-  scoped_refptr<base::SingleThreadTaskRunner> proxy_thread =
-      ice_transport_proxy->proxy_thread();
-  DCHECK(proxy_thread->BelongsToCurrentThread());
-  // Wait to initialize the host until the weak_ptr_factory_ is initialized.
-  // The QuicTransportHost is constructed on the proxy thread but should only be
-  // interacted with via PostTask to the host thread. The OnTaskRunnerDeleter
-  // (configured above) will ensure it gets deleted on the host thread.
-  host_.reset(new QuicTransportHost(weak_ptr_factory_.GetWeakPtr(),
-                                    std::move(quic_transport_factory)));
-  // Connect to the IceTransportProxy. This gives us a reference to the
-  // underlying IceTransportHost that should be connected by the
-  // QuicTransportHost on the host thread. It is safe to post it unretained
-  // since the IceTransportHost's ownership is determined by the
-  // IceTransportProxy, and the IceTransportProxy is required to outlive this
-  // object.
-  IceTransportHost* ice_transport_host =
-      ice_transport_proxy->ConnectConsumer(this);
-  PostCrossThreadTask(
-      *host_thread(), FROM_HERE,
-      CrossThreadBindOnce(&QuicTransportHost::Initialize,
-                          CrossThreadUnretained(host_.get()),
-                          CrossThreadUnretained(ice_transport_host), config));
-}
-
-QuicTransportProxy::~QuicTransportProxy() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  ice_transport_proxy_->DisconnectConsumer(this);
-  // Note: The QuicTransportHost will be deleted on the host thread.
-}
-
-scoped_refptr<base::SingleThreadTaskRunner> QuicTransportProxy::proxy_thread()
-    const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return ice_transport_proxy_->proxy_thread();
-}
-
-scoped_refptr<base::SingleThreadTaskRunner> QuicTransportProxy::host_thread()
-    const {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return ice_transport_proxy_->host_thread();
-}
-
-void QuicTransportProxy::Start(P2PQuicTransport::StartConfig config) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  PostCrossThreadTask(*host_thread(), FROM_HERE,
-                      CrossThreadBindOnce(&QuicTransportHost::Start,
-                                          CrossThreadUnretained(host_.get()),
-                                          WTF::Passed(std::move(config))));
-}
-
-void QuicTransportProxy::Stop() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  PostCrossThreadTask(*host_thread(), FROM_HERE,
-                      CrossThreadBindOnce(&QuicTransportHost::Stop,
-                                          CrossThreadUnretained(host_.get())));
-}
-
-QuicStreamProxy* QuicTransportProxy::CreateStream() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  auto stream_proxy = std::make_unique<QuicStreamProxy>();
-  auto stream_host = std::make_unique<QuicStreamHost>();
-  stream_proxy->set_host(stream_host->AsWeakPtr());
-  stream_host->set_proxy(stream_proxy->AsWeakPtr());
-
-  stream_proxy->Initialize(this);
-
-  PostCrossThreadTask(*host_thread(), FROM_HERE,
-                      CrossThreadBindOnce(&QuicTransportHost::CreateStream,
-                                          CrossThreadUnretained(host_.get()),
-                                          WTF::Passed(std::move(stream_host))));
-
-  QuicStreamProxy* stream_proxy_ptr = stream_proxy.get();
-  stream_proxies_.insert(stream_proxy_ptr, std::move(stream_proxy));
-  return stream_proxy_ptr;
-}
-
-void QuicTransportProxy::SendDatagram(Vector<uint8_t> datagram) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  PostCrossThreadTask(*host_thread(), FROM_HERE,
-                      CrossThreadBindOnce(&QuicTransportHost::SendDatagram,
-                                          CrossThreadUnretained(host_.get()),
-                                          std::move(datagram)));
-}
-
-void QuicTransportProxy::GetStats(uint32_t request_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  PostCrossThreadTask(
-      *host_thread(), FROM_HERE,
-      CrossThreadBindOnce(&QuicTransportHost::GetStats,
-                          CrossThreadUnretained(host_.get()), request_id));
-}
-
-void QuicTransportProxy::OnRemoveStream(
-    QuicStreamProxy* stream_proxy_to_remove) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  auto it = stream_proxies_.find(stream_proxy_to_remove);
-  DCHECK(it != stream_proxies_.end());
-  stream_proxies_.erase(it);
-}
-
-void QuicTransportProxy::OnConnected(
-    P2PQuicNegotiatedParams negotiated_params) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  delegate_->OnConnected(negotiated_params);
-}
-
-void QuicTransportProxy::OnRemoteStopped() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  stream_proxies_.clear();
-  delegate_->OnRemoteStopped();
-}
-
-void QuicTransportProxy::OnConnectionFailed(const std::string& error_details,
-                                            bool from_remote) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  stream_proxies_.clear();
-  delegate_->OnConnectionFailed(error_details, from_remote);
-}
-
-void QuicTransportProxy::OnStream(
-    std::unique_ptr<QuicStreamProxy> stream_proxy) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  stream_proxy->Initialize(this);
-
-  QuicStreamProxy* stream_proxy_ptr = stream_proxy.get();
-  stream_proxies_.insert(stream_proxy_ptr, std::move(stream_proxy));
-  delegate_->OnStream(stream_proxy_ptr);
-}
-
-void QuicTransportProxy::OnStats(uint32_t request_id,
-                                 const P2PQuicTransportStats& stats) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  delegate_->OnStats(request_id, stats);
-}
-
-void QuicTransportProxy::OnDatagramSent() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  delegate_->OnDatagramSent();
-}
-
-void QuicTransportProxy::OnDatagramReceived(Vector<uint8_t> datagram) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  delegate_->OnDatagramReceived(std::move(datagram));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h b/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h
deleted file mode 100644
index 387b2db..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.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_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_PROXY_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_PROXY_H_
-
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_checker.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-#include "third_party/webrtc/api/scoped_refptr.h"
-
-namespace blink {
-
-class IceTransportProxy;
-class QuicStreamProxy;
-class QuicTransportHost;
-
-// This class allows the QUIC implementation (P2PQuicTransport) to run on a
-// thread different from the thread from which it is controlled. All
-// interactions with the QUIC implementation happen asynchronously.
-//
-// The QuicTransportProxy is intended to be used with an IceTransportProxy --
-// see the IceTransportProxy class documentation for background and terms. The
-// proxy and host threads used with the QuicTransportProxy should be the same as
-// the ones used with the connected IceTransportProxy.
-class QuicTransportProxy final {
-  USING_FAST_MALLOC(QuicTransportProxy);
-
- public:
-  // Delegate for receiving callbacks from the QUIC implementation. These all
-  // run on the proxy thread.
-  class Delegate {
-   public:
-    virtual ~Delegate() = default;
-
-    // Called when the QUIC handshake finishes and fingerprints have been
-    // verified.
-    virtual void OnConnected(P2PQuicNegotiatedParams negotiated_params) {}
-    // Called when the remote side has indicated it is closed.
-    virtual void OnRemoteStopped() {}
-    // Called when the connection is closed due to a QUIC error. This can happen
-    // locally by the framer or remotely by the peer.
-    virtual void OnConnectionFailed(const std::string& error_details,
-                                    bool from_remote) {}
-    // Called when the remote side has created a new stream.
-    virtual void OnStream(QuicStreamProxy* stream_proxy) {}
-
-    // Called after the stats have been gathered on the host thread. The
-    // |request_id| maps to |request_id| used in GetStats().
-    virtual void OnStats(uint32_t request_id,
-                         const P2PQuicTransportStats& stats) {}
-    // Called when the datagram (sent with SendDatagram) has been
-    // consumed by the QUIC library and sent on the network.
-    virtual void OnDatagramSent() {}
-    // Called when we receive a datagram from the remote side.
-    virtual void OnDatagramReceived(Vector<uint8_t> datagram) {}
-  };
-
-  // Construct a Proxy with the underlying QUIC implementation running on the
-  // same thread as the IceTransportProxy. Callbacks will be serviced by the
-  // given delegate.
-  // The delegate and IceTransportProxy must outlive the QuicTransportProxy.
-  // The QuicTransportProxy will immediately connect to the given
-  // IceTransportProxy; it can be disconnected by destroying the
-  // QuicTransportProxy object.
-  QuicTransportProxy(
-      Delegate* delegate,
-      IceTransportProxy* ice_transport_proxy,
-      std::unique_ptr<P2PQuicTransportFactory> quic_transport_factory,
-      const P2PQuicTransportConfig& config);
-  ~QuicTransportProxy();
-
-  scoped_refptr<base::SingleThreadTaskRunner> proxy_thread() const;
-  scoped_refptr<base::SingleThreadTaskRunner> host_thread() const;
-
-  void Start(P2PQuicTransport::StartConfig config);
-  void Stop();
-
-  QuicStreamProxy* CreateStream();
-
-  void SendDatagram(Vector<uint8_t> datagram);
-
-  // Gathers stats on the host thread, then returns them asynchronously with
-  // Delegate::OnStats. The |request_id| is used to map the GetStats call to the
-  // returned stats.
-  void GetStats(uint32_t request_id);
-
-  // QuicStreamProxy callbacks.
-  void OnRemoveStream(QuicStreamProxy* stream_proxy);
-
- private:
-  // Callbacks from QuicTransportHost.
-  friend class QuicTransportHost;
-  void OnConnected(P2PQuicNegotiatedParams negotiated_params);
-  void OnRemoteStopped();
-  void OnConnectionFailed(const std::string& error_details, bool from_remote);
-  void OnStream(std::unique_ptr<QuicStreamProxy> stream_proxy);
-  void OnStats(uint32_t request_id, const P2PQuicTransportStats& stats);
-  void OnDatagramSent();
-  void OnDatagramReceived(Vector<uint8_t> datagram);
-
-  // Since the Host is deleted on the host thread (Via OnTaskRunnerDeleter), as
-  // long as this is alive it is safe to post tasks to it (using unretained).
-  std::unique_ptr<QuicTransportHost, base::OnTaskRunnerDeleter> host_;
-  Delegate* const delegate_;
-  IceTransportProxy* ice_transport_proxy_;
-  HashMap<QuicStreamProxy*, std::unique_ptr<QuicStreamProxy>> stream_proxies_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Must be the last member.
-  base::WeakPtrFactory<QuicTransportProxy> weak_ptr_factory_{this};
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_QUIC_TRANSPORT_PROXY_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_ice_transport_adapter.h b/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_ice_transport_adapter.h
index 3c6c2a0..d5f867b 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_ice_transport_adapter.h
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_ice_transport_adapter.h
@@ -7,20 +7,12 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
 
 namespace blink {
 
 class MockIceTransportAdapter : public testing::NiceMock<IceTransportAdapter> {
  public:
-  MockIceTransportAdapter() : MockIceTransportAdapter(nullptr) {}
-  MockIceTransportAdapter(
-      std::unique_ptr<P2PQuicPacketTransport> packet_transport)
-      : packet_transport_(std::move(packet_transport)) {
-    ON_CALL(*this, packet_transport()).WillByDefault(testing::Invoke([this] {
-      return packet_transport_.get();
-    }));
-  }
+  MockIceTransportAdapter() = default;
   ~MockIceTransportAdapter() override { Die(); }
   MOCK_METHOD0(Die, void());
 
@@ -36,10 +28,6 @@
                     const Vector<cricket::Candidate>&));
   MOCK_METHOD1(HandleRemoteRestart, void(const cricket::IceParameters&));
   MOCK_METHOD1(AddRemoteCandidate, void(const cricket::Candidate&));
-  MOCK_CONST_METHOD0(packet_transport, P2PQuicPacketTransport*());
-
- private:
-  std::unique_ptr<P2PQuicPacketTransport> packet_transport_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_packet_transport.h b/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_packet_transport.h
deleted file mode 100644
index 9e28706e..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_packet_transport.h
+++ /dev/null
@@ -1,24 +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_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_PACKET_TRANSPORT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_PACKET_TRANSPORT_H_
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_packet_transport.h"
-
-namespace blink {
-
-class MockP2PQuicPacketTransport : public P2PQuicPacketTransport {
- public:
-  // P2PQuicPacketTransport overrides.
-  MOCK_METHOD1(WritePacket, int(const QuicPacket&));
-  MOCK_METHOD1(SetReceiveDelegate, void(ReceiveDelegate*));
-  MOCK_METHOD1(SetWriteObserver, void(WriteObserver*));
-  MOCK_METHOD0(Writable, bool());
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_PACKET_TRANSPORT_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream.h b/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream.h
deleted file mode 100644
index 3db62fd..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream.h
+++ /dev/null
@@ -1,36 +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_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_STREAM_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_STREAM_H_
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h"
-
-namespace blink {
-
-class MockP2PQuicStream : public testing::NiceMock<P2PQuicStream> {
- public:
-  explicit MockP2PQuicStream(P2PQuicStream::Delegate** delegate_out = nullptr) {
-    if (delegate_out) {
-      // Ensure the caller has not left the delegate_out value floating.
-      DCHECK_EQ(nullptr, *delegate_out);
-      EXPECT_CALL(*this, SetDelegate(testing::_))
-          .WillOnce(testing::Invoke(
-              [delegate_out](P2PQuicStream::Delegate* delegate) {
-                *delegate_out = delegate;
-              }));
-    }
-  }
-
-  // P2PQuicStream overrides.
-  MOCK_METHOD0(Reset, void());
-  MOCK_METHOD1(MarkReceivedDataConsumed, void(uint32_t));
-  MOCK_METHOD2(WriteData, void(Vector<uint8_t>, bool));
-  MOCK_METHOD1(SetDelegate, void(Delegate*));
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_STREAM_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream_delegate.h b/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream_delegate.h
deleted file mode 100644
index a33d4ddf..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream_delegate.h
+++ /dev/null
@@ -1,24 +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_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_STREAM_DELEGATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_STREAM_DELEGATE_H_
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_stream.h"
-
-namespace blink {
-
-class MockP2PQuicStreamDelegate
-    : public testing::NiceMock<P2PQuicStream::Delegate> {
- public:
-  // P2PQuicStream::Delegate overrides.
-  MOCK_METHOD1(OnWriteDataConsumed, void(uint32_t));
-  MOCK_METHOD0(OnRemoteReset, void());
-  MOCK_METHOD2(OnDataReceived, void(Vector<uint8_t>, bool));
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_STREAM_DELEGATE_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport.h b/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport.h
deleted file mode 100644
index e9cfc96..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_TRANSPORT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_TRANSPORT_H_
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h"
-
-namespace blink {
-
-class MockP2PQuicTransport : public testing::NiceMock<P2PQuicTransport> {
- public:
-  ~MockP2PQuicTransport() override { Die(); }
-  MOCK_METHOD0(Die, void());
-
-  // P2PQuicTransport overrides.
-  MOCK_METHOD0(Stop, void());
-  void Start(StartConfig config) override { MockStart(config); }
-  MOCK_METHOD1(MockStart, void(const StartConfig&));
-  MOCK_METHOD0(CreateStream, P2PQuicStream*());
-  MOCK_CONST_METHOD0(GetStats, P2PQuicTransportStats());
-  MOCK_METHOD1(SendDatagram, void(Vector<uint8_t>));
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_TRANSPORT_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport_delegate.h b/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport_delegate.h
deleted file mode 100644
index b702cc8f..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport_delegate.h
+++ /dev/null
@@ -1,27 +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_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_TRANSPORT_DELEGATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_TRANSPORT_DELEGATE_H_
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-
-namespace blink {
-
-class MockP2PQuicTransportDelegate
-    : public testing::NiceMock<P2PQuicTransport::Delegate> {
- public:
-  // P2PQuicTransport::Delegate overrides.
-  MOCK_METHOD0(OnRemoteStopped, void());
-  MOCK_METHOD2(OnConnectionFailed, void(const std::string&, bool));
-  MOCK_METHOD1(OnConnected, void(P2PQuicNegotiatedParams));
-  MOCK_METHOD1(OnStream, void(P2PQuicStream*));
-  MOCK_METHOD1(OnDatagramReceived, void(Vector<uint8_t> datagram));
-  MOCK_METHOD0(OnDatagramSent, void());
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_TRANSPORT_DELEGATE_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport_factory.h b/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport_factory.h
deleted file mode 100644
index a6bc14f..0000000
--- a/third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport_factory.h
+++ /dev/null
@@ -1,54 +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_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_TRANSPORT_FACTORY_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_TRANSPORT_FACTORY_H_
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport.h"
-
-namespace blink {
-
-class MockP2PQuicTransportFactory
-    : public testing::NiceMock<P2PQuicTransportFactory> {
- public:
-  MockP2PQuicTransportFactory() = default;
-  MockP2PQuicTransportFactory(
-      std::unique_ptr<MockP2PQuicTransport> mock_transport,
-      P2PQuicTransport::Delegate** delegate_out = nullptr)
-      : mock_transport_(std::move(mock_transport)),
-        delegate_out_(delegate_out) {
-    if (delegate_out) {
-      // Ensure the caller has not left the delegate_out value floating.
-      DCHECK_EQ(nullptr, *delegate_out);
-    }
-    ON_CALL(*this, CreateQuicTransport(testing::_, testing::_, testing::_))
-        .WillByDefault(
-            testing::Invoke([this](P2PQuicTransport::Delegate* delegate,
-                                   P2PQuicPacketTransport* packet_transport,
-                                   const P2PQuicTransportConfig& config) {
-              DCHECK(mock_transport_);
-              if (delegate_out_) {
-                *delegate_out_ = delegate;
-              }
-              return std::move(mock_transport_);
-            }));
-  }
-
-  // P2PQuicTransportFactory overrides.
-  MOCK_METHOD3(CreateQuicTransport,
-               std::unique_ptr<P2PQuicTransport>(
-                   P2PQuicTransport::Delegate* delegate,
-                   P2PQuicPacketTransport* packet_transport,
-                   const P2PQuicTransportConfig& config));
-
- private:
-  std::unique_ptr<MockP2PQuicTransport> mock_transport_;
-  P2PQuicTransport::Delegate** delegate_out_ = nullptr;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_TEST_MOCK_P2P_QUIC_TRANSPORT_FACTORY_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h b/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h
index ad74f6a..6167403 100644
--- a/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h
+++ b/third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h
@@ -12,7 +12,6 @@
 #include <vector>
 
 #include "third_party/blink/public/platform/web_vector.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "third_party/webrtc/api/rtc_error.h"
@@ -41,7 +40,6 @@
 
 class MockWebRtcVideoTrack;
 class MediaStreamVideoTrack;
-struct P2PQuicTransportConfig;
 
 }
 
@@ -86,12 +84,6 @@
 };
 
 template <>
-struct CrossThreadCopier<blink::P2PQuicTransportConfig>
-    : public CrossThreadCopierPassThrough<blink::P2PQuicTransportConfig> {
-  STATIC_ONLY(CrossThreadCopier);
-};
-
-template <>
 struct CrossThreadCopier<webrtc::DtlsTransportInformation>
     : public CrossThreadCopierPassThrough<webrtc::DtlsTransportInformation> {
   STATIC_ONLY(CrossThreadCopier);
@@ -104,31 +96,6 @@
 };
 
 template <>
-struct CrossThreadCopier<blink::P2PQuicTransport::StartConfig>
-    : public CrossThreadCopierPassThrough<
-          blink::P2PQuicTransport::StartConfig> {
-  STATIC_ONLY(CrossThreadCopier);
-  using Type = blink::P2PQuicTransport::StartConfig;
-  static blink::P2PQuicTransport::StartConfig Copy(
-      blink::P2PQuicTransport::StartConfig config) {
-    // This is in fact a move.
-    return config;
-  }
-};
-
-template <>
-struct CrossThreadCopier<blink::P2PQuicTransportStats>
-    : public CrossThreadCopierPassThrough<blink::P2PQuicTransportStats> {
-  STATIC_ONLY(CrossThreadCopier);
-};
-
-template <>
-struct CrossThreadCopier<blink::P2PQuicNegotiatedParams>
-    : public CrossThreadCopierPassThrough<blink::P2PQuicNegotiatedParams> {
-  STATIC_ONLY(CrossThreadCopier);
-};
-
-template <>
 struct CrossThreadCopier<webrtc::RTCError>
     : public CrossThreadCopierPassThrough<webrtc::RTCError> {
   STATIC_ONLY(CrossThreadCopier);
diff --git a/third_party/blink/renderer/modules/peerconnection/idls.gni b/third_party/blink/renderer/modules/peerconnection/idls.gni
index 2ddbb81..d6b0fb6 100644
--- a/third_party/blink/renderer/modules/peerconnection/idls.gni
+++ b/third_party/blink/renderer/modules/peerconnection/idls.gni
@@ -19,9 +19,6 @@
   "rtc_peer_connection.idl",
   "rtc_peer_connection_ice_error_event.idl",
   "rtc_peer_connection_ice_event.idl",
-  "rtc_quic_stream.idl",
-  "rtc_quic_stream_event.idl",
-  "rtc_quic_transport.idl",
   "rtc_rtp_receiver.idl",
   "rtc_rtp_sender.idl",
   "rtc_rtp_transceiver.idl",
@@ -53,11 +50,6 @@
   "rtc_offer_options.idl",
   "rtc_peer_connection_ice_error_event_init.idl",
   "rtc_peer_connection_ice_event_init.idl",
-  "rtc_quic_parameters.idl",
-  "rtc_quic_stream_event_init.idl",
-  "rtc_quic_stream_read_result.idl",
-  "rtc_quic_stream_write_parameters.idl",
-  "rtc_quic_transport_stats.idl",
   "rtc_rtcp_parameters.idl",
   "rtc_rtp_capabilities.idl",
   "rtc_rtp_codec_capability.idl",
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
index 984e4d1..497509c 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.cc
@@ -22,7 +22,6 @@
 #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
@@ -188,34 +187,10 @@
   DCHECK(!proxy_);
 }
 
-bool RTCIceTransport::HasConsumer() const {
-  return consumer_;
-}
-
 bool RTCIceTransport::IsFromPeerConnection() const {
   return peer_connection_;
 }
 
-IceTransportProxy* RTCIceTransport::ConnectConsumer(
-    RTCQuicTransport* consumer) {
-  DCHECK(consumer);
-  DCHECK(proxy_);
-  DCHECK(!peer_connection_);
-  if (!consumer_) {
-    consumer_ = consumer;
-  } else {
-    DCHECK_EQ(consumer_, consumer);
-  }
-  return proxy_.get();
-}
-
-void RTCIceTransport::DisconnectConsumer(RTCQuicTransport* consumer) {
-  DCHECK(consumer);
-  DCHECK(proxy_);
-  DCHECK_EQ(consumer, consumer_);
-  consumer_ = nullptr;
-}
-
 String RTCIceTransport::role() const {
   switch (role_) {
     case cricket::ICEROLE_CONTROLLING:
@@ -435,9 +410,6 @@
           *ConvertToCricketIceCandidate(*remote_candidate));
     }
     proxy_->Start(remote_parameters, role, initial_remote_candidates);
-    if (consumer_) {
-      consumer_->OnIceTransportStarted();
-    }
   } else {
     remote_candidates_.clear();
     state_ = webrtc::IceTransportState::kNew;
@@ -545,11 +517,6 @@
   if (IsClosed()) {
     return;
   }
-  if (HasConsumer()) {
-    consumer_->OnIceTransportClosed(reason);
-  }
-  // Notifying the consumer that we're closing should cause it to disconnect.
-  DCHECK(!HasConsumer());
   state_ = webrtc::IceTransportState::kClosed;
   selected_candidate_pair_ = nullptr;
   proxy_.reset();
@@ -590,7 +557,6 @@
   visitor->Trace(local_parameters_);
   visitor->Trace(remote_parameters_);
   visitor->Trace(selected_candidate_pair_);
-  visitor->Trace(consumer_);
   visitor->Trace(peer_connection_);
   EventTargetWithInlineData::Trace(visitor);
   ExecutionContextLifecycleObserver::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
index a8aa600..884b804 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h
@@ -27,7 +27,6 @@
 class RTCIceCandidate;
 class RTCIceGatherOptions;
 class IceTransportAdapterCrossThreadFactory;
-class RTCQuicTransport;
 class RTCPeerConnection;
 
 // Blink bindings for the RTCIceTransport JavaScript object.
@@ -92,14 +91,6 @@
   // Returns true if the RTCIceTransport is in a terminal state.
   bool IsClosed() const { return state_ == webrtc::IceTransportState::kClosed; }
 
-  // An RTCQuicTransport can be connected to this RTCIceTransport. Only one can
-  // be connected at a time. The consumer will be automatically disconnected
-  // if stop() is called on this object. Otherwise, the RTCQuicTransport is
-  // responsible for disconnecting itself when it is done.
-  // ConnectConsumer returns an IceTransportProxy that can be used to connect
-  // a QuicTransportProxy. It may be called repeatedly with the same
-  // RTCQuicTransport.
-  bool HasConsumer() const;
   // If |this| was created from an RTCPeerConnection.
   //
   // Background: This is because we don't reuse an RTCIceTransport that has been
@@ -115,8 +106,6 @@
   // -Asynchronously connect to the P2PTransport - if the count of connected
   // transports to the P2PTransportChannel is > 1, then throw an exception.
   bool IsFromPeerConnection() const;
-  IceTransportProxy* ConnectConsumer(RTCQuicTransport* consumer);
-  void DisconnectConsumer(RTCQuicTransport* consumer);
 
   // rtc_ice_transport.idl
   String role() const;
@@ -185,7 +174,6 @@
   Member<RTCIceParameters> remote_parameters_;
   Member<RTCIceCandidatePair> selected_candidate_pair_;
 
-  Member<RTCQuicTransport> consumer_;
   const WeakMember<RTCPeerConnection> peer_connection_;
 
   // Handle to the WebRTC ICE transport. Created when this binding is
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc
index f6f802c..8eb1ba9 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.cc
@@ -13,7 +13,6 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_candidate_init.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_gather_options.h"
 #include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_ice_transport_adapter_cross_thread_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_packet_transport.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h"
 #include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h"
 #include "third_party/webrtc/pc/webrtc_sdp.h"
@@ -108,9 +107,7 @@
 
 RTCIceTransport* RTCIceTransportTest::CreateIceTransport(
     V8TestingScope& scope) {
-  return CreateIceTransport(
-      scope, std::make_unique<MockIceTransportAdapter>(
-                 std::make_unique<MockP2PQuicPacketTransport>()));
+  return CreateIceTransport(scope, std::make_unique<MockIceTransportAdapter>());
 }
 
 RTCIceTransport* RTCIceTransportTest::CreateIceTransport(
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_parameters.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_parameters.idl
deleted file mode 100644
index 4fd90d7..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_parameters.idl
+++ /dev/null
@@ -1,16 +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.
-
-// https://w3c.github.io/webrtc-quic/#dom-rtcquicrole
-enum RTCQuicRole {
-  "auto",
-  "client",
-  "server",
-};
-
-// https://w3c.github.io/webrtc-quic/#rtcquicparameters*
-dictionary RTCQuicParameters {
-  RTCQuicRole role = "auto";
-  sequence<RTCDtlsFingerprint> fingerprints;
-};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc
deleted file mode 100644
index fda672d9..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.cc
+++ /dev/null
@@ -1,413 +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/modules/peerconnection/rtc_quic_stream.h"
-
-#include "base/containers/span.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-
-namespace blink {
-
-// 6 MB allows a reasonable amount to buffer on the read and write side.
-// TODO(https://crbug.com/874296): Consider exposing these configurations.
-const uint32_t RTCQuicStream::kWriteBufferSize = 6 * 1024 * 1024;
-const uint32_t RTCQuicStream::kReadBufferSize = 6 * 1024 * 1024;
-
-class RTCQuicStream::PendingReadBufferedAmountPromise
-    : public GarbageCollected<PendingReadBufferedAmountPromise> {
- public:
-  PendingReadBufferedAmountPromise(ScriptPromiseResolver* promise_resolver,
-                                   uint32_t readable_amount)
-      : promise_resolver_(promise_resolver),
-        readable_amount_(readable_amount) {}
-
-  ScriptPromiseResolver* promise_resolver() const { return promise_resolver_; }
-  uint32_t readable_amount() const { return readable_amount_; }
-
-  void Trace(Visitor* visitor) const { visitor->Trace(promise_resolver_); }
-
- private:
-  Member<ScriptPromiseResolver> promise_resolver_;
-  uint32_t readable_amount_;
-};
-
-class RTCQuicStream::PendingWriteBufferedAmountPromise
-    : public GarbageCollected<PendingWriteBufferedAmountPromise> {
- public:
-  PendingWriteBufferedAmountPromise(ScriptPromiseResolver* promise_resolver,
-                                    uint32_t threshold)
-      : promise_resolver_(promise_resolver), threshold_(threshold) {}
-
-  ScriptPromiseResolver* promise_resolver() const { return promise_resolver_; }
-  uint32_t threshold() const { return threshold_; }
-
-  void Trace(Visitor* visitor) const { visitor->Trace(promise_resolver_); }
-
- private:
-  Member<ScriptPromiseResolver> promise_resolver_;
-  uint32_t threshold_;
-};
-
-RTCQuicStream::RTCQuicStream(ExecutionContext* context,
-                             RTCQuicTransport* transport,
-                             QuicStreamProxy* stream_proxy)
-    : ExecutionContextClient(context),
-      transport_(transport),
-      proxy_(stream_proxy) {
-  DCHECK(transport_);
-  DCHECK(proxy_);
-}
-
-RTCQuicStream::~RTCQuicStream() = default;
-
-RTCQuicTransport* RTCQuicStream::transport() const {
-  return transport_;
-}
-
-String RTCQuicStream::state() const {
-  switch (state_) {
-    case RTCQuicStreamState::kNew:
-      return "new";
-    case RTCQuicStreamState::kOpening:
-      return "opening";
-    case RTCQuicStreamState::kOpen:
-      return "open";
-    case RTCQuicStreamState::kClosing:
-      return "closing";
-    case RTCQuicStreamState::kClosed:
-      return "closed";
-  }
-  return String();
-}
-
-uint32_t RTCQuicStream::readBufferedAmount() const {
-  return receive_buffer_.size();
-}
-
-uint32_t RTCQuicStream::maxReadBufferedAmount() const {
-  return kReadBufferSize;
-}
-
-uint32_t RTCQuicStream::writeBufferedAmount() const {
-  return write_buffered_amount_;
-}
-
-uint32_t RTCQuicStream::maxWriteBufferedAmount() const {
-  return kWriteBufferSize;
-}
-
-RTCQuicStreamReadResult* RTCQuicStream::readInto(
-    NotShared<DOMUint8Array> data,
-    ExceptionState& exception_state) {
-  if (RaiseIfNotReadable(exception_state)) {
-    return 0;
-  }
-  uint32_t read_amount = static_cast<uint32_t>(receive_buffer_.ReadInto(
-      base::make_span(data.View()->Data(), data.View()->lengthAsSizeT())));
-  if (!received_fin_ && read_amount > 0) {
-    proxy_->MarkReceivedDataConsumed(read_amount);
-  }
-  if (receive_buffer_.empty() && received_fin_) {
-    read_fin_ = true;
-    if (wrote_fin_) {
-      DCHECK_EQ(state_, RTCQuicStreamState::kClosing);
-      Close(CloseReason::kReadWriteFinished);
-    } else {
-      DCHECK_EQ(state_, RTCQuicStreamState::kOpen);
-      state_ = RTCQuicStreamState::kClosing;
-    }
-  }
-  auto* result = RTCQuicStreamReadResult::Create();
-  result->setAmount(read_amount);
-  result->setFinished(read_fin_);
-  return result;
-}
-
-void RTCQuicStream::write(const RTCQuicStreamWriteParameters* data,
-                          ExceptionState& exception_state) {
-  bool finish = data->finish();
-  bool has_write_data =
-      data->hasData() && data->data().View()->lengthAsSizeT() > 0;
-  if (!has_write_data && !finish) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kNotSupportedError,
-        "Cannot write empty data, unless data.finish is set to true.");
-    return;
-  }
-  if (RaiseIfNotWritable(exception_state)) {
-    return;
-  }
-  Vector<uint8_t> data_vector;
-  if (has_write_data) {
-    DOMUint8Array* write_data = data->data().View();
-    size_t remaining_write_buffer_size =
-        kWriteBufferSize - writeBufferedAmount();
-    if (write_data->lengthAsSizeT() > remaining_write_buffer_size) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kOperationError,
-          "The write data size of " +
-              String::Number(write_data->lengthAsSizeT()) +
-              " bytes would exceed the remaining write buffer size of " +
-              String::Number(remaining_write_buffer_size) + " bytes.");
-      return;
-    }
-    data_vector.resize(static_cast<wtf_size_t>(write_data->lengthAsSizeT()));
-    memcpy(data_vector.data(), write_data->Data(), write_data->lengthAsSizeT());
-    write_buffered_amount_ +=
-        static_cast<uint32_t>(write_data->lengthAsSizeT());
-  }
-  proxy_->WriteData(std::move(data_vector), finish);
-  if (finish) {
-    wrote_fin_ = true;
-    if (!read_fin_) {
-      DCHECK_EQ(state_, RTCQuicStreamState::kOpen);
-      state_ = RTCQuicStreamState::kClosing;
-      RejectPendingWaitForWriteBufferedAmountBelowPromises();
-    } else {
-      DCHECK_EQ(state_, RTCQuicStreamState::kClosing);
-      Close(CloseReason::kReadWriteFinished);
-    }
-  }
-}
-
-void RTCQuicStream::reset() {
-  if (IsClosed()) {
-    return;
-  }
-  Close(CloseReason::kLocalReset);
-}
-
-ScriptPromise RTCQuicStream::waitForReadable(ScriptState* script_state,
-                                             uint32_t amount,
-                                             ExceptionState& exception_state) {
-  if (RaiseIfNotReadable(exception_state)) {
-    return ScriptPromise();
-  }
-  if (amount > kReadBufferSize) {
-    exception_state.ThrowTypeError(
-        "The amount " + String::Number(amount) +
-        " is greater than the maximum read buffer size of " +
-        String::Number(kReadBufferSize) + ".");
-    return ScriptPromise();
-  }
-  auto* promise_resolver =
-      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  ScriptPromise promise = promise_resolver->Promise();
-  if (received_fin_ || receive_buffer_.size() >= amount) {
-    promise_resolver->Resolve();
-  } else {
-    pending_read_buffered_amount_promises_.push_back(
-        MakeGarbageCollected<PendingReadBufferedAmountPromise>(promise_resolver,
-                                                               amount));
-  }
-  return promise;
-}
-
-ScriptPromise RTCQuicStream::waitForWriteBufferedAmountBelow(
-    ScriptState* script_state,
-    uint32_t threshold,
-    ExceptionState& exception_state) {
-  if (RaiseIfNotWritable(exception_state)) {
-    return ScriptPromise();
-  }
-  auto* promise_resolver =
-      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  ScriptPromise promise = promise_resolver->Promise();
-  if (write_buffered_amount_ <= threshold) {
-    promise_resolver->Resolve();
-  } else {
-    pending_write_buffered_amount_promises_.push_back(
-        MakeGarbageCollected<PendingWriteBufferedAmountPromise>(
-            promise_resolver, threshold));
-  }
-  return promise;
-}
-
-bool RTCQuicStream::RaiseIfNotReadable(ExceptionState& exception_state) {
-  if (read_fin_) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The stream is not readable: The end of the stream has been read.");
-    return true;
-  }
-  if (IsClosed()) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The stream is not readable: The stream is closed.");
-    return true;
-  }
-  return false;
-}
-
-bool RTCQuicStream::RaiseIfNotWritable(ExceptionState& exception_state) {
-  if (wrote_fin_) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The stream is not writable: finish() has been called.");
-    return true;
-  }
-  if (IsClosed()) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The stream is not writable: The stream is closed.");
-    return true;
-  }
-  return false;
-}
-
-void RTCQuicStream::RejectPendingWaitForReadablePromises() {
-  // TODO(https://github.com/w3c/webrtc-quic/issues/81): The promise resolve
-  // order is under specified.
-  for (PendingReadBufferedAmountPromise* pending_promise :
-       pending_read_buffered_amount_promises_) {
-    ScriptState::Scope scope(
-        pending_promise->promise_resolver()->GetScriptState());
-    ExceptionState exception_state(
-        pending_promise->promise_resolver()->GetScriptState()->GetIsolate(),
-        ExceptionState::kExecutionContext, "RTCQuicStream", "waitForReadable");
-    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
-                                      "The RTCQuicStream is not readable.");
-    pending_promise->promise_resolver()->Reject(exception_state);
-  }
-  pending_read_buffered_amount_promises_.clear();
-}
-
-void RTCQuicStream::RejectPendingWaitForWriteBufferedAmountBelowPromises() {
-  // TODO(https://github.com/w3c/webrtc-quic/issues/81): The promise resolve
-  // order is under specified.
-  for (PendingWriteBufferedAmountPromise* pending_promise :
-       pending_write_buffered_amount_promises_) {
-    ScriptState::Scope scope(
-        pending_promise->promise_resolver()->GetScriptState());
-    ExceptionState exception_state(
-        pending_promise->promise_resolver()->GetScriptState()->GetIsolate(),
-        ExceptionState::kExecutionContext, "RTCQuicStream",
-        "waitForWriteBufferedAmountBelow");
-    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
-                                      "The stream is no longer writable.");
-    pending_promise->promise_resolver()->Reject(exception_state);
-  }
-  pending_write_buffered_amount_promises_.clear();
-}
-
-void RTCQuicStream::OnRemoteReset() {
-  Close(CloseReason::kRemoteReset);
-}
-
-void RTCQuicStream::OnDataReceived(Vector<uint8_t> data, bool fin) {
-  DCHECK(!received_fin_);
-  DCHECK_LE(data.size(), kReadBufferSize - receive_buffer_.size());
-  received_fin_ = fin;
-  receive_buffer_.Append(std::move(data));
-  // TODO(https://github.com/w3c/webrtc-quic/issues/81): The promise resolve
-  // order is under specified.
-  for (auto* it = pending_read_buffered_amount_promises_.begin();
-       it != pending_read_buffered_amount_promises_.end();
-       /* incremented manually */) {
-    PendingReadBufferedAmountPromise* pending_promise = *it;
-    if (received_fin_ ||
-        receive_buffer_.size() >= pending_promise->readable_amount()) {
-      pending_promise->promise_resolver()->Resolve();
-      it = pending_read_buffered_amount_promises_.erase(it);
-    } else {
-      ++it;
-    }
-  }
-}
-
-void RTCQuicStream::OnWriteDataConsumed(uint32_t amount) {
-  DCHECK_GE(write_buffered_amount_, amount);
-  write_buffered_amount_ -= amount;
-  // TODO(https://github.com/w3c/webrtc-quic/issues/81): The promise resolve
-  // order is under specified.
-  for (auto* it = pending_write_buffered_amount_promises_.begin();
-       it != pending_write_buffered_amount_promises_.end();
-       /* incremented manually */) {
-    PendingWriteBufferedAmountPromise* pending_promise = *it;
-    if (write_buffered_amount_ <= pending_promise->threshold()) {
-      pending_promise->promise_resolver()->Resolve();
-      it = pending_write_buffered_amount_promises_.erase(it);
-    } else {
-      ++it;
-    }
-  }
-}
-
-void RTCQuicStream::OnQuicTransportClosed(
-    RTCQuicTransport::CloseReason reason) {
-  switch (reason) {
-    case RTCQuicTransport::CloseReason::kContextDestroyed:
-      Close(CloseReason::kContextDestroyed);
-      break;
-    default:
-      Close(CloseReason::kQuicTransportClosed);
-      break;
-  }
-}
-
-void RTCQuicStream::Close(CloseReason reason) {
-  DCHECK_NE(state_, RTCQuicStreamState::kClosed);
-
-  // Tear down the QuicStreamProxy.
-  // If the Close is caused by a remote event or regular use of WriteData, the
-  // QuicStreamProxy will have already been deleted.
-  // If the Close is caused by the transport then the transport is responsible
-  // for deleting the QuicStreamProxy.
-  if (reason == CloseReason::kLocalReset) {
-    // This deletes the QuicStreamProxy.
-    proxy_->Reset();
-  }
-  proxy_ = nullptr;
-
-  // Remove this stream from the RTCQuicTransport unless closing from a
-  // transport-level event.
-  switch (reason) {
-    case CloseReason::kReadWriteFinished:
-    case CloseReason::kLocalReset:
-    case CloseReason::kRemoteReset:
-      transport_->RemoveStream(this);
-      break;
-    case CloseReason::kQuicTransportClosed:
-    case CloseReason::kContextDestroyed:
-      // The RTCQuicTransport will handle clearing its list of streams.
-      break;
-  }
-
-  // Clear observable state.
-  receive_buffer_.Clear();
-  write_buffered_amount_ = 0;
-
-  // It's illegal to resolve or reject promises when the ExecutionContext is
-  // being destroyed.
-  if (reason != CloseReason::kContextDestroyed) {
-    RejectPendingWaitForReadablePromises();
-    RejectPendingWaitForWriteBufferedAmountBelowPromises();
-  }
-
-  // Change the state. Fire the statechange event only if the close is caused by
-  // a remote stream event.
-  state_ = RTCQuicStreamState::kClosed;
-  if (reason == CloseReason::kRemoteReset) {
-    DispatchEvent(*Event::Create(event_type_names::kStatechange));
-  }
-}
-
-const AtomicString& RTCQuicStream::InterfaceName() const {
-  return event_target_names::kRTCQuicStream;
-}
-
-ExecutionContext* RTCQuicStream::GetExecutionContext() const {
-  return ExecutionContextClient::GetExecutionContext();
-}
-
-void RTCQuicStream::Trace(Visitor* visitor) const {
-  visitor->Trace(transport_);
-  visitor->Trace(pending_read_buffered_amount_promises_);
-  visitor->Trace(pending_write_buffered_amount_promises_);
-  EventTargetWithInlineData::Trace(visitor);
-  ExecutionContextClient::Trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h
deleted file mode 100644
index eace0450..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h
+++ /dev/null
@@ -1,141 +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_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_H_
-
-#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_read_result.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_write_parameters.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
-#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
-#include "third_party/blink/renderer/modules/event_target_modules.h"
-#include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_stream_proxy.h"
-#include "third_party/blink/renderer/modules/peerconnection/byte_buffer_queue.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h"
-
-namespace blink {
-
-class ScriptPromise;
-
-enum class RTCQuicStreamState { kNew, kOpening, kOpen, kClosing, kClosed };
-
-// The RTCQuicStream does not need to be ActiveScriptWrappable since the
-// RTCQuicTransport that it is associated with holds a strong reference to it
-// as long as it is not closed.
-class MODULES_EXPORT RTCQuicStream final : public EventTargetWithInlineData,
-                                           public ExecutionContextClient,
-                                           public QuicStreamProxy::Delegate {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  // TODO(steveanton): These maybe should be adjustable.
-  static const uint32_t kWriteBufferSize;
-  static const uint32_t kReadBufferSize;
-
-  enum class CloseReason {
-    // Both read and write sides have been finished.
-    kReadWriteFinished,
-    // reset() was called.
-    kLocalReset,
-    // The remote stream sent a reset().
-    kRemoteReset,
-    // The RTCQuicTransport has closed.
-    kQuicTransportClosed,
-    // The ExecutionContext is being destroyed.
-    kContextDestroyed,
-  };
-
-  RTCQuicStream(ExecutionContext* context,
-                RTCQuicTransport* transport,
-                QuicStreamProxy* stream_proxy);
-  ~RTCQuicStream() override;
-
-  // Called by the RTCQuicTransport when it is being closed.
-  void OnQuicTransportClosed(RTCQuicTransport::CloseReason reason);
-
-  // rtc_quic_stream.idl
-  RTCQuicTransport* transport() const;
-  String state() const;
-  uint32_t readBufferedAmount() const;
-  uint32_t maxReadBufferedAmount() const;
-  uint32_t writeBufferedAmount() const;
-  uint32_t maxWriteBufferedAmount() const;
-  RTCQuicStreamReadResult* readInto(NotShared<DOMUint8Array> data,
-                                    ExceptionState& exception_state);
-  void write(const RTCQuicStreamWriteParameters* data,
-             ExceptionState& exception_state);
-  void reset();
-  ScriptPromise waitForWriteBufferedAmountBelow(
-      ScriptState* script_state,
-      uint32_t threshold,
-      ExceptionState& exception_state);
-  ScriptPromise waitForReadable(ScriptState* script_state,
-                                uint32_t amount,
-                                ExceptionState& exception_state);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange, kStatechange)
-
-  // EventTarget overrides.
-  const AtomicString& InterfaceName() const override;
-  ExecutionContext* GetExecutionContext() const override;
-
-  // For garbage collection.
-  void Trace(Visitor* visitor) const override;
-
- private:
-  class PendingReadBufferedAmountPromise;
-  class PendingWriteBufferedAmountPromise;
-
-  // QuicStreamProxy::Delegate overrides.
-  void OnRemoteReset() override;
-  void OnDataReceived(Vector<uint8_t> data, bool fin) override;
-  void OnWriteDataConsumed(uint32_t amount) override;
-
-  bool RaiseIfNotReadable(ExceptionState&);
-  bool RaiseIfNotWritable(ExceptionState&);
-
-  // Permenantly closes the RTCQuicStream with the given reason.
-  // The RTCQuicStream must not already be closed.
-  // This will transition the state to closed.
-  void Close(CloseReason reason);
-
-  bool IsClosed() const { return state_ == RTCQuicStreamState::kClosed; }
-
-  void RejectPendingWaitForReadablePromises();
-  void RejectPendingWaitForWriteBufferedAmountBelowPromises();
-
-  Member<RTCQuicTransport> transport_;
-  RTCQuicStreamState state_ = RTCQuicStreamState::kOpen;
-
-  // Data that has been received but not read.
-  // OnDataReceived() appends to the read buffer.
-  // readInto() will read out from the front of the buffer.
-  ByteBufferQueue receive_buffer_;
-  // True if the fin has been received from the network.
-  bool received_fin_ = false;
-  // True if the fin has been read out via readInto(). This signifies that the
-  // RTCQuicStream is closed for reading.
-  bool read_fin_ = false;
-  // Pending waitForReadable promises.
-  HeapVector<Member<PendingReadBufferedAmountPromise>>
-      pending_read_buffered_amount_promises_;
-
-  // Amount of bytes written but may not yet have been sent by the underlying
-  // P2PQuicStream.
-  // write() increases this number.
-  // OnDataSent() decreases this number.
-  uint32_t write_buffered_amount_ = 0;
-  // True if finish() has been called.
-  bool wrote_fin_ = false;
-  // Pending waitForWriteBufferedAmountBelow Promises.
-  HeapVector<Member<PendingWriteBufferedAmountPromise>>
-      pending_write_buffered_amount_promises_;
-
-  QuicStreamProxy* proxy_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl
deleted file mode 100644
index 8e793d4..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.idl
+++ /dev/null
@@ -1,36 +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.
-
-// https://w3c.github.io/webrtc-quic/#rtcquicstreamstate*
-enum RTCQuicStreamState {
-    "new",
-    "opening",
-    "open",
-    "closing",
-    "closed",
-};
-
-// https://w3c.github.io/webrtc-quic/#quicstream*
-[
-   Exposed=Window,
-   RuntimeEnabled=RTCQuicTransport,
-   SecureContext
-] interface RTCQuicStream : EventTarget {
-    [Measure] readonly attribute RTCQuicTransport transport;
-    [Measure] readonly attribute RTCQuicStreamState state;
-    [Measure] readonly attribute unsigned long readBufferedAmount;
-    [Measure] readonly attribute unsigned long maxReadBufferedAmount;
-    [Measure] readonly attribute unsigned long writeBufferedAmount;
-    [Measure] readonly attribute unsigned long maxWriteBufferedAmount;
-    [Measure, RaisesException] RTCQuicStreamReadResult readInto(Uint8Array data);
-    [Measure, RaisesException] void write(RTCQuicStreamWriteParameters data);
-    [Measure] void reset();
-    [CallWith=ScriptState, Measure, RaisesException]
-    Promise<void> waitForWriteBufferedAmountBelow(unsigned long amount);
-    [CallWith=ScriptState, Measure, RaisesException]
-    Promise<void> waitForReadable(unsigned long amount);
-    attribute EventHandler onstatechange;
-    // TODO(crbug.com/868068): Implement remaining methods, attributes, and events.
-};
-
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc
deleted file mode 100644
index 7f61f19..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.cc
+++ /dev/null
@@ -1,45 +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/modules/peerconnection/rtc_quic_stream_event.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_stream_event_init.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h"
-
-namespace blink {
-
-RTCQuicStreamEvent* RTCQuicStreamEvent::Create(RTCQuicStream* stream) {
-  return MakeGarbageCollected<RTCQuicStreamEvent>(stream);
-}
-
-RTCQuicStreamEvent* RTCQuicStreamEvent::Create(
-    const AtomicString& type,
-    const RTCQuicStreamEventInit* initializer) {
-  return MakeGarbageCollected<RTCQuicStreamEvent>(type, initializer);
-}
-
-RTCQuicStreamEvent::RTCQuicStreamEvent(RTCQuicStream* stream)
-    : Event(event_type_names::kQuicstream, Bubbles::kNo, Cancelable::kNo),
-      stream_(stream) {}
-
-RTCQuicStreamEvent::RTCQuicStreamEvent(
-    const AtomicString& type,
-    const RTCQuicStreamEventInit* initializer)
-    : Event(type, initializer), stream_(initializer->stream()) {}
-
-RTCQuicStreamEvent::~RTCQuicStreamEvent() = default;
-
-RTCQuicStream* RTCQuicStreamEvent::stream() const {
-  return stream_.Get();
-}
-
-const AtomicString& RTCQuicStreamEvent::InterfaceName() const {
-  return event_interface_names::kRTCQuicStreamEvent;
-}
-
-void RTCQuicStreamEvent::Trace(Visitor* visitor) const {
-  visitor->Trace(stream_);
-  Event::Trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h
deleted file mode 100644
index faeb397b..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h
+++ /dev/null
@@ -1,43 +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_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_EVENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_EVENT_H_
-
-#include "third_party/blink/renderer/modules/event_modules.h"
-
-namespace blink {
-
-class RTCQuicStream;
-class RTCQuicStreamEventInit;
-
-class MODULES_EXPORT RTCQuicStreamEvent final : public Event {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  static RTCQuicStreamEvent* Create(RTCQuicStream* stream);
-  static RTCQuicStreamEvent* Create(const AtomicString& type,
-                                    const RTCQuicStreamEventInit* init);
-
-  RTCQuicStreamEvent(RTCQuicStream* stream);
-  RTCQuicStreamEvent(const AtomicString& type,
-                     const RTCQuicStreamEventInit* init);
-  ~RTCQuicStreamEvent() override;
-
-  // rtc_quic_stream_event.idl
-  RTCQuicStream* stream() const;
-
-  // Event overrides.
-  const AtomicString& InterfaceName() const override;
-
-  // For garbage collection.
-  void Trace(Visitor*) const override;
-
- private:
-  Member<RTCQuicStream> stream_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_STREAM_EVENT_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl
deleted file mode 100644
index 3facdd0..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.idl
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// https://w3c.github.io/webrtc-quic/#rtcquicstreamevent
-[
-   RuntimeEnabled=RTCQuicTransport,
-   Exposed=Window
-] interface RTCQuicStreamEvent : Event {
-    constructor(DOMString type, optional RTCQuicStreamEventInit eventInitDict = {});
-    readonly attribute RTCQuicStream stream;
-};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event_init.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event_init.idl
deleted file mode 100644
index 53e3bcd..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event_init.idl
+++ /dev/null
@@ -1,8 +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.
-
-// https://w3c.github.io/webrtc-quic/#dom-rtcquicstreameventinit
-dictionary RTCQuicStreamEventInit : EventInit {
-  RTCQuicStream stream;
-};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_read_result.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_read_result.idl
deleted file mode 100644
index b2d58c2..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_read_result.idl
+++ /dev/null
@@ -1,9 +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.
-
-// https://w3c.github.io/webrtc-quic/#dom-rtcquicstreamreadresult
-dictionary RTCQuicStreamReadResult {
-    unsigned long amount;
-    boolean finished;
-};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_test.cc
deleted file mode 100644
index 3d717b7..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_test.cc
+++ /dev/null
@@ -1,1228 +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.
-
-// This file tests the RTCQuicStream Blink bindings, QuicStreamProxy and
-// QuicStreamHost by mocking out the underlying P2PQuicTransport.
-// Everything is run on a single thread but with separate TestSimpleTaskRunners
-// for the main thread / worker thread.
-
-#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h"
-
-namespace blink {
-namespace {
-
-using testing::_;
-using testing::ElementsAre;
-using testing::InvokeWithoutArgs;
-using testing::Return;
-using testing::SaveArg;
-
-RTCQuicStreamWriteParameters* CreateWriteParametersWithData(
-    const Vector<uint8_t>& data) {
-  RTCQuicStreamWriteParameters* write_parameters =
-      RTCQuicStreamWriteParameters::Create();
-  write_parameters->setData(NotShared<DOMUint8Array>(
-      DOMUint8Array::Create(data.data(), data.size())));
-  write_parameters->setFinish(false);
-  return write_parameters;
-}
-
-RTCQuicStreamWriteParameters* CreateWriteParametersWithDataOfLength(
-    uint32_t length,
-    bool finish = false) {
-  RTCQuicStreamWriteParameters* write_parameters =
-      RTCQuicStreamWriteParameters::Create();
-  write_parameters->setData(
-      NotShared<DOMUint8Array>(DOMUint8Array::Create(length)));
-  write_parameters->setFinish(finish);
-  return write_parameters;
-}
-
-RTCQuicStreamWriteParameters* CreateWriteParametersWithoutData(bool finish) {
-  RTCQuicStreamWriteParameters* write_parameters =
-      RTCQuicStreamWriteParameters::Create();
-  write_parameters->setFinish(finish);
-  return write_parameters;
-}
-
-}  // namespace
-
-class RTCQuicStreamTest : public RTCQuicTransportTest {
- public:
-  RTCQuicStream* CreateQuicStream(V8TestingScope& scope,
-                                  MockP2PQuicStream* mock_stream) {
-    auto p2p_quic_transport = std::make_unique<MockP2PQuicTransport>();
-    EXPECT_CALL(*p2p_quic_transport, CreateStream())
-        .WillOnce(Return(mock_stream));
-    Persistent<RTCQuicTransport> quic_transport =
-        CreateConnectedQuicTransport(scope, std::move(p2p_quic_transport));
-    return quic_transport->createStream(ASSERT_NO_EXCEPTION);
-  }
-};
-
-// Test that RTCQuicTransport.createStream causes CreateStream to be called on
-// the underlying transport and a P2PQuicStream::Delegate to be set on the
-// underlying P2PQuicStream.
-TEST_F(RTCQuicStreamTest, RTCQuicTransportCreateStreamCallsUnderlying) {
-  V8TestingScope scope;
-
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
-  EXPECT_CALL(*p2p_quic_stream, SetDelegate(_))
-      .WillOnce(testing::Invoke(
-          [](P2PQuicStream::Delegate* delegate) { EXPECT_TRUE(delegate); }));
-
-  auto p2p_quic_transport = std::make_unique<MockP2PQuicTransport>();
-  EXPECT_CALL(*p2p_quic_transport, CreateStream())
-      .WillOnce(Return(p2p_quic_stream.get()));
-
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, std::move(p2p_quic_transport));
-  Persistent<RTCQuicStream> quic_stream =
-      quic_transport->createStream(ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-}
-
-// Test that calling OnStream on the P2PQuicTransport delegate causes a
-// quicstream event to fire with a new RTCQuicStream.
-TEST_F(RTCQuicStreamTest, NewRemoteStreamFiresEvent) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* transport_delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &transport_delegate);
-
-  Persistent<MockEventListener> quic_stream_listener =
-      CreateMockEventListener();
-  EXPECT_CALL(*quic_stream_listener, Invoke(_, _))
-      .WillOnce(testing::Invoke([](ExecutionContext*, Event* event) {
-        auto* stream_event = static_cast<RTCQuicStreamEvent*>(event);
-        EXPECT_NE(nullptr, stream_event->stream());
-      }));
-  quic_transport->addEventListener(event_type_names::kQuicstream,
-                                   quic_stream_listener);
-
-  ASSERT_TRUE(transport_delegate);
-
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
-  EXPECT_CALL(*p2p_quic_stream, SetDelegate(_))
-      .WillOnce(testing::Invoke(
-          [](P2PQuicStream::Delegate* delegate) { EXPECT_TRUE(delegate); }));
-  transport_delegate->OnStream(p2p_quic_stream.get());
-
-  RunUntilIdle();
-}
-
-// Test that calling reset() calls Reset() on the underlying P2PQuicStream.
-TEST_F(RTCQuicStreamTest, ResetCallsUnderlying) {
-  V8TestingScope scope;
-
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
-  EXPECT_CALL(*p2p_quic_stream, Reset()).Times(1);
-
-  auto p2p_quic_transport = std::make_unique<MockP2PQuicTransport>();
-  EXPECT_CALL(*p2p_quic_transport, CreateStream())
-      .WillOnce(Return(p2p_quic_stream.get()));
-
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, std::move(p2p_quic_transport));
-  Persistent<RTCQuicStream> stream =
-      quic_transport->createStream(ASSERT_NO_EXCEPTION);
-
-  stream->reset();
-
-  RunUntilIdle();
-}
-
-// Test that calling OnRemoteReset() on the P2PQuicStream delegate fires a
-// statechange event to 'closed'.
-TEST_F(RTCQuicStreamTest, OnRemoteResetFiresStateChangeToClosed) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
-  EXPECT_CALL(*p2p_quic_stream, SetDelegate(_))
-      .WillOnce(SaveArg<0>(&stream_delegate));
-
-  auto p2p_quic_transport = std::make_unique<MockP2PQuicTransport>();
-  EXPECT_CALL(*p2p_quic_transport, CreateStream())
-      .WillOnce(Return(p2p_quic_stream.get()));
-
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, std::move(p2p_quic_transport));
-  Persistent<RTCQuicStream> quic_stream =
-      quic_transport->createStream(ASSERT_NO_EXCEPTION);
-
-  Persistent<MockEventListener> state_change_listener =
-      CreateMockEventListener();
-  EXPECT_CALL(*state_change_listener, Invoke(_, _))
-      .WillOnce(InvokeWithoutArgs(
-          [quic_stream]() { EXPECT_EQ("closed", quic_stream->state()); }));
-  quic_stream->addEventListener(event_type_names::kStatechange,
-                                state_change_listener);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
-
-  stream_delegate->OnRemoteReset();
-
-  RunUntilIdle();
-}
-
-// Test that a pending OnRemoteReset() is ignored if reset() is called first.
-TEST_F(RTCQuicStreamTest, PendingOnRemoteResetIgnoredAfterReset) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
-  EXPECT_CALL(*p2p_quic_stream, SetDelegate(_))
-      .WillOnce(SaveArg<0>(&stream_delegate));
-
-  auto p2p_quic_transport = std::make_unique<MockP2PQuicTransport>();
-  EXPECT_CALL(*p2p_quic_transport, CreateStream())
-      .WillOnce(Return(p2p_quic_stream.get()));
-
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, std::move(p2p_quic_transport));
-  Persistent<RTCQuicStream> quic_stream =
-      quic_transport->createStream(ASSERT_NO_EXCEPTION);
-
-  // Expect no statechange event since reset() will already transition the state
-  // to 'closed'.
-  Persistent<MockEventListener> state_change_listener =
-      CreateMockEventListener();
-  EXPECT_CALL(*state_change_listener, Invoke(_, _)).Times(0);
-  quic_stream->addEventListener(event_type_names::kStatechange,
-                                state_change_listener);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
-
-  stream_delegate->OnRemoteReset();
-  quic_stream->reset();
-  EXPECT_EQ("closed", quic_stream->state());
-
-  RunUntilIdle();
-
-  EXPECT_EQ("closed", quic_stream->state());
-}
-
-// The following group tests write(), writeBufferedAmount(), and
-// maxWriteBufferdAmount().
-
-// Test that write() adds to writeBufferedAmount().
-TEST_F(RTCQuicStreamTest, WriteAddsToWriteBufferedAmount) {
-  V8TestingScope scope;
-
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  stream->write(CreateWriteParametersWithData({1, 2}), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(2u, stream->writeBufferedAmount());
-
-  stream->write(CreateWriteParametersWithData({3, 4, 5}), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(5u, stream->writeBufferedAmount());
-
-  RunUntilIdle();
-}
-
-// Test that write() calls WriteData() on the underlying P2PQuicStream.
-TEST_F(RTCQuicStreamTest, WriteCallsWriteData) {
-  V8TestingScope scope;
-
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
-  EXPECT_CALL(*p2p_quic_stream, WriteData(_, _))
-      .WillOnce(testing::Invoke([](Vector<uint8_t> data, bool fin) {
-        EXPECT_THAT(data, ElementsAre(1, 2, 3, 4));
-        EXPECT_FALSE(fin);
-      }));
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(CreateWriteParametersWithData({1, 2, 3, 4}),
-                ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-}
-
-// Test that write() with no data throws a NotSupportedError and does not post a
-// WriteData() to the underlying P2PQuicStream.
-TEST_F(RTCQuicStreamTest, WriteWithoutDataThrowsNotSupportedError) {
-  V8TestingScope scope;
-
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
-  EXPECT_CALL(*p2p_quic_stream, WriteData(_, _)).Times(0);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(CreateWriteParametersWithoutData(/*finish=*/false),
-                scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kNotSupportedError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-
-  RunUntilIdle();
-}
-
-// Test that writing a finish without data calls WriteData() on the underlying
-// P2PQuicStream.
-TEST_F(RTCQuicStreamTest, WriteFinishWithoutDataCallsWriteData) {
-  V8TestingScope scope;
-
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
-  EXPECT_CALL(*p2p_quic_stream, WriteData(_, _))
-      .WillOnce(testing::Invoke([](Vector<uint8_t> data, bool fin) {
-        EXPECT_THAT(data, ElementsAre());
-        EXPECT_TRUE(fin);
-      }));
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(CreateWriteParametersWithoutData(/*finish=*/true),
-                ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-}
-
-// Test that writeBufferedAmount is decreased when receiving OnWriteDataConsumed
-// from the underlying P2PQuicStream.
-TEST_F(RTCQuicStreamTest, OnWriteDataConsumedSubtractsFromWriteBufferedAmount) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(CreateWriteParametersWithDataOfLength(4), ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnWriteDataConsumed(4);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(0u, stream->writeBufferedAmount());
-}
-
-// Test that writeBufferedAmount is set to 0 if the stream was reset by the
-// remote peer.
-TEST_F(RTCQuicStreamTest, OnRemoteResetSetsWriteBufferedAmountToZero) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(CreateWriteParametersWithDataOfLength(4), ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
-
-  stream_delegate->OnRemoteReset();
-
-  RunUntilIdle();
-
-  EXPECT_EQ(0u, stream->writeBufferedAmount());
-
-  RunUntilIdle();
-}
-
-// Test that writeBufferedAmount is set to 0 if the stream calls write() with
-// a finish, followed by receiving a finish from the remote side, and reading
-// it out.
-//
-// TODO(https://crbug.com/874296): It doesn't really make sense the write buffer
-// gets cleared in this case. Consider changing this.
-TEST_F(RTCQuicStreamTest,
-       FinishThenReceiveFinishSetsWriteBufferedAmountToZero) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(CreateWriteParametersWithDataOfLength(4, /*finish=*/true),
-                ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
-
-  stream_delegate->OnDataReceived({}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(4u, stream->writeBufferedAmount());
-  NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(10));
-  EXPECT_TRUE(stream->readInto(read_buffer, ASSERT_NO_EXCEPTION)->finished());
-  EXPECT_EQ(0u, stream->writeBufferedAmount());
-
-  RunUntilIdle();
-}
-
-// Test that write throws an InvalidStateError if the stream was reset by the
-// remote peer.
-TEST_F(RTCQuicStreamTest, WriteThrowsIfRemoteReset) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
-
-  stream_delegate->OnRemoteReset();
-
-  RunUntilIdle();
-
-  stream->write(CreateWriteParametersWithDataOfLength(1),
-                scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-
-  RunUntilIdle();
-}
-
-// The following group tests waitForWriteBufferedAmountBelow().
-
-// Test that a waitForWriteBufferedAmountBelow() promise resolves once
-// OnWriteDataConsumed() frees up enough write buffer space.
-TEST_F(RTCQuicStreamTest, WaitForWriteBufferedAmountBelowResolves) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  stream->write(
-      CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
-      ASSERT_NO_EXCEPTION);
-
-  ScriptPromise promise = stream->waitForWriteBufferedAmountBelow(
-      scope.GetScriptState(), stream->maxWriteBufferedAmount() - 1,
-      ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnWriteDataConsumed(1);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that a waitForWriteBufferedAmount() promise does not resolve until
-// OnWriteDataConsumed() frees up exactly the threshold amount.
-TEST_F(RTCQuicStreamTest,
-       WaitForWriteBufferedAmountBelowDoesNotResolveUntilExceedsThreshold) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(
-      CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
-      ASSERT_NO_EXCEPTION);
-
-  ScriptPromise promise = stream->waitForWriteBufferedAmountBelow(
-      scope.GetScriptState(), stream->maxWriteBufferedAmount() - 10,
-      ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-
-  RunUntilIdle();
-
-  // Post OnWriteDataConsumed(9) -- this should not resolve the promise since
-  // we're waiting for 10 bytes to be available.
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnWriteDataConsumed(9);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-
-  // Post OnWriteDataConsumed(1) -- this should resolve the promise since now we
-  // have 9 + 1 = 10 bytes available.
-  stream_delegate->OnWriteDataConsumed(1);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that if two waitForWriteBufferedAmount() promises are waiting on
-// different thresholds, OnWriteDataConsumed() which satisfies the first
-// threshold but not the second will only resolve the first promise. Once
-// OnWriteDataConsumed() is received again past the second threshold then the
-// second promise will be resolved.
-TEST_F(RTCQuicStreamTest,
-       TwoWaitForWriteBufferedAmountBelowPromisesResolveInSequence) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(
-      CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
-      ASSERT_NO_EXCEPTION);
-
-  ScriptPromise promise_10 = stream->waitForWriteBufferedAmountBelow(
-      scope.GetScriptState(), stream->maxWriteBufferedAmount() - 10,
-      ASSERT_NO_EXCEPTION);
-  ScriptPromise promise_90 = stream->waitForWriteBufferedAmountBelow(
-      scope.GetScriptState(), stream->maxWriteBufferedAmount() - 90,
-      ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnWriteDataConsumed(10);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise_10.V8Value().As<v8::Promise>()->State());
-  EXPECT_EQ(v8::Promise::kPending,
-            promise_90.V8Value().As<v8::Promise>()->State());
-
-  stream_delegate->OnWriteDataConsumed(80);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise_90.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that if two waitForWriteBufferedAmount() promises are waiting on
-// different thresholds and a single OnWriteDataConsumed() is received such that
-// the buffered amount is below both thresholds then both promises are resolved.
-TEST_F(RTCQuicStreamTest,
-       TwoWaitForWriteBufferedAmountBelowPromisesResolveTogether) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(
-      CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
-      ASSERT_NO_EXCEPTION);
-
-  ScriptPromise promise_10 = stream->waitForWriteBufferedAmountBelow(
-      scope.GetScriptState(), stream->maxWriteBufferedAmount() - 10,
-      ASSERT_NO_EXCEPTION);
-  ScriptPromise promise_90 = stream->waitForWriteBufferedAmountBelow(
-      scope.GetScriptState(), stream->maxWriteBufferedAmount() - 90,
-      ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnWriteDataConsumed(90);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise_10.V8Value().As<v8::Promise>()->State());
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise_90.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that when receiving OnRemoteReset() the waitForWriteBufferedAmountBelow
-// Promise will be rejected.
-TEST_F(RTCQuicStreamTest,
-       WaitForWriteBufferedAmountBelowPromisesRejectedOnRemoteReset) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(
-      CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
-      ASSERT_NO_EXCEPTION);
-
-  ScriptPromise promise = stream->waitForWriteBufferedAmountBelow(
-      scope.GetScriptState(), 0, ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
-
-  stream_delegate->OnRemoteReset();
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that there is no crash when the ExecutionContext is being destroyed and
-// there are pending waitForWriteBufferedAmountBelow() promises. If the
-// RTCQuicStream attempts to resolve the promise in ContextDestroyed, it will
-// likely crash since the v8::Isolate is being torn down.
-TEST_F(
-    RTCQuicStreamTest,
-    NoCrashIfPendingWaitForWriteBufferedAmountBelowPromisesOnContextDestroyed) {
-  V8TestingScope scope;
-
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  stream->write(
-      CreateWriteParametersWithDataOfLength(stream->maxWriteBufferedAmount()),
-      ASSERT_NO_EXCEPTION);
-
-  stream->waitForWriteBufferedAmountBelow(scope.GetScriptState(), 0,
-                                          ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-}
-
-// The following group tests readInto(), readBufferedAmount(), and
-// maxReadBufferedAmount().
-
-static base::span<const uint8_t> GetSpan(NotShared<DOMUint8Array> data) {
-  return base::make_span(data.View()->Data(), data.View()->lengthAsSizeT());
-}
-
-// Test that readInto() with an empty data buffer succeeds but does not post
-// MarkReceivedDataConsumed() to the underlying P2PQuicStream.
-TEST_F(RTCQuicStreamTest, ReadIntoEmptyDoesNotPostMarkReceivedDataConsumed) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream, MarkReceivedDataConsumed(_)).Times(0);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  EXPECT_EQ(0u, stream->readBufferedAmount());
-
-  NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(0));
-  RTCQuicStreamReadResult* result =
-      stream->readInto(read_buffer, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(0u, result->amount());
-  EXPECT_FALSE(result->finished());
-  EXPECT_EQ(0u, stream->readBufferedAmount());
-
-  RunUntilIdle();
-}
-
-// Test that data delived via OnDataReceived() increases readBufferedAmount.
-TEST_F(RTCQuicStreamTest, OnDataReceivedIncreasesReadBufferedAmount) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/false);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(3u, stream->readBufferedAmount());
-}
-
-// Test that readInto() reads out data received from OnDataReceived() and
-// decreases readBufferedAmount.
-TEST_F(RTCQuicStreamTest, ReadIntoReadsDataFromOnDataReceived) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/false);
-
-  RunUntilIdle();
-
-  NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(5));
-  RTCQuicStreamReadResult* result =
-      stream->readInto(read_buffer, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(3u, result->amount());
-  EXPECT_FALSE(result->finished());
-  EXPECT_THAT(GetSpan(read_buffer), ElementsAre(1, 2, 3, 0, 0));
-  EXPECT_EQ(0u, stream->readBufferedAmount());
-
-  RunUntilIdle();
-}
-
-// Test that readInto() posts MarkReceivedDataConsumed() with the amount of
-// bytes read to the underlying P2PQuicStream.
-TEST_F(RTCQuicStreamTest, ReadIntoPostsMarkReceivedDataConsumed) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream, MarkReceivedDataConsumed(3)).Times(1);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/false);
-
-  RunUntilIdle();
-
-  NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(5));
-  RTCQuicStreamReadResult* result =
-      stream->readInto(read_buffer, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(3u, result->amount());
-  EXPECT_FALSE(result->finished());
-
-  RunUntilIdle();
-}
-
-// Test that readInto() returns {finished: true} if OnDataReceived() has
-// indicated the stream is finished without receiving any data.
-TEST_F(RTCQuicStreamTest, ReadIntoReadsBareFin) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  NotShared<DOMUint8Array> empty_read_buffer(DOMUint8Array::Create(0));
-  RTCQuicStreamReadResult* result =
-      stream->readInto(empty_read_buffer, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(0u, result->amount());
-  EXPECT_TRUE(result->finished());
-
-  RunUntilIdle();
-}
-
-// Test that readInto() indicates finished once all buffered received data has
-// been read.
-TEST_F(RTCQuicStreamTest, ReadIntoReadsBufferedDataAndFinish) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(3));
-  RTCQuicStreamReadResult* result =
-      stream->readInto(read_buffer, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(3u, result->amount());
-  EXPECT_TRUE(result->finished());
-  EXPECT_THAT(GetSpan(read_buffer), ElementsAre(1, 2, 3));
-
-  RunUntilIdle();
-}
-
-// Test that readInto() does not indicate finished until all buffered data has
-// been read out, even if the finish has already been received.
-TEST_F(RTCQuicStreamTest, ReadIntoReadsPartialDataBeforeFin) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  {
-    NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(2));
-    RTCQuicStreamReadResult* result =
-        stream->readInto(read_buffer, ASSERT_NO_EXCEPTION);
-    EXPECT_EQ(2u, result->amount());
-    EXPECT_FALSE(result->finished());
-    EXPECT_THAT(GetSpan(read_buffer), ElementsAre(1, 2));
-  }
-
-  {
-    NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(2));
-    RTCQuicStreamReadResult* result =
-        stream->readInto(read_buffer, ASSERT_NO_EXCEPTION);
-    EXPECT_EQ(1u, result->amount());
-    EXPECT_TRUE(result->finished());
-    EXPECT_THAT(GetSpan(read_buffer), ElementsAre(3, 0));
-  }
-
-  RunUntilIdle();
-}
-
-// Test that readInto() does not post MarkReceivedDataConsumed() to the
-// underlying P2PQuicStream once the finish flag has been delivered in
-// OnDataReceived().
-TEST_F(RTCQuicStreamTest,
-       ReadIntoDoesNotPostMarkReceivedDataConsumedOnceFinReceived) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream, MarkReceivedDataConsumed(_)).Times(0);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(2));
-
-  RTCQuicStreamReadResult* result =
-      stream->readInto(read_buffer, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(2u, result->amount());
-  EXPECT_FALSE(result->finished());
-
-  result = stream->readInto(read_buffer, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(1u, result->amount());
-  EXPECT_TRUE(result->finished());
-
-  RunUntilIdle();
-}
-
-// Test that readInto() throws an InvalidStateError if the finish flag has
-// already been read out.
-TEST_F(RTCQuicStreamTest, ReadIntoThrowsIfFinishAlreadyRead) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(2));
-  EXPECT_TRUE(stream->readInto(read_buffer, ASSERT_NO_EXCEPTION)->finished());
-
-  stream->readInto(read_buffer, scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-}
-
-// Test that readInto() throws an InvalidStateError if the stream is closed.
-TEST_F(RTCQuicStreamTest, ReadIntoThrowsIfClosed) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-  EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
-
-  stream->reset();
-
-  NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(2));
-  stream->readInto(read_buffer, scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-
-  RunUntilIdle();
-}
-
-// The following group tests waitForReadable().
-
-// Test that a waitForReadable() promise resolves once OnDataReceived() delivers
-// enough data.
-TEST_F(RTCQuicStreamTest, WaitForReadableResolves) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  ScriptPromise promise =
-      stream->waitForReadable(scope.GetScriptState(), 3, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/false);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that a waitForReadable() promise resolves immediately if sufficient data
-// is already in the receive buffer.
-TEST_F(RTCQuicStreamTest, WaitForReadableResolveImmediately) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/false);
-
-  RunUntilIdle();
-
-  ScriptPromise promise =
-      stream->waitForReadable(scope.GetScriptState(), 3, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise.V8Value().As<v8::Promise>()->State());
-
-  RunUntilIdle();
-}
-
-// Test that a waitForReadable() promise resolves immediately if finish has
-// been received, but not yet read out.
-TEST_F(RTCQuicStreamTest,
-       WaitForReadableResolveImmediatelyAfterFinishReceived) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  ScriptPromise promise =
-      stream->waitForReadable(scope.GetScriptState(), 10, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise.V8Value().As<v8::Promise>()->State());
-
-  RunUntilIdle();
-}
-
-// Test that a waitForReadable() promise does not resolve until OnDataReceived()
-// delivers at least the readable amount.
-TEST_F(RTCQuicStreamTest, WaitForReadableDoesNotResolveUntilExceedsThreshold) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  ScriptPromise promise =
-      stream->waitForReadable(scope.GetScriptState(), 5, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/false);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-
-  stream_delegate->OnDataReceived({4, 5}, /*fin=*/false);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that if two waitForReadable() promises are waiting on different readable
-// amounts, OnDataReceived() which satisfies the first readable amount but not
-// the second will only resolve the first promise. Once OnDataReceived() is
-// received again with readable amount satisfying the second promise then it
-// will be resolved.
-TEST_F(RTCQuicStreamTest, TwoWaitForReadablePromisesResolveInSequence) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  ScriptPromise promise_3 =
-      stream->waitForReadable(scope.GetScriptState(), 3, ASSERT_NO_EXCEPTION);
-  ScriptPromise promise_5 =
-      stream->waitForReadable(scope.GetScriptState(), 5, ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3}, /*fin=*/false);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise_3.V8Value().As<v8::Promise>()->State());
-  EXPECT_EQ(v8::Promise::kPending,
-            promise_5.V8Value().As<v8::Promise>()->State());
-
-  stream_delegate->OnDataReceived({4, 5}, /*fin=*/false);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise_5.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that if two waitForReadable() promises are waiting on different
-// thresholds and a single OnDataReceived() is received such that the readable
-// amount satisfies both promises then they are both resolved.
-TEST_F(RTCQuicStreamTest, TwoWaitForReadablePromisesResolveTogether) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  ScriptPromise promise_3 =
-      stream->waitForReadable(scope.GetScriptState(), 3, ASSERT_NO_EXCEPTION);
-  ScriptPromise promise_5 =
-      stream->waitForReadable(scope.GetScriptState(), 5, ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({1, 2, 3, 4, 5}, /*fin=*/false);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise_3.V8Value().As<v8::Promise>()->State());
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise_5.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that a remote finish immediately resolves all pending waitForReadable()
-// promises.
-TEST_F(RTCQuicStreamTest, RemoteFinishResolvesPendingWaitForReadablePromises) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  ScriptPromise promise_3 =
-      stream->waitForReadable(scope.GetScriptState(), 3, ASSERT_NO_EXCEPTION);
-  ScriptPromise promise_5 =
-      stream->waitForReadable(scope.GetScriptState(), 5, ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise_3.V8Value().As<v8::Promise>()->State());
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise_5.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that calling waitForReadable() resolves immediately if the finish has
-// been received via OnDataReceived() but not yet read out via readInto().
-// Note: If the finish has been read out via readInto(), waitForReadable() will
-// throw an exception since the stream is no longer readable.
-TEST_F(RTCQuicStreamTest, WaitForReadableResolvesImmediatelyIfRemoteFinished) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  ScriptPromise promise =
-      stream->waitForReadable(scope.GetScriptState(), 5, ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// The following group tests state transitions with reset(), write() with a
-// finish, remote reset() and remote write() with a finish.
-
-// Test that a OnRemoteReset() immediately transitions the state to 'closed'.
-TEST_F(RTCQuicStreamTest, OnRemoteResetTransitionsToClosed) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  EXPECT_EQ("open", stream->state());
-  EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
-
-  stream_delegate->OnRemoteReset();
-
-  RunUntilIdle();
-
-  EXPECT_EQ("closed", stream->state());
-
-  RunUntilIdle();
-}
-
-// Test that writing a finish after reading out a remote finish transitions
-// state to 'closed'.
-TEST_F(RTCQuicStreamTest, FinishAfterReadingRemoteFinishTransitionsToClosed) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream, WriteData(_, true)).Times(1);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  stream_delegate->OnDataReceived({}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(10));
-  EXPECT_TRUE(stream->readInto(read_buffer, ASSERT_NO_EXCEPTION)->finished());
-
-  EXPECT_EQ("closing", stream->state());
-  EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
-
-  stream->write(CreateWriteParametersWithoutData(/*finish=*/true),
-                ASSERT_NO_EXCEPTION);
-
-  EXPECT_EQ("closed", stream->state());
-
-  RunUntilIdle();
-}
-
-// Test that reading out a remote finish after writing a finish transitions
-// state to 'closed'.
-TEST_F(RTCQuicStreamTest, ReadingRemoteFinishAfterFinishTransitionsToClosed) {
-  V8TestingScope scope;
-
-  P2PQuicStream::Delegate* stream_delegate = nullptr;
-  auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream, WriteData(_, true)).Times(1);
-  Persistent<RTCQuicStream> stream =
-      CreateQuicStream(scope, p2p_quic_stream.get());
-
-  stream->write(CreateWriteParametersWithoutData(/*finish=*/true),
-                ASSERT_NO_EXCEPTION);
-
-  EXPECT_EQ("closing", stream->state());
-
-  RunUntilIdle();
-
-  ASSERT_TRUE(stream_delegate);
-  EXPECT_CALL(*p2p_quic_stream.get(), SetDelegate(nullptr));
-
-  stream_delegate->OnDataReceived({}, /*fin=*/true);
-
-  RunUntilIdle();
-
-  EXPECT_EQ("closing", stream->state());
-
-  NotShared<DOMUint8Array> read_buffer(DOMUint8Array::Create(10));
-  EXPECT_TRUE(stream->readInto(read_buffer, ASSERT_NO_EXCEPTION)->finished());
-
-  EXPECT_EQ("closed", stream->state());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_write_parameters.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_write_parameters.idl
deleted file mode 100644
index 2d8d47c2..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_write_parameters.idl
+++ /dev/null
@@ -1,9 +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.
-
-// https://w3c.github.io/webrtc-quic/#dom-rtcquicstreamwriteparameters
-dictionary RTCQuicStreamWriteParameters {
-    Uint8Array data;
-    boolean finish = false;
-};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
deleted file mode 100644
index 1d0953d..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
+++ /dev/null
@@ -1,715 +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/modules/peerconnection/rtc_quic_transport.h"
-
-#include "net/quic/platform/impl/quic_chromium_clock.h"
-#include "net/quic/quic_chromium_alarm_factory.h"
-#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_transport_stats.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
-#include "third_party/blink/renderer/core/dom/events/event.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.h"
-#include "third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_certificate.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h"
-
-namespace blink {
-namespace {
-// QUIC requires 128 bits of entropy for the pre shared key.
-const size_t kPreSharedKeyLength = 128 / 8;
-
-// This class wraps a P2PQuicTransportFactoryImpl but does not construct it
-// until CreateQuicTransport is called for the first time. This ensures that it
-// is executed on the WebRTC worker thread.
-class DefaultP2PQuicTransportFactory : public P2PQuicTransportFactory {
- public:
-  explicit DefaultP2PQuicTransportFactory(
-      scoped_refptr<base::SingleThreadTaskRunner> host_thread)
-      : host_thread_(std::move(host_thread)) {
-    DCHECK(host_thread_);
-  }
-
-  // P2PQuicTransportFactory overrides.
-  std::unique_ptr<P2PQuicTransport> CreateQuicTransport(
-      P2PQuicTransport::Delegate* delegate,
-      P2PQuicPacketTransport* packet_transport,
-      const P2PQuicTransportConfig& config) override {
-    DCHECK(host_thread_->RunsTasksInCurrentSequence());
-    return GetFactory()->CreateQuicTransport(delegate, packet_transport,
-                                             config);
-  }
-
- private:
-  P2PQuicTransportFactory* GetFactory() {
-    DCHECK(host_thread_->RunsTasksInCurrentSequence());
-    if (!factory_impl_) {
-      quic::QuicClock* clock = quic::QuicChromiumClock::GetInstance();
-      auto alarm_factory = std::make_unique<net::QuicChromiumAlarmFactory>(
-          host_thread_.get(), clock);
-      factory_impl_ = std::make_unique<P2PQuicTransportFactoryImpl>(
-          clock, std::move(alarm_factory));
-    }
-    return factory_impl_.get();
-  }
-
-  scoped_refptr<base::SingleThreadTaskRunner> host_thread_;
-  std::unique_ptr<P2PQuicTransportFactory> factory_impl_;
-};
-
-void RejectPromise(ScriptPromiseResolver* promise_resolver,
-                   const char* method_name) {
-  ScriptState::Scope scope(promise_resolver->GetScriptState());
-  ExceptionState exception_state(
-      promise_resolver->GetScriptState()->GetIsolate(),
-      ExceptionState::kExecutionContext, "RTCQuicTransport", method_name);
-  exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
-                                    "The RTCQuicTransport is closed.");
-  promise_resolver->Reject(exception_state);
-}
-
-}  // namespace
-
-RTCQuicTransport* RTCQuicTransport::Create(ExecutionContext* context,
-                                           RTCIceTransport* transport,
-                                           ExceptionState& exception_state) {
-  return Create(context, transport, {}, exception_state);
-}
-
-RTCQuicTransport* RTCQuicTransport::Create(
-    ExecutionContext* context,
-    RTCIceTransport* transport,
-    const HeapVector<Member<RTCCertificate>>& certificates,
-    ExceptionState& exception_state) {
-  return Create(context, transport, certificates, exception_state,
-                std::make_unique<DefaultP2PQuicTransportFactory>(
-                    PeerConnectionDependencyFactory::GetInstance()
-                        ->GetWebRtcNetworkTaskRunner()));
-}
-
-RTCQuicTransport* RTCQuicTransport::Create(
-    ExecutionContext* context,
-    RTCIceTransport* transport,
-    const HeapVector<Member<RTCCertificate>>& certificates,
-    ExceptionState& exception_state,
-    std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory) {
-  DCHECK(context);
-  DCHECK(transport);
-  DCHECK(p2p_quic_transport_factory);
-  if (transport->IsClosed()) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
-                                      "Cannot construct an RTCQuicTransport "
-                                      "with a closed RTCIceTransport.");
-    return nullptr;
-  }
-  if (transport->HasConsumer()) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
-                                      "Cannot construct an RTCQuicTransport "
-                                      "with an RTCIceTransport that already "
-                                      "has a connected RTCQuicTransport.");
-    return nullptr;
-  }
-  if (transport->IsFromPeerConnection()) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "Cannot construct an RTCQuicTransport "
-        "with an RTCIceTransport that came from an "
-        "RTCPeerConnection.");
-    return nullptr;
-  }
-  for (const auto& certificate : certificates) {
-    if (certificate->expires() <
-        ConvertSecondsToDOMTimeStamp(base::Time::Now().ToDoubleT())) {
-      exception_state.ThrowTypeError(
-          "Cannot construct an RTCQuicTransport with an expired "
-          "certificate.");
-      return nullptr;
-    }
-  }
-  uint8_t generated_key[kPreSharedKeyLength];
-  quic::QuicRandom::GetInstance()->RandBytes(generated_key,
-                                             base::size(generated_key));
-  return MakeGarbageCollected<RTCQuicTransport>(
-      context, transport,
-      DOMArrayBuffer::Create(generated_key, base::size(generated_key)),
-      certificates, exception_state, std::move(p2p_quic_transport_factory));
-}
-
-RTCQuicTransport::RTCQuicTransport(
-    ExecutionContext* context,
-    RTCIceTransport* transport,
-    DOMArrayBuffer* key,
-    const HeapVector<Member<RTCCertificate>>& certificates,
-    ExceptionState& exception_state,
-    std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory)
-    : ExecutionContextClient(context),
-      transport_(transport),
-      key_(key),
-      certificates_(certificates),
-      p2p_quic_transport_factory_(std::move(p2p_quic_transport_factory)) {
-  DCHECK_GT(key_->ByteLengthAsSizeT(), 0u);
-  transport->ConnectConsumer(this);
-}
-
-RTCQuicTransport::~RTCQuicTransport() {
-  DCHECK(!proxy_);
-}
-
-RTCIceTransport* RTCQuicTransport::transport() const {
-  return transport_;
-}
-
-String RTCQuicTransport::state() const {
-  switch (state_) {
-    case RTCQuicTransportState::kNew:
-      return "new";
-    case RTCQuicTransportState::kConnecting:
-      return "connecting";
-    case RTCQuicTransportState::kConnected:
-      return "connected";
-    case RTCQuicTransportState::kClosed:
-      return "closed";
-    case RTCQuicTransportState::kFailed:
-      return "failed";
-  }
-  return String();
-}
-
-DOMArrayBuffer* RTCQuicTransport::getKey() const {
-  return DOMArrayBuffer::Create(key_->Data(), key_->ByteLengthAsSizeT());
-}
-
-void RTCQuicTransport::connect(ExceptionState& exception_state) {
-  if (RaiseExceptionIfClosed(exception_state)) {
-    return;
-  }
-  if (RaiseExceptionIfStarted(exception_state)) {
-    return;
-  }
-  start_reason_ = StartReason::kClientConnecting;
-  std::string pre_shared_key(static_cast<const char*>(key_->Data()),
-                             key_->ByteLengthAsSizeT());
-  StartConnection(quic::Perspective::IS_CLIENT,
-                  P2PQuicTransport::StartConfig(pre_shared_key));
-}
-
-void RTCQuicTransport::listen(const DOMArrayPiece& remote_key,
-                              ExceptionState& exception_state) {
-  if (remote_key.ByteLengthAsSizeT() == 0u) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
-                                      "Cannot listen with an empty key.");
-    return;
-  }
-  if (RaiseExceptionIfClosed(exception_state)) {
-    return;
-  }
-  if (RaiseExceptionIfStarted(exception_state)) {
-    return;
-  }
-  start_reason_ = StartReason::kServerListening;
-  std::string pre_shared_key(static_cast<const char*>(remote_key.Data()),
-                             remote_key.ByteLengthAsSizeT());
-  StartConnection(quic::Perspective::IS_SERVER,
-                  P2PQuicTransport::StartConfig(pre_shared_key));
-}
-
-RTCQuicParameters* RTCQuicTransport::getLocalParameters() const {
-  RTCQuicParameters* result = RTCQuicParameters::Create();
-
-  HeapVector<Member<RTCDtlsFingerprint>> fingerprints;
-  for (const auto& certificate : certificates_) {
-    // TODO(github.com/w3c/webrtc-quic/issues/33): The specification says that
-    // getLocalParameters should return one fingerprint per certificate but is
-    // not clear which one to pick if an RTCCertificate has multiple
-    // fingerprints.
-    for (const auto& certificate_fingerprint : certificate->getFingerprints()) {
-      fingerprints.push_back(certificate_fingerprint);
-    }
-  }
-  result->setFingerprints(fingerprints);
-  return result;
-}
-
-RTCQuicParameters* RTCQuicTransport::getRemoteParameters() const {
-  return remote_parameters_;
-}
-
-const HeapVector<Member<RTCCertificate>>& RTCQuicTransport::getCertificates()
-    const {
-  return certificates_;
-}
-
-const HeapVector<Member<DOMArrayBuffer>>&
-RTCQuicTransport::getRemoteCertificates() const {
-  return remote_certificates_;
-}
-
-static quic::Perspective QuicPerspectiveFromIceRole(cricket::IceRole ice_role) {
-  switch (ice_role) {
-    case cricket::ICEROLE_CONTROLLED:
-      return quic::Perspective::IS_CLIENT;
-    case cricket::ICEROLE_CONTROLLING:
-      return quic::Perspective::IS_SERVER;
-    default:
-      NOTREACHED();
-  }
-  return quic::Perspective::IS_CLIENT;
-}
-
-static std::unique_ptr<rtc::SSLFingerprint> RTCDtlsFingerprintToSSLFingerprint(
-    const RTCDtlsFingerprint* dtls_fingerprint) {
-  std::string algorithm = dtls_fingerprint->algorithm().Utf8();
-  std::string value = dtls_fingerprint->value().Utf8();
-  std::unique_ptr<rtc::SSLFingerprint> rtc_fingerprint =
-      rtc::SSLFingerprint::CreateUniqueFromRfc4572(algorithm, value);
-  DCHECK(rtc_fingerprint);
-  return rtc_fingerprint;
-}
-
-void RTCQuicTransport::start(RTCQuicParameters* remote_parameters,
-                             ExceptionState& exception_state) {
-  if (RaiseExceptionIfClosed(exception_state)) {
-    return;
-  }
-  if (RaiseExceptionIfStarted(exception_state)) {
-    return;
-  }
-  remote_parameters_ = remote_parameters;
-  start_reason_ = StartReason::kP2PWithRemoteFingerprints;
-  if (transport_->IsStarted()) {
-    Vector<std::unique_ptr<rtc::SSLFingerprint>> rtc_fingerprints;
-    for (const RTCDtlsFingerprint* fingerprint :
-         remote_parameters_->fingerprints()) {
-      rtc_fingerprints.push_back(
-          RTCDtlsFingerprintToSSLFingerprint(fingerprint));
-    };
-    StartConnection(QuicPerspectiveFromIceRole(transport_->GetRole()),
-                    P2PQuicTransport::StartConfig(std::move(rtc_fingerprints)));
-  }
-}
-
-void RTCQuicTransport::StartConnection(
-    quic::Perspective perspective,
-    P2PQuicTransport::StartConfig start_config) {
-  DCHECK_EQ(state_, RTCQuicTransportState::kNew);
-  DCHECK_NE(start_reason_, StartReason::kNotStarted);
-
-  state_ = RTCQuicTransportState::kConnecting;
-  // We don't create the underlying transports until we are starting
-  // to connect.
-  Vector<rtc::scoped_refptr<rtc::RTCCertificate>> rtc_certificates;
-  for (const auto& certificate : certificates_) {
-    rtc_certificates.push_back(certificate->Certificate());
-  }
-  IceTransportProxy* transport_proxy = transport_->ConnectConsumer(this);
-  P2PQuicTransportConfig quic_transport_config(
-      perspective, rtc_certificates,
-      /*stream_delegate_read_buffer_size_in=*/RTCQuicStream::kReadBufferSize,
-      /*stream_write_buffer_size_in=*/RTCQuicStream::kWriteBufferSize);
-  proxy_.reset(new QuicTransportProxy(this, transport_proxy,
-                                      std::move(p2p_quic_transport_factory_),
-                                      quic_transport_config));
-  proxy_->Start(std::move(start_config));
-}
-
-void RTCQuicTransport::OnIceTransportStarted() {
-  // If start() has already been called, we now start up the connection,
-  // since start() determines its quic::Perspective based upon ICE.
-  if (start_reason_ == StartReason::kP2PWithRemoteFingerprints) {
-    DCHECK(remote_parameters_);
-    Vector<std::unique_ptr<rtc::SSLFingerprint>> rtc_fingerprints;
-    for (const RTCDtlsFingerprint* fingerprint :
-         remote_parameters_->fingerprints()) {
-      rtc_fingerprints.push_back(
-          RTCDtlsFingerprintToSSLFingerprint(fingerprint));
-    };
-    StartConnection(QuicPerspectiveFromIceRole(transport_->GetRole()),
-                    P2PQuicTransport::StartConfig(std::move(rtc_fingerprints)));
-  }
-}
-
-void RTCQuicTransport::stop() {
-  if (IsClosed()) {
-    // The transport could have already been closed due to the context being
-    // destroyed, the RTCIceTransport closing or a remote/local stop().
-    return;
-  }
-  if (IsDisposed()) {
-    // This occurs in the "failed" state.
-    state_ = RTCQuicTransportState::kClosed;
-    return;
-  }
-  Close(CloseReason::kLocalStopped);
-}
-
-RTCQuicStream* RTCQuicTransport::createStream(ExceptionState& exception_state) {
-  // TODO(github.com/w3c/webrtc-quic/issues/50): Maybe support createStream in
-  // the 'new' or 'connecting' states.
-  if (state_ != RTCQuicTransportState::kConnected) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
-                                      "RTCQuicTransport.createStream() is only "
-                                      "valid in the 'connected' state.");
-    return nullptr;
-  }
-  return AddStream(proxy_->CreateStream());
-}
-
-ScriptPromise RTCQuicTransport::readyToSendDatagram(
-    ScriptState* script_state,
-    ExceptionState& exception_state) {
-  if (ready_to_send_datagram_promise_) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "Pending readyToSendDatagram promise exists");
-    return ScriptPromise();
-  }
-  if (RaiseExceptionIfNotConnected(exception_state)) {
-    return ScriptPromise();
-  }
-
-  auto* promise_resolver =
-      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  ScriptPromise promise = promise_resolver->Promise();
-  if (CanWriteDatagram()) {
-    promise_resolver->Resolve();
-    return promise;
-  }
-  ready_to_send_datagram_promise_ = promise_resolver;
-  return promise;
-}
-
-void RTCQuicTransport::sendDatagram(const DOMArrayPiece& data,
-                                    ExceptionState& exception_state) {
-  if (RaiseExceptionIfNotConnected(exception_state)) {
-    return;
-  }
-  if (!CanWriteDatagram()) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "Cannot send datagram because not readyToSend()");
-    return;
-  }
-  if (data.ByteLengthAsSizeT() > max_datagram_length_) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "data of size " + String::Number(data.ByteLengthAsSizeT()) +
-            " is too large to fit into a datagram of max size: " +
-            String::Number(max_datagram_length_.value_or(0)));
-    return;
-  }
-
-  Vector<uint8_t> datagram(static_cast<wtf_size_t>(data.ByteLengthAsSizeT()));
-  memcpy(datagram.data(), data.Data(), data.ByteLengthAsSizeT());
-  proxy_->SendDatagram(std::move(datagram));
-  num_buffered_sent_datagrams_++;
-}
-
-ScriptPromise RTCQuicTransport::receiveDatagrams(
-    ScriptState* script_state,
-    ExceptionState& exception_state) {
-  if (receive_datagrams_promise_) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "Pending receiveDatagrams promise exists");
-    return ScriptPromise();
-  }
-
-  if (RaiseExceptionIfNotConnected(exception_state)) {
-    return ScriptPromise();
-  }
-
-  auto* promise_resolver =
-      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  ScriptPromise promise = promise_resolver->Promise();
-  if (received_datagrams_.IsEmpty()) {
-    receive_datagrams_promise_ = promise_resolver;
-    return promise;
-  }
-  HeapVector<Member<DOMArrayBuffer>> resolved_datagrams;
-  resolved_datagrams.swap(received_datagrams_);
-  promise_resolver->Resolve(resolved_datagrams);
-  return promise;
-}
-
-ScriptPromise RTCQuicTransport::getStats(ScriptState* script_state,
-                                         ExceptionState& exception_state) {
-  // TODO(https://crbug.com/874296): If a shutdown procedure is implemented, we
-  // can cache the stats before the underlying transport is torn down. This
-  // would allow getting stats after your transport has closed.
-  if (state_ != RTCQuicTransportState::kConnected &&
-      state_ != RTCQuicTransportState::kConnecting) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The RTCQuicTransport's state is not 'connecting' or 'connected'.");
-    return ScriptPromise();
-  }
-  auto* promise_resolver =
-      MakeGarbageCollected<ScriptPromiseResolver>(script_state);
-  uint32_t request_id = ++get_stats_id_counter_;
-  stats_promise_map_.Set(request_id, promise_resolver);
-  proxy_->GetStats(request_id);
-  return promise_resolver->Promise();
-}
-
-RTCQuicStream* RTCQuicTransport::AddStream(QuicStreamProxy* stream_proxy) {
-  auto* stream = MakeGarbageCollected<RTCQuicStream>(GetExecutionContext(),
-                                                     this, stream_proxy);
-  stream_proxy->set_delegate(stream);
-  streams_.insert(stream);
-  return stream;
-}
-
-void RTCQuicTransport::RemoveStream(RTCQuicStream* stream) {
-  DCHECK(stream);
-  auto it = streams_.find(stream);
-  DCHECK(it != streams_.end());
-  streams_.erase(it);
-}
-
-void RTCQuicTransport::OnConnected(P2PQuicNegotiatedParams negotiated_params) {
-  // Datagrams should always be supported between RTCQuicTransport endpoints.
-  DCHECK(negotiated_params.datagrams_supported());
-  max_datagram_length_ = negotiated_params.max_datagram_length();
-  state_ = RTCQuicTransportState::kConnected;
-  DispatchEvent(*Event::Create(event_type_names::kStatechange));
-}
-
-void RTCQuicTransport::OnConnectionFailed(const std::string& error_details,
-                                          bool from_remote) {
-  Close(CloseReason::kFailed);
-}
-
-void RTCQuicTransport::OnRemoteStopped() {
-  Close(CloseReason::kRemoteStopped);
-}
-
-void RTCQuicTransport::OnStream(QuicStreamProxy* stream_proxy) {
-  RTCQuicStream* stream = AddStream(stream_proxy);
-  DispatchEvent(*MakeGarbageCollected<RTCQuicStreamEvent>(stream));
-}
-
-static RTCQuicTransportStats* CreateRTCQuicTransportStats(
-    const P2PQuicTransportStats& p2p_stats) {
-  RTCQuicTransportStats* rtc_stats = RTCQuicTransportStats::Create();
-  rtc_stats->setTimestamp(
-      ConvertTimeTicksToDOMHighResTimeStamp(p2p_stats.timestamp));
-  rtc_stats->setBytesSent(p2p_stats.bytes_sent);
-  rtc_stats->setPacketsSent(p2p_stats.packets_sent);
-  rtc_stats->setStreamBytesSent(p2p_stats.stream_bytes_sent);
-  rtc_stats->setStreamBytesReceived(p2p_stats.stream_bytes_received);
-  rtc_stats->setNumOutgoingStreamsCreated(
-      p2p_stats.num_outgoing_streams_created);
-  rtc_stats->setNumIncomingStreamsCreated(
-      p2p_stats.num_incoming_streams_created);
-  rtc_stats->setBytesReceived(p2p_stats.bytes_received);
-  rtc_stats->setPacketsReceived(p2p_stats.packets_received);
-  rtc_stats->setPacketsProcessed(p2p_stats.packets_processed);
-  rtc_stats->setBytesRetransmitted(p2p_stats.bytes_retransmitted);
-  rtc_stats->setPacketsRetransmitted(p2p_stats.packets_retransmitted);
-  rtc_stats->setPacketsLost(p2p_stats.packets_lost);
-  rtc_stats->setPacketsDropped(p2p_stats.packets_dropped);
-  rtc_stats->setCryptoRetransmitCount(p2p_stats.crypto_retransmit_count);
-  rtc_stats->setMinRttUs(p2p_stats.min_rtt_us);
-  rtc_stats->setSmoothedRttUs(p2p_stats.srtt_us);
-  rtc_stats->setMaxPacketSize(p2p_stats.max_packet_size);
-  rtc_stats->setMaxReceivedPacketSize(p2p_stats.max_received_packet_size);
-  rtc_stats->setEstimatedBandwidthBps(p2p_stats.estimated_bandwidth_bps);
-  rtc_stats->setPacketsReordered(p2p_stats.packets_reordered);
-  rtc_stats->setBlockedFramesReceived(p2p_stats.blocked_frames_received);
-  rtc_stats->setBlockedFramesSent(p2p_stats.blocked_frames_sent);
-  rtc_stats->setConnectivityProbingPacketsReceived(
-      p2p_stats.connectivity_probing_packets_received);
-  rtc_stats->setNumDatagramsLost(p2p_stats.num_datagrams_lost);
-  return rtc_stats;
-}
-
-void RTCQuicTransport::OnStats(uint32_t request_id,
-                               const P2PQuicTransportStats& stats) {
-  auto it = stats_promise_map_.find(request_id);
-  DCHECK(it != stats_promise_map_.end());
-  ScriptPromiseResolver* resolver = it->value;
-  stats_promise_map_.erase(it);
-
-  RTCQuicTransportStats* rtc_stats = CreateRTCQuicTransportStats(stats);
-  rtc_stats->setNumReceivedDatagramsDropped(num_dropped_received_datagrams_);
-
-  // Resolving a promise can cause user code to run, so do this last.
-  // See crbug.com/1108472
-  resolver->Resolve(rtc_stats);
-}
-
-void RTCQuicTransport::OnDatagramSent() {
-  num_buffered_sent_datagrams_--;
-  DCHECK_GE(num_buffered_sent_datagrams_, 0);
-
-  // There may be a pending readyToSend promise that can now be resolved.
-  if (ready_to_send_datagram_promise_) {
-    ready_to_send_datagram_promise_.Release()->Resolve();
-  }
-}
-
-void RTCQuicTransport::OnDatagramReceived(Vector<uint8_t> datagram) {
-  DOMArrayBuffer* copied_datagram = DOMArrayBuffer::Create(
-      static_cast<void*>(datagram.data()), datagram.size());
-  if (receive_datagrams_promise_) {
-    // We have an pending promise to resolve with received datagrams.
-    HeapVector<Member<DOMArrayBuffer>> received_datagrams;
-    received_datagrams.push_back(copied_datagram);
-    receive_datagrams_promise_.Release()->Resolve(received_datagrams);
-    return;
-  }
-  if (received_datagrams_.size() == kMaxBufferedRecvDatagrams) {
-    num_dropped_received_datagrams_++;
-    return;
-  }
-  received_datagrams_.push_back(copied_datagram);
-}
-
-void RTCQuicTransport::OnIceTransportClosed(
-    RTCIceTransport::CloseReason reason) {
-  if (reason == RTCIceTransport::CloseReason::kContextDestroyed) {
-    Close(CloseReason::kContextDestroyed);
-  } else {
-    Close(CloseReason::kIceTransportClosed);
-  }
-}
-
-void RTCQuicTransport::Close(CloseReason reason) {
-  DCHECK(!IsDisposed());
-
-  // Disconnect from the RTCIceTransport, allowing a new RTCQuicTransport to
-  // connect to it.
-  transport_->DisconnectConsumer(this);
-
-  // Notify the active streams that the transport is closing.
-  for (RTCQuicStream* stream : streams_) {
-    stream->OnQuicTransportClosed(reason);
-  }
-  streams_.clear();
-
-  // Tear down the QuicTransportProxy and change the state.
-  switch (reason) {
-    case CloseReason::kLocalStopped:
-    case CloseReason::kIceTransportClosed:
-    case CloseReason::kContextDestroyed:
-      // The QuicTransportProxy may be active so gracefully Stop() before
-      // destroying it.
-      if (proxy_) {
-        proxy_->Stop();
-        proxy_.reset();
-      }
-      state_ = RTCQuicTransportState::kClosed;
-      break;
-    case CloseReason::kRemoteStopped:
-    case CloseReason::kFailed:
-      // The QuicTransportProxy has already been closed by the event, so just
-      // go ahead and delete it.
-      proxy_.reset();
-      state_ =
-          (reason == CloseReason::kFailed ? RTCQuicTransportState::kFailed
-                                          : RTCQuicTransportState::kClosed);
-      DispatchEvent(*Event::Create(event_type_names::kStatechange));
-      break;
-  }
-  received_datagrams_.clear();
-
-  if (reason != CloseReason::kContextDestroyed) {
-    // Cannot reject/resolve promises when ExecutionContext is being destroyed.
-    RejectPendingPromises();
-  }
-
-  DCHECK(!proxy_);
-  DCHECK(IsDisposed());
-}
-
-bool RTCQuicTransport::RaiseExceptionIfClosed(
-    ExceptionState& exception_state) const {
-  if (IsClosed()) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The RTCQuicTransport's state is 'closed'.");
-    return true;
-  }
-  return false;
-}
-
-bool RTCQuicTransport::RaiseExceptionIfNotConnected(
-    ExceptionState& exception_state) const {
-  if (state_ != RTCQuicTransportState::kConnected) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "RTCQuicTransport is not in the 'connected' state.");
-    return true;
-  }
-  return false;
-}
-
-bool RTCQuicTransport::RaiseExceptionIfStarted(
-    ExceptionState& exception_state) const {
-  if (start_reason_ == StartReason::kServerListening) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The RTCQuicTransport has already called listen().");
-    return true;
-  }
-  if (start_reason_ == StartReason::kClientConnecting) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The RTCQuicTransport has already called connect().");
-    return true;
-  }
-  if (start_reason_ == StartReason::kP2PWithRemoteFingerprints) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidStateError,
-        "The RTCQuicTransport has already called start().");
-    return true;
-  }
-  return false;
-}
-
-void RTCQuicTransport::RejectPendingPromises() {
-  for (ScriptPromiseResolver* promise_resolver : stats_promise_map_.Values()) {
-    RejectPromise(promise_resolver, "getStats");
-  }
-  stats_promise_map_.clear();
-  if (ready_to_send_datagram_promise_) {
-    RejectPromise(ready_to_send_datagram_promise_.Release(),
-                  "readyToSendDatagram");
-  }
-  if (receive_datagrams_promise_) {
-    RejectPromise(receive_datagrams_promise_.Release(), "receiveDatagrams");
-  }
-}
-
-const AtomicString& RTCQuicTransport::InterfaceName() const {
-  return event_target_names::kRTCQuicTransport;
-}
-
-ExecutionContext* RTCQuicTransport::GetExecutionContext() const {
-  return ExecutionContextClient::GetExecutionContext();
-}
-
-void RTCQuicTransport::Trace(Visitor* visitor) const {
-  visitor->Trace(transport_);
-  visitor->Trace(certificates_);
-  visitor->Trace(remote_certificates_);
-  visitor->Trace(remote_parameters_);
-  visitor->Trace(streams_);
-  visitor->Trace(key_);
-  visitor->Trace(stats_promise_map_);
-  visitor->Trace(receive_datagrams_promise_);
-  visitor->Trace(ready_to_send_datagram_promise_);
-  visitor->Trace(received_datagrams_);
-  EventTargetWithInlineData::Trace(visitor);
-  ExecutionContextClient::Trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h
deleted file mode 100644
index 11ff5be..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h
+++ /dev/null
@@ -1,273 +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_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_H_
-
-#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_parameters.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h"
-#include "third_party/blink/renderer/modules/event_target_modules.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/quic_transport_proxy.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
-
-namespace blink {
-
-class DOMArrayBuffer;
-class ExceptionState;
-class RTCCertificate;
-class RTCQuicStream;
-class P2PQuicTransportFactory;
-
-enum class RTCQuicTransportState {
-  kNew,
-  kConnecting,
-  kConnected,
-  kClosed,
-  kFailed
-};
-
-// The number of datagrams we are willing to buffer send side.
-//
-// This buffer exists to account for the thread hop delay in knowing if the
-// QUIC connection is congestion control blocked or not. Ideally it should
-// stay small to keep latency for sending datagrams low, but a higher value
-// allows for higher throughput.
-//
-// Note: This value is not based upon measurements, but a guess for suitable
-// throughput. More investigation could be done to tune this value.
-const uint16_t kMaxBufferedSendDatagrams = 5;
-
-// The number of datagrams we are willing to buffer on the receive side before
-// dropping them. This is so that if the main thread freezes datagrams aren't
-// lost, without buffering them indefinitely.
-//
-// This value was chosen because the max datagram size is ~1.2 KB, meaning
-// a max ~6MB of buffering, which currently is the same arbitrary value used for
-// buffering stream data currently.
-const uint32_t kMaxBufferedRecvDatagrams = 5000;
-
-// The RTCQuicTransport does not need to be ActiveScriptWrappable since the
-// RTCIceTransport to which it is attached holds a strong reference to it as
-// long as it is alive.
-class MODULES_EXPORT RTCQuicTransport final
-    : public EventTargetWithInlineData,
-      public ExecutionContextClient,
-      public QuicTransportProxy::Delegate {
-  DEFINE_WRAPPERTYPEINFO();
-
- public:
-  enum class CloseReason {
-    // stop() was called.
-    kLocalStopped,
-    // The remote side closed the QUIC connection.
-    kRemoteStopped,
-    // The QUIC connection failed.
-    kFailed,
-    // The RTCIceTransport was closed.
-    kIceTransportClosed,
-    // The ExecutionContext is being destroyed.
-    kContextDestroyed,
-  };
-
-  static RTCQuicTransport* Create(ExecutionContext* context,
-                                  RTCIceTransport* transport,
-                                  ExceptionState& exception_state);
-  static RTCQuicTransport* Create(
-      ExecutionContext* context,
-      RTCIceTransport* transport,
-      const HeapVector<Member<RTCCertificate>>& certificates,
-      ExceptionState& exception_state);
-  static RTCQuicTransport* Create(
-      ExecutionContext* context,
-      RTCIceTransport* transport,
-      const HeapVector<Member<RTCCertificate>>& certificates,
-      ExceptionState& exception_state,
-      std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory);
-
-  RTCQuicTransport(
-      ExecutionContext* context,
-      RTCIceTransport* transport,
-      DOMArrayBuffer* key,
-      const HeapVector<Member<RTCCertificate>>& certificates,
-      ExceptionState& exception_state,
-      std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory);
-  ~RTCQuicTransport() override;
-
-  // Called by the RTCIceTransport when it is being closed.
-  void OnIceTransportClosed(RTCIceTransport::CloseReason reason);
-
-  // Called by the RTCIceTransport when its start() method is called.
-  void OnIceTransportStarted();
-
-  RTCQuicStream* AddStream(QuicStreamProxy* stream_proxy);
-  void RemoveStream(RTCQuicStream* stream);
-
-  // https://w3c.github.io/webrtc-quic/#quic-transport*
-  RTCIceTransport* transport() const;
-
-  // The pre shared key to be used in the QUIC handshake with connect().
-  // This should be signaled to the remote endpoint and used with the remote
-  // endpoint's listen() function to begin a connection.
-  DOMArrayBuffer* getKey() const;
-
-  // The maximum datagram size in bytes allowed with sendDatagram.
-  // Before the transport has become connected this will be 0.
-  base::Optional<uint16_t> maxDatagramLength() const {
-    return max_datagram_length_;
-  }
-
-  String state() const;
-  // Note: The listen/connect functions encourage an API user to connect()
-  // before the remote endpoint has called listen(), which can result in the
-  // CHLO being sent before the server side is ready. Although the CHLO is
-  // cached by the RTCIceTransport (if it is connected), the API user is
-  // encouraged to not connect() until the remote endpoint has called listen().
-  // An API design with the server side generating the pre shared key would
-  // enforce this, but we purposely constrained the client side to generate the
-  // key to enforce that a browser endpoint is generating the key in the case of
-  // communicating with a non-browser, server side endpoint.
-  //
-  // Begins the QUIC handshake as a client endpoint, using the internal |key_|
-  // as the pre shared key for the QUIC handshake.
-  void connect(ExceptionState& exception_state);
-  // Begins listening for the QUIC handshake as a server endpoint. Uses
-  // the |remote_key| from the remote side as a pre shared key in the QUIC
-  // handshake.
-  void listen(const DOMArrayPiece& remote_key, ExceptionState& exception_state);
-  // The following APIs that include certificates/parameters (including start())
-  // are not used (or exposed to JavaScript) until QUIC supports both side
-  // certificate verification.
-  RTCQuicParameters* getLocalParameters() const;
-  RTCQuicParameters* getRemoteParameters() const;
-  const HeapVector<Member<RTCCertificate>>& getCertificates() const;
-  const HeapVector<Member<DOMArrayBuffer>>& getRemoteCertificates() const;
-  void start(RTCQuicParameters* remote_parameters,
-             ExceptionState& exception_state);
-
-  void stop();
-  RTCQuicStream* createStream(ExceptionState& exception_state);
-  // Throws InvalidStateError if called when previous promise returned from
-  // readyToSendDatagram is still pending. Resolves when transport is not
-  // blocked by congestion control for sending a datagram. This will resolve
-  // immediately if transport is not blocked.
-  ScriptPromise readyToSendDatagram(ScriptState* script_state,
-                                    ExceptionState& exception_state);
-  // Note: This deviates from the spec, which returns a promise that fulfills if
-  // the datagram is acked/lost. See unresolved issue:
-  // https://github.com/w3c/webrtc-quic/issues/117
-  void sendDatagram(const DOMArrayPiece& data, ExceptionState& exception_state);
-  // Throws InvalidStateError if called when previous promise returned from
-  // receiveDatagrams is still pending. If datagrams have been buffered since
-  // the last call to receiveDatagrams, this will resolve immediately with the
-  // buffered datagrams. Otherwise it will resolve when a datagram is received.
-  // When too many datagrams are buffered they will be dropped. This will be
-  // reflected in the stats.
-  //
-  // Note: This deviates from the spec, which specifies adding a null value to
-  // the end of the sequence if datagrams are dropped. Instead, stats includes
-  // numReceivedDatagramsDropped. See issue:
-  // https://github.com/w3c/webrtc-quic/issues/124
-  ScriptPromise receiveDatagrams(ScriptState* script_state,
-                                 ExceptionState& exception_state);
-
-  // Resolves the promise with an RTCQuicTransportStats dictionary.
-  ScriptPromise getStats(ScriptState* script_state,
-                         ExceptionState& exception_state);
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange, kStatechange)
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(error, kError)
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(quicstream, kQuicstream)
-
-  // EventTarget overrides.
-  const AtomicString& InterfaceName() const override;
-  ExecutionContext* GetExecutionContext() const override;
-
-  // For garbage collection.
-  void Trace(Visitor* visitor) const override;
-
- private:
-  enum class StartReason {
-    // listen() was called with the remote key.
-    kServerListening,
-    // connect() was called.
-    kClientConnecting,
-    // start() was called with the remote fingerprints.
-    // Note that start() is not currently exposed to JavaScript.
-    kP2PWithRemoteFingerprints,
-    // Initial default state.
-    kNotStarted,
-  };
-
-  // QuicTransportProxy::Delegate overrides;
-  void OnConnected(P2PQuicNegotiatedParams negotiated_params) override;
-  void OnConnectionFailed(const std::string& error_details,
-                          bool from_remote) override;
-  void OnRemoteStopped() override;
-  void OnStream(QuicStreamProxy* stream_proxy) override;
-  void OnStats(uint32_t request_id,
-               const P2PQuicTransportStats& stats) override;
-  void OnDatagramSent() override;
-  void OnDatagramReceived(Vector<uint8_t> datagram) override;
-
-  // Starts the underlying QUIC connection, by creating the underlying QUIC
-  // transport objects and starting the QUIC handshake.
-  void StartConnection(quic::Perspective role,
-                       P2PQuicTransport::StartConfig start_config);
-
-  // Permenantly closes the RTCQuicTransport with the given reason.
-  // The RTCQuicTransport must not already be closed or failed.
-  // This will transition the state to either closed or failed according to the
-  // reason.
-  void Close(CloseReason reason);
-
-  bool IsClosed() const { return state_ == RTCQuicTransportState::kClosed; }
-  // The transport is no longer usable once it has reached the "failed" or
-  // "closed" state.
-  bool IsDisposed() const {
-    return (state_ == RTCQuicTransportState::kClosed ||
-            state_ == RTCQuicTransportState::kFailed);
-  }
-  bool CanWriteDatagram() const {
-    return num_buffered_sent_datagrams_ < kMaxBufferedSendDatagrams;
-  }
-  bool RaiseExceptionIfClosed(ExceptionState& exception_state) const;
-  bool RaiseExceptionIfNotConnected(ExceptionState& exception_state) const;
-  bool RaiseExceptionIfStarted(ExceptionState& exception_state) const;
-  void RejectPendingPromises();
-
-  Member<RTCIceTransport> transport_;
-  RTCQuicTransportState state_ = RTCQuicTransportState::kNew;
-  StartReason start_reason_ = StartReason::kNotStarted;
-  // The pre shared key to be used in the QUIC handshake. It is used with
-  // connect() on the local side, and listen() on the remote side.
-  Member<DOMArrayBuffer> key_;
-  // The certificates/parameters are not being used until the QUIC library
-  // supports both side certificate verification in the crypto handshake.
-  HeapVector<Member<RTCCertificate>> certificates_;
-  HeapVector<Member<DOMArrayBuffer>> remote_certificates_;
-  Member<RTCQuicParameters> remote_parameters_;
-  std::unique_ptr<P2PQuicTransportFactory> p2p_quic_transport_factory_;
-  std::unique_ptr<QuicTransportProxy> proxy_;
-  HeapHashSet<Member<RTCQuicStream>> streams_;
-  // Maps from the ID of the stats request to the promise to be resolved.
-  HeapHashMap<uint32_t, Member<ScriptPromiseResolver>> stats_promise_map_;
-  uint32_t get_stats_id_counter_ = 0;
-  // The number of datagrams that have been given to QUIC but not sent on the
-  // network yet. This could be due to congestion control.
-  int num_buffered_sent_datagrams_ = 0;
-  // The number of datagrams that dropped because the RTCQuicTransport has
-  // received more datagrams than its max buffer size and there is no way to
-  // indicate backpressure to the send side.
-  uint32_t num_dropped_received_datagrams_ = 0;
-  HeapVector<Member<DOMArrayBuffer>> received_datagrams_;
-  base::Optional<uint16_t> max_datagram_length_;
-  Member<ScriptPromiseResolver> receive_datagrams_promise_;
-  Member<ScriptPromiseResolver> ready_to_send_datagram_promise_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_H_
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl
deleted file mode 100644
index 54524edf..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.idl
+++ /dev/null
@@ -1,39 +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.
-
-// https://w3c.github.io/webrtc-quic/#dom-rtcquictransportstate
-enum RTCQuicTransportState {
-    "new",
-    "connecting",
-    "connected",
-    "closed",
-    "failed",
-};
-
-// https://w3c.github.io/webrtc-quic/#quic-transport*
-[
-   Exposed=Window,
-   RuntimeEnabled=RTCQuicTransport,
-   SecureContext
-] interface RTCQuicTransport : EventTarget {
-    [CallWith=ExecutionContext, RaisesException, Measure] constructor(RTCIceTransport transport);
-    [Measure] readonly attribute RTCIceTransport transport;
-    [Measure] readonly attribute RTCQuicTransportState state;
-    [Measure] readonly attribute unsigned short? maxDatagramLength;
-    [Measure] ArrayBuffer getKey();
-    [Measure, RaisesException] void connect();
-    [Measure, RaisesException] void listen(BufferSource remote_key);
-    [Measure] void stop();
-    [Measure, RaisesException] RTCQuicStream createStream();
-    [CallWith=ScriptState, Measure, RaisesException]
-    Promise<void> readyToSendDatagram();
-    [Measure, RaisesException] void sendDatagram(BufferSource data);
-    [CallWith=ScriptState, Measure, RaisesException]
-    Promise<sequence<ArrayBuffer>> receiveDatagrams();
-    [CallWith=ScriptState, Measure, RaisesException]
-    Promise<RTCQuicTransportStats> getStats();
-    attribute EventHandler onstatechange;
-    attribute EventHandler onerror;
-    attribute EventHandler onquicstream;
-};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl
deleted file mode 100644
index 935dc653..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_stats.idl
+++ /dev/null
@@ -1,32 +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.
-
-dictionary RTCQuicTransportStats {
-  double timestamp;
-  unsigned long long bytesSent;
-  unsigned long long packetsSent;
-  unsigned long long streamBytesSent;
-  unsigned long long streamBytesReceived;
-  unsigned long numOutgoingStreamsCreated;
-  unsigned long numIncomingStreamsCreated;
-  unsigned long long bytesReceived;
-  unsigned long long packetsReceived;
-  unsigned long long packetsProcessed;
-  unsigned long long bytesRetransmitted;
-  unsigned long long packetsRetransmitted;
-  unsigned long long packetsLost;
-  unsigned long long packetsDropped;
-  unsigned long long cryptoRetransmitCount;
-  unsigned long long minRttUs;
-  unsigned long long smoothedRttUs;
-  unsigned long long maxPacketSize;
-  unsigned long long maxReceivedPacketSize;
-  unsigned long long estimatedBandwidthBps;
-  unsigned long long packetsReordered;
-  unsigned long long blockedFramesReceived;
-  unsigned long long blockedFramesSent;
-  unsigned long long connectivityProbingPacketsReceived;
-  unsigned long numReceivedDatagramsDropped;
-  unsigned long numDatagramsLost;
-};
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc
deleted file mode 100644
index 64ef497..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.cc
+++ /dev/null
@@ -1,1169 +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.
-
-// This file tests the RTCQuicTransport Blink bindings, QuicTransportProxy and
-// QuicTransportHost by mocking out the underlying P2PQuicTransport.
-// Everything is run on a single thread but with separate TestSimpleTaskRunners
-// for the main thread / worker thread.
-
-#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h"
-#include "base/containers/span.h"
-#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_gather_options.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_quic_transport_stats.h"
-#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
-#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_stats.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_packet_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/webrtc/rtc_base/rtc_certificate_generator.h"
-
-namespace blink {
-namespace {
-
-using testing::_;
-using testing::Assign;
-using testing::ElementsAre;
-using testing::Invoke;
-using testing::Mock;
-using testing::Return;
-
-HeapVector<Member<RTCCertificate>> GenerateLocalRTCCertificates() {
-  HeapVector<Member<RTCCertificate>> certificates;
-  certificates.push_back(MakeGarbageCollected<RTCCertificate>(
-      rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams::ECDSA(),
-                                                        absl::nullopt)));
-  return certificates;
-}
-
-constexpr char kRemoteFingerprintAlgorithm1[] = "sha-256";
-constexpr char kRemoteFingerprintValue1[] =
-    "8E:57:5F:8E:65:D2:83:7B:05:97:BB:72:DE:09:DE:03:BD:95:9B:A0:03:10:50:82:"
-    "5E:73:38:16:4C:E0:C5:84";
-const size_t kKeyLength = 16;
-const uint8_t kKey[kKeyLength] = {0, 1, 2,  3,  4,  5,  6,  7,
-                                  8, 9, 10, 11, 12, 13, 14, 15};
-// Arbitrary datagram.
-const size_t kDatagramLength = 4;
-const uint8_t kDatagram[kDatagramLength] = {0, 1, 2, 3};
-const uint16_t kMaxDatagramLengthBytes = 1000;
-
-RTCDtlsFingerprint* CreateRemoteFingerprint1() {
-  RTCDtlsFingerprint* dtls_fingerprint = RTCDtlsFingerprint::Create();
-  dtls_fingerprint->setAlgorithm(kRemoteFingerprintAlgorithm1);
-  dtls_fingerprint->setValue(kRemoteFingerprintValue1);
-  return dtls_fingerprint;
-}
-
-RTCQuicParameters* CreateRemoteRTCQuicParameters1() {
-  HeapVector<Member<RTCDtlsFingerprint>> fingerprints;
-  fingerprints.push_back(CreateRemoteFingerprint1());
-  RTCQuicParameters* quic_parameters = RTCQuicParameters::Create();
-  quic_parameters->setFingerprints(fingerprints);
-  return quic_parameters;
-}
-
-// Sends datagrams without getting callbacks that they have been sent on the
-// network until the buffer becomes full.
-void FillDatagramBuffer(RTCQuicTransport* transport) {
-  for (size_t i = 0; i < kMaxBufferedSendDatagrams; ++i) {
-    transport->sendDatagram(DOMArrayBuffer::Create(kDatagram, kDatagramLength),
-                            ASSERT_NO_EXCEPTION);
-  }
-}
-
-static base::span<uint8_t> SpanFromDOMArrayBuffer(DOMArrayBuffer* buffer) {
-  return base::span<uint8_t>(static_cast<uint8_t*>(buffer->Data()),
-                             buffer->ByteLengthAsSizeT());
-}
-
-}  // namespace
-
-RTCQuicTransport* RTCQuicTransportTest::CreateQuicTransport(
-    V8TestingScope& scope,
-    RTCIceTransport* ice_transport,
-    const HeapVector<Member<RTCCertificate>>& certificates,
-    std::unique_ptr<MockP2PQuicTransport> mock_transport,
-    P2PQuicTransport::Delegate** delegate_out) {
-  return CreateQuicTransport(scope, ice_transport, certificates,
-                             std::make_unique<MockP2PQuicTransportFactory>(
-                                 std::move(mock_transport), delegate_out));
-}
-
-RTCQuicTransport* RTCQuicTransportTest::CreateQuicTransport(
-    V8TestingScope& scope,
-    RTCIceTransport* ice_transport,
-    const HeapVector<Member<RTCCertificate>>& certificates,
-    std::unique_ptr<MockP2PQuicTransportFactory> mock_factory) {
-  return RTCQuicTransport::Create(scope.GetExecutionContext(), ice_transport,
-                                  certificates, ASSERT_NO_EXCEPTION,
-                                  std::move(mock_factory));
-}
-
-RTCQuicTransport* RTCQuicTransportTest::CreateConnectedQuicTransport(
-    V8TestingScope& scope,
-    P2PQuicTransport::Delegate** delegate_out) {
-  return CreateConnectedQuicTransport(
-      scope, std::make_unique<MockP2PQuicTransport>(), delegate_out);
-}
-
-RTCQuicTransport* RTCQuicTransportTest::CreateConnectedQuicTransport(
-    V8TestingScope& scope,
-    std::unique_ptr<MockP2PQuicTransport> mock_transport,
-    P2PQuicTransport::Delegate** delegate_out) {
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport), &delegate);
-  quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
-  RunUntilIdle();
-  DCHECK(delegate);
-  P2PQuicNegotiatedParams params;
-  params.set_max_datagram_length(kMaxDatagramLengthBytes);
-  delegate->OnConnected(params);
-  RunUntilIdle();
-  DCHECK_EQ("connected", quic_transport->state());
-  if (delegate_out) {
-    *delegate_out = delegate;
-  }
-  return quic_transport;
-}
-
-// Test that calling start() creates a P2PQuicTransport with the correct
-// P2PQuicTransportConfig. The config should have:
-// 1. The P2PQuicPacketTransport returned by the MockIceTransportAdapter.
-// 2. Server mode configured since the ICE role is 'controlling'.
-// 3. The certificates passed in the RTCQuicTransport constructor.
-TEST_F(RTCQuicTransportTest, P2PQuicTransportConstructedByStart) {
-  V8TestingScope scope;
-
-  auto quic_packet_transport = std::make_unique<MockP2PQuicPacketTransport>();
-  auto* quic_packet_transport_ptr = quic_packet_transport.get();
-  auto ice_transport_adapter_mock = std::make_unique<MockIceTransportAdapter>(
-      std::move(quic_packet_transport));
-  Persistent<RTCIceTransport> ice_transport =
-      CreateIceTransport(scope, std::move(ice_transport_adapter_mock));
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  rtc::scoped_refptr<rtc::RTCCertificate> certificate =
-      rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams::ECDSA(),
-                                                        absl::nullopt);
-  auto mock_factory = std::make_unique<MockP2PQuicTransportFactory>();
-  EXPECT_CALL(*mock_factory, CreateQuicTransport(_, _, _))
-      .WillOnce(Invoke([quic_packet_transport_ptr, certificate](
-                           P2PQuicTransport::Delegate* delegate,
-                           P2PQuicPacketTransport* packet_transport,
-                           const P2PQuicTransportConfig& config) {
-        EXPECT_EQ(quic_packet_transport_ptr, packet_transport);
-        EXPECT_EQ(quic::Perspective::IS_SERVER, config.perspective);
-        EXPECT_THAT(config.certificates, ElementsAre(certificate));
-        return std::make_unique<MockP2PQuicTransport>();
-      }));
-  HeapVector<Member<RTCCertificate>> certificates;
-  certificates.push_back(MakeGarbageCollected<RTCCertificate>(certificate));
-  Persistent<RTCQuicTransport> quic_transport = CreateQuicTransport(
-      scope, ice_transport, certificates, std::move(mock_factory));
-  quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
-}
-
-// Test that calling connect() creates a P2PQuicTransport with the correct
-// P2PQuicTransportConfig. The config should have:
-// 1. The P2PQuicPacketTransport returned by the MockIceTransportAdapter.
-// 2. Client mode configured.
-TEST_F(RTCQuicTransportTest, P2PQuicTransportConstructedByConnect) {
-  V8TestingScope scope;
-
-  auto quic_packet_transport = std::make_unique<MockP2PQuicPacketTransport>();
-  auto* quic_packet_transport_ptr = quic_packet_transport.get();
-  auto ice_transport_adapter_mock = std::make_unique<MockIceTransportAdapter>(
-      std::move(quic_packet_transport));
-  Persistent<RTCIceTransport> ice_transport =
-      CreateIceTransport(scope, std::move(ice_transport_adapter_mock));
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_factory = std::make_unique<MockP2PQuicTransportFactory>();
-  EXPECT_CALL(*mock_factory, CreateQuicTransport(_, _, _))
-      .WillOnce(Invoke(
-          [quic_packet_transport_ptr](P2PQuicTransport::Delegate* delegate,
-                                      P2PQuicPacketTransport* packet_transport,
-                                      const P2PQuicTransportConfig& config) {
-            EXPECT_EQ(quic_packet_transport_ptr, packet_transport);
-            EXPECT_EQ(quic::Perspective::IS_CLIENT, config.perspective);
-            return std::make_unique<MockP2PQuicTransport>();
-          }));
-
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, {}, std::move(mock_factory));
-  quic_transport->connect(ASSERT_NO_EXCEPTION);
-}
-
-// Test that calling listen() creates a P2PQuicTransport with the correct
-// P2PQuicTransportConfig. The config should have:
-// 1. The P2PQuicPacketTransport returned by the MockIceTransportAdapter.
-// 2. Server mode configured.
-TEST_F(RTCQuicTransportTest, P2PQuicTransportConstructedByListen) {
-  V8TestingScope scope;
-
-  auto quic_packet_transport = std::make_unique<MockP2PQuicPacketTransport>();
-  auto* quic_packet_transport_ptr = quic_packet_transport.get();
-  auto ice_transport_adapter_mock = std::make_unique<MockIceTransportAdapter>(
-      std::move(quic_packet_transport));
-  Persistent<RTCIceTransport> ice_transport =
-      CreateIceTransport(scope, std::move(ice_transport_adapter_mock));
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_factory = std::make_unique<MockP2PQuicTransportFactory>();
-  EXPECT_CALL(*mock_factory, CreateQuicTransport(_, _, _))
-      .WillOnce(Invoke(
-          [quic_packet_transport_ptr](P2PQuicTransport::Delegate* delegate,
-                                      P2PQuicPacketTransport* packet_transport,
-                                      const P2PQuicTransportConfig& config) {
-            EXPECT_EQ(quic_packet_transport_ptr, packet_transport);
-            EXPECT_EQ(quic::Perspective::IS_SERVER, config.perspective);
-            return std::make_unique<MockP2PQuicTransport>();
-          }));
-
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, {}, std::move(mock_factory));
-  quic_transport->listen(DOMArrayBuffer::Create(kKey, kKeyLength),
-                         ASSERT_NO_EXCEPTION);
-}
-
-// Test that calling start() creates a P2PQuicTransport with client perspective
-// if the RTCIceTransport role is 'controlled'.
-TEST_F(RTCQuicTransportTest, P2PQuicTransportConstructedByStartClient) {
-  V8TestingScope scope;
-
-  auto ice_transport_adapter_mock = std::make_unique<MockIceTransportAdapter>(
-      std::make_unique<MockP2PQuicPacketTransport>());
-  Persistent<RTCIceTransport> ice_transport =
-      CreateIceTransport(scope, std::move(ice_transport_adapter_mock));
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlled",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_factory = std::make_unique<MockP2PQuicTransportFactory>(
-      std::make_unique<MockP2PQuicTransport>());
-  EXPECT_CALL(*mock_factory, CreateQuicTransport(_, _, _))
-      .WillOnce(Invoke([](P2PQuicTransport::Delegate* delegate,
-                          P2PQuicPacketTransport* packet_transport,
-                          const P2PQuicTransportConfig& config) {
-        EXPECT_EQ(quic::Perspective::IS_CLIENT, config.perspective);
-        return std::make_unique<MockP2PQuicTransport>();
-      }));
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_factory));
-  quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
-}
-
-// Test that calling start() calls Start() on the P2PQuicTransport with the
-// correct remote fingerprints.
-TEST_F(RTCQuicTransportTest, StartPassesRemoteFingerprints) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  EXPECT_CALL(*mock_transport, MockStart(_))
-      .WillOnce(Invoke([](const P2PQuicTransport::StartConfig& config) {
-        ASSERT_EQ(1u, config.remote_fingerprints.size());
-        EXPECT_EQ(kRemoteFingerprintAlgorithm1,
-                  config.remote_fingerprints[0]->algorithm);
-        EXPECT_EQ(kRemoteFingerprintValue1,
-                  config.remote_fingerprints[0]->GetRfc4572Fingerprint());
-      }));
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport));
-  quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
-}
-
-// Test that calling start() with a started RTCIceTransport changes its state to
-// connecting.
-TEST_F(RTCQuicTransportTest, StartWithConnectedTransportChangesToConnecting) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport));
-  quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ("connecting", quic_transport->state());
-}
-
-// Test that calling start() changes its state to connecting once
-// RTCIceTransport starts.
-TEST_F(RTCQuicTransportTest, StartChangesToConnectingWhenIceStarts) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport));
-  quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ("new", quic_transport->state());
-
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-  EXPECT_EQ("connecting", quic_transport->state());
-}
-
-// Test that calling start() twice throws a kInvalidStateError.
-TEST_F(RTCQuicTransportTest, StartTwiceThrowsError) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport));
-  quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
-
-  quic_transport->start(CreateRemoteRTCQuicParameters1(),
-                        scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-}
-
-// Test that calling start() after connect() throws a kInvalidStateError.
-TEST_F(RTCQuicTransportTest, StartAfterConnectThrowsError) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport));
-  quic_transport->connect(ASSERT_NO_EXCEPTION);
-
-  quic_transport->start(CreateRemoteRTCQuicParameters1(),
-                        scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-}
-
-// Test that calling start() after listen() throws a kInvalidStateError.
-TEST_F(RTCQuicTransportTest, StartAfterListenThrowsError) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport));
-  quic_transport->listen(DOMArrayBuffer::Create(kKey, kKeyLength),
-                         ASSERT_NO_EXCEPTION);
-
-  quic_transport->start(CreateRemoteRTCQuicParameters1(),
-                        scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-}
-
-// Test that calling start() after stop() throws a kInvalidStateError.
-TEST_F(RTCQuicTransportTest, StartAfterStopThrowsError) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport));
-
-  quic_transport->stop();
-  quic_transport->start(CreateRemoteRTCQuicParameters1(),
-                        scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-}
-
-// Test that calling start() after RTCIceTransport::stop() throws a
-// kInvalidStateError.
-TEST_F(RTCQuicTransportTest, StartAfterIceStopsThrowsError) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport));
-
-  ice_transport->stop();
-  quic_transport->start(CreateRemoteRTCQuicParameters1(),
-                        scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-}
-
-// Test that calling connect() calls Start() on the P2PQuicTransport with the
-// generated pre shared key from the local side.
-TEST_F(RTCQuicTransportTest, ConnectPassesPreSharedKey) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  auto* mock_transport_ptr = mock_transport.get();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, {}, std::move(mock_transport));
-  DOMArrayBuffer* key = quic_transport->getKey();
-  std::string pre_shared_key(static_cast<const char*>(key->Data()),
-                             key->ByteLengthAsSizeT());
-
-  EXPECT_CALL(*mock_transport_ptr, MockStart(_))
-      .WillOnce(
-          Invoke([pre_shared_key](const P2PQuicTransport::StartConfig& config) {
-            EXPECT_EQ(pre_shared_key, config.pre_shared_key);
-          }));
-  quic_transport->connect(ASSERT_NO_EXCEPTION);
-}
-
-// Test that calling listen() calls Start() on the P2PQuicTransport with the
-// correct given pre shared key from the remote side.
-TEST_F(RTCQuicTransportTest, ListenPassesPreSharedKey) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  auto* mock_transport_ptr = mock_transport.get();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, {}, std::move(mock_transport));
-
-  std::string pre_shared_key = "foobar";
-  EXPECT_CALL(*mock_transport_ptr, MockStart(_))
-      .WillOnce(
-          Invoke([pre_shared_key](const P2PQuicTransport::StartConfig& config) {
-            EXPECT_EQ(pre_shared_key, config.pre_shared_key);
-          }));
-
-  quic_transport->listen(
-      DOMArrayBuffer::Create(pre_shared_key.c_str(), pre_shared_key.length()),
-      ASSERT_NO_EXCEPTION);
-}
-
-// Test that calling stop() deletes the underlying P2PQuicTransport.
-TEST_F(RTCQuicTransportTest, StopCallsStopThenDeletesQuicTransportAdapter) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  bool mock_deleted = false;
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  EXPECT_CALL(*mock_transport, Stop()).Times(1);
-  EXPECT_CALL(*mock_transport, Die()).WillOnce(Assign(&mock_deleted, true));
-
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport));
-  quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
-
-  quic_transport->stop();
-  RunUntilIdle();
-
-  EXPECT_TRUE(mock_deleted);
-}
-
-// Test that calling stop() on the underlying RTCIceTransport deletes the
-// underlying P2PQuicTransport.
-TEST_F(RTCQuicTransportTest, RTCIceTransportStopDeletesP2PQuicTransport) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-
-  bool mock_deleted = false;
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  EXPECT_CALL(*mock_transport, Die()).WillOnce(Assign(&mock_deleted, true));
-
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport));
-  quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
-
-  ice_transport->stop();
-  RunUntilIdle();
-
-  EXPECT_TRUE(mock_deleted);
-}
-
-// Test that the P2PQuicTransport is deleted and the RTCQuicTransport goes to
-// the "failed" state when the QUIC connection fails.
-TEST_F(RTCQuicTransportTest,
-       ConnectionFailedBecomesClosedAndDeletesP2PQuicTransport) {
-  V8TestingScope scope;
-
-  bool mock_deleted = false;
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  EXPECT_CALL(*mock_transport, Die()).WillOnce(Assign(&mock_deleted, true));
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
-  DCHECK(delegate);
-  delegate->OnConnectionFailed("test_failure", /*from_remote=*/false);
-  RunUntilIdle();
-
-  EXPECT_TRUE(mock_deleted);
-  EXPECT_EQ("failed", quic_transport->state());
-}
-
-// Test that after the connection fails, stop() will change the state
-// of the transport to "closed".
-TEST_F(RTCQuicTransportTest, StopAfterConnectionFailed) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport = CreateConnectedQuicTransport(
-      scope, std::make_unique<MockP2PQuicTransport>(), &delegate);
-  DCHECK(delegate);
-  delegate->OnConnectionFailed("test_failure", /*from_remote=*/false);
-  RunUntilIdle();
-
-  EXPECT_EQ("failed", quic_transport->state());
-
-  quic_transport->stop();
-  EXPECT_EQ("closed", quic_transport->state());
-}
-
-// Test that the P2PQuicTransport is deleted when the underlying RTCIceTransport
-// is ContextDestroyed.
-TEST_F(RTCQuicTransportTest,
-       RTCIceTransportContextDestroyedDeletesP2PQuicTransport) {
-  bool mock_deleted = false;
-  {
-    V8TestingScope scope;
-
-    Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-    ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                         ASSERT_NO_EXCEPTION);
-
-    auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-    EXPECT_CALL(*mock_transport, Die()).WillOnce(Assign(&mock_deleted, true));
-
-    Persistent<RTCQuicTransport> quic_transport = CreateQuicTransport(
-        scope, ice_transport, GenerateLocalRTCCertificates(),
-        std::move(mock_transport));
-    quic_transport->start(CreateRemoteRTCQuicParameters1(),
-                          ASSERT_NO_EXCEPTION);
-  }  // ContextDestroyed when V8TestingScope goes out of scope.
-
-  RunUntilIdle();
-
-  EXPECT_TRUE(mock_deleted);
-}
-
-// Test that the certificate passed to RTCQuicTransport is the same
-// returned by getCertificates().
-TEST_F(RTCQuicTransportTest, GetCertificatesReturnsGivenCertificates) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  auto certificates = GenerateLocalRTCCertificates();
-  Persistent<RTCQuicTransport> quic_transport = CreateQuicTransport(
-      scope, ice_transport, certificates, std::move(mock_transport));
-  auto returned_certificates = quic_transport->getCertificates();
-
-  EXPECT_EQ(certificates[0], returned_certificates[0]);
-}
-
-// Test that the fingerprint returned by getLocalParameters() is
-// the fingerprint of the certificate passed to the RTCQuicTransport.
-TEST_F(RTCQuicTransportTest,
-       GetLocalParametersReturnsGivenCertificatesFingerprints) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  auto certificates = GenerateLocalRTCCertificates();
-  auto fingerprints = certificates[0]->getFingerprints();
-  Persistent<RTCQuicTransport> quic_transport = CreateQuicTransport(
-      scope, ice_transport, certificates, std::move(mock_transport));
-  auto returned_fingerprints =
-      quic_transport->getLocalParameters()->fingerprints();
-
-  EXPECT_EQ(1u, returned_fingerprints.size());
-  EXPECT_EQ(fingerprints.size(), returned_fingerprints.size());
-  EXPECT_EQ(fingerprints[0]->value(), returned_fingerprints[0]->value());
-  EXPECT_EQ(fingerprints[0]->algorithm(),
-            returned_fingerprints[0]->algorithm());
-}
-
-TEST_F(RTCQuicTransportTest, ExpiredCertificateThrowsError) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  auto mock_factory = std::make_unique<MockP2PQuicTransportFactory>();
-  HeapVector<Member<RTCCertificate>> certificates;
-  certificates.push_back(MakeGarbageCollected<RTCCertificate>(
-      rtc::RTCCertificateGenerator::GenerateCertificate(rtc::KeyParams::ECDSA(),
-                                                        /*expires_ms=*/0)));
-  RTCQuicTransport::Create(scope.GetExecutionContext(), ice_transport,
-                           certificates, scope.GetExceptionState(),
-                           std::move(mock_factory));
-  EXPECT_EQ(ESErrorType::kTypeError,
-            scope.GetExceptionState().CodeAs<ESErrorType>());
-}
-
-// Test that the key returned has at least 128 bits of entropy as required by
-// QUIC.
-TEST_F(RTCQuicTransportTest, GetKeyReturnsValidKey) {
-  V8TestingScope scope;
-
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, {}, std::move(mock_transport));
-  auto* key = quic_transport->getKey();
-
-  EXPECT_GE(key->ByteLengthAsSizeT(), 16u);
-}
-
-// Test that stats are converted correctly to the RTCQuicTransportStats
-// dictionary.
-TEST_F(RTCQuicTransportTest, OnStatsConvertsRTCStatsDictionary) {
-  V8TestingScope scope;
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  MockP2PQuicTransport* mock_transport_ptr = mock_transport.get();
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
-  DCHECK(delegate);
-
-  // Create some dummy values.
-  P2PQuicTransportStats stats;
-  stats.bytes_sent = 0;
-  stats.packets_sent = 1;
-  stats.stream_bytes_sent = 2;
-  stats.stream_bytes_received = 3;
-  stats.num_outgoing_streams_created = 4;
-  stats.num_incoming_streams_created = 5;
-  stats.bytes_received = 6;
-  stats.packets_received = 7;
-  stats.packets_processed = 8;
-  stats.bytes_retransmitted = 9;
-  stats.packets_retransmitted = 10;
-  stats.packets_lost = 11;
-  stats.packets_dropped = 12;
-  stats.crypto_retransmit_count = 13;
-  stats.min_rtt_us = 14;
-  stats.srtt_us = 15;
-  stats.max_packet_size = 16;
-  stats.max_received_packet_size = 17;
-  stats.estimated_bandwidth_bps = 18;
-  stats.packets_reordered = 19;
-  stats.blocked_frames_received = 20;
-  stats.blocked_frames_sent = 21;
-  stats.connectivity_probing_packets_received = 22;
-  stats.num_datagrams_lost = 23;
-  EXPECT_CALL(*mock_transport_ptr, GetStats()).WillOnce(Return(stats));
-  ScriptPromise stats_promise =
-      quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-
-  RunUntilIdle();
-
-  ASSERT_EQ(v8::Promise::kFulfilled,
-            stats_promise.V8Value().As<v8::Promise>()->State());
-
-  RTCQuicTransportStats* rtc_quic_stats =
-      NativeValueTraits<RTCQuicTransportStats>::NativeValue(
-          scope.GetIsolate(),
-          stats_promise.V8Value().As<v8::Promise>()->Result(),
-          ASSERT_NO_EXCEPTION);
-  ASSERT_TRUE(rtc_quic_stats->hasTimestamp());
-  EXPECT_EQ(ConvertTimeTicksToDOMHighResTimeStamp(stats.timestamp),
-            rtc_quic_stats->timestamp());
-  ASSERT_TRUE(rtc_quic_stats->hasBytesSent());
-  EXPECT_EQ(stats.bytes_sent, rtc_quic_stats->bytesSent());
-  ASSERT_TRUE(rtc_quic_stats->hasPacketsSent());
-  EXPECT_EQ(stats.packets_sent, rtc_quic_stats->packetsSent());
-  ASSERT_TRUE(rtc_quic_stats->hasStreamBytesSent());
-  EXPECT_EQ(stats.stream_bytes_sent, rtc_quic_stats->streamBytesSent());
-  ASSERT_TRUE(rtc_quic_stats->hasStreamBytesSent());
-  EXPECT_EQ(stats.stream_bytes_received, rtc_quic_stats->streamBytesReceived());
-  ASSERT_TRUE(rtc_quic_stats->hasNumOutgoingStreamsCreated());
-  EXPECT_EQ(stats.num_outgoing_streams_created,
-            rtc_quic_stats->numOutgoingStreamsCreated());
-  ASSERT_TRUE(rtc_quic_stats->hasNumIncomingStreamsCreated());
-  EXPECT_EQ(stats.num_incoming_streams_created,
-            rtc_quic_stats->numIncomingStreamsCreated());
-  ASSERT_TRUE(rtc_quic_stats->hasBytesReceived());
-  EXPECT_EQ(stats.bytes_received, rtc_quic_stats->bytesReceived());
-  ASSERT_TRUE(rtc_quic_stats->hasPacketsReceived());
-  EXPECT_EQ(stats.packets_received, rtc_quic_stats->packetsReceived());
-  ASSERT_TRUE(rtc_quic_stats->hasPacketsProcessed());
-  EXPECT_EQ(stats.packets_processed, rtc_quic_stats->packetsProcessed());
-  ASSERT_TRUE(rtc_quic_stats->hasBytesRetransmitted());
-  EXPECT_EQ(stats.bytes_retransmitted, rtc_quic_stats->bytesRetransmitted());
-  ASSERT_TRUE(rtc_quic_stats->hasPacketsRetransmitted());
-  EXPECT_EQ(stats.packets_retransmitted,
-            rtc_quic_stats->packetsRetransmitted());
-  ASSERT_TRUE(rtc_quic_stats->hasPacketsLost());
-  EXPECT_EQ(stats.packets_lost, rtc_quic_stats->packetsLost());
-  ASSERT_TRUE(rtc_quic_stats->hasPacketsDropped());
-  EXPECT_EQ(stats.packets_dropped, rtc_quic_stats->packetsDropped());
-  ASSERT_TRUE(rtc_quic_stats->hasCryptoRetransmitCount());
-  EXPECT_EQ(stats.crypto_retransmit_count,
-            rtc_quic_stats->cryptoRetransmitCount());
-  ASSERT_TRUE(rtc_quic_stats->hasMinRttUs());
-  EXPECT_EQ(stats.min_rtt_us, rtc_quic_stats->minRttUs());
-  ASSERT_TRUE(rtc_quic_stats->hasSmoothedRttUs());
-  EXPECT_EQ(stats.srtt_us, rtc_quic_stats->smoothedRttUs());
-  ASSERT_TRUE(rtc_quic_stats->hasMaxPacketSize());
-  EXPECT_EQ(stats.max_packet_size, rtc_quic_stats->maxPacketSize());
-  ASSERT_TRUE(rtc_quic_stats->hasMaxReceivedPacketSize());
-  EXPECT_EQ(stats.max_received_packet_size,
-            rtc_quic_stats->maxReceivedPacketSize());
-  ASSERT_TRUE(rtc_quic_stats->hasEstimatedBandwidthBps());
-  EXPECT_EQ(stats.estimated_bandwidth_bps,
-            rtc_quic_stats->estimatedBandwidthBps());
-  ASSERT_TRUE(rtc_quic_stats->hasPacketsReordered());
-  EXPECT_EQ(stats.packets_reordered, rtc_quic_stats->packetsReordered());
-  ASSERT_TRUE(rtc_quic_stats->hasBlockedFramesReceived());
-  EXPECT_EQ(stats.blocked_frames_received,
-            rtc_quic_stats->blockedFramesReceived());
-  ASSERT_TRUE(rtc_quic_stats->hasBlockedFramesSent());
-  EXPECT_EQ(stats.blocked_frames_sent, rtc_quic_stats->blockedFramesSent());
-  ASSERT_TRUE(rtc_quic_stats->hasConnectivityProbingPacketsReceived());
-  EXPECT_EQ(stats.connectivity_probing_packets_received,
-            rtc_quic_stats->connectivityProbingPacketsReceived());
-  ASSERT_TRUE(rtc_quic_stats->hasNumDatagramsLost());
-  EXPECT_EQ(stats.num_datagrams_lost, rtc_quic_stats->numDatagramsLost());
-}
-
-// Test that all promises are rejected if the connection closes before
-// the OnStats callback is called.
-TEST_F(RTCQuicTransportTest, FailedConnectionRejectsStatsPromises) {
-  V8TestingScope scope;
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
-  DCHECK(delegate);
-
-  ScriptPromise promise_1 =
-      quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  ScriptPromise promise_2 =
-      quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  delegate->OnConnectionFailed("test_failure", /*from_remote=*/false);
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise_1.V8Value().As<v8::Promise>()->State());
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise_2.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that all promises are rejected if the remote side closes before
-// the OnStats callback is called.
-TEST_F(RTCQuicTransportTest, RemoteStopRejectsStatsPromises) {
-  V8TestingScope scope;
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
-  DCHECK(delegate);
-
-  ScriptPromise promise_1 =
-      quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  ScriptPromise promise_2 =
-      quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  delegate->OnRemoteStopped();
-
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise_1.V8Value().As<v8::Promise>()->State());
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise_2.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that calling getStats() after going to the "failed" state
-// raises a kInvalidStateError.
-TEST_F(RTCQuicTransportTest, FailedStateGetStatsRaisesInvalidStateError) {
-  V8TestingScope scope;
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
-  DCHECK(delegate);
-
-  delegate->OnRemoteStopped();
-  RunUntilIdle();
-
-  quic_transport->getStats(scope.GetScriptState(), scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-}
-
-// Test that the max datagram length is updated properly when the transport
-// becomes connected.
-TEST_F(RTCQuicTransportTest, MaxDatagramLengthComesFromNegotiatedParams) {
-  V8TestingScope scope;
-  Persistent<RTCIceTransport> ice_transport = CreateIceTransport(scope);
-  ice_transport->start(CreateRemoteRTCIceParameters1(), "controlling",
-                       ASSERT_NO_EXCEPTION);
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateQuicTransport(scope, ice_transport, GenerateLocalRTCCertificates(),
-                          std::move(mock_transport), &delegate);
-  quic_transport->start(CreateRemoteRTCQuicParameters1(), ASSERT_NO_EXCEPTION);
-  RunUntilIdle();
-  P2PQuicNegotiatedParams params;
-  uint16_t max_datagram_length = 10;
-  params.set_max_datagram_length(max_datagram_length);
-  delegate->OnConnected(params);
-  RunUntilIdle();
-  ASSERT_EQ("connected", quic_transport->state());
-  ASSERT_TRUE(quic_transport->maxDatagramLength().has_value());
-  EXPECT_EQ(max_datagram_length, quic_transport->maxDatagramLength().value());
-}
-
-// Test that sending a datagram after the buffer is full will raise a
-// kInvalidStateError.
-TEST_F(RTCQuicTransportTest, SendingWhenNotReadyRaisesInvalidStateError) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-
-  FillDatagramBuffer(quic_transport);
-  RunUntilIdle();
-
-  quic_transport->sendDatagram(
-      DOMArrayBuffer::Create(kDatagram, kDatagramLength),
-      scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-}
-
-// Test that calling readyToSend before the last promise has resolved raises a
-// kInvalidStateError.
-TEST_F(RTCQuicTransportTest, ReadyToSendTwiceRaisesInvalidStateError) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-
-  FillDatagramBuffer(quic_transport);
-  RunUntilIdle();
-
-  quic_transport->readyToSendDatagram(scope.GetScriptState(),
-                                      ASSERT_NO_EXCEPTION);
-  quic_transport->readyToSendDatagram(scope.GetScriptState(),
-                                      scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-}
-
-// Test that readyToSend promise will be pending until transport is no longer
-// congestion control blocked.
-TEST_F(RTCQuicTransportTest, ReadyToSendPromiseResolvesWhenReady) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-  FillDatagramBuffer(quic_transport);
-  RunUntilIdle();
-
-  ScriptPromise promise = quic_transport->readyToSendDatagram(
-      scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-
-  delegate->OnDatagramSent();
-  RunUntilIdle();
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that the pending readyToSend proimise will be rejected if stop() is
-// called.
-TEST_F(RTCQuicTransportTest, ReadyToSendPromiseRejectedWithStop) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-  FillDatagramBuffer(quic_transport);
-  RunUntilIdle();
-
-  ScriptPromise promise = quic_transport->readyToSendDatagram(
-      scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-  quic_transport->stop();
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that the pending readyToSend proimise will be rejected if stop() is
-// called on the RTCIceTransport.
-TEST_F(RTCQuicTransportTest, ReadyToSendPromiseRejectedWithIceStop) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-  FillDatagramBuffer(quic_transport);
-  RunUntilIdle();
-
-  ScriptPromise promise = quic_transport->readyToSendDatagram(
-      scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-  quic_transport->transport()->stop();
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that the pending readyToSend proimise will be rejected if connection
-// fails.
-TEST_F(RTCQuicTransportTest, ReadyToSendPromiseRejectedWithFailedConnection) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-  FillDatagramBuffer(quic_transport);
-  RunUntilIdle();
-
-  ScriptPromise promise = quic_transport->readyToSendDatagram(
-      scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-  delegate->OnConnectionFailed("test_failure", /*from_remote=*/false);
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that the pending readyToSend proimise will be rejected if the remote
-// side stops.
-TEST_F(RTCQuicTransportTest, ReadyToSendPromiseRejectedWithRemoteStop) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-  FillDatagramBuffer(quic_transport);
-  RunUntilIdle();
-
-  ScriptPromise promise = quic_transport->readyToSendDatagram(
-      scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-  delegate->OnRemoteStopped();
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that the pending receiveDatagrams proimise will be rejected if
-// connection fails.
-TEST_F(RTCQuicTransportTest,
-       ReceiveDatagramsPromiseRejectedWithFailedConnection) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-  ScriptPromise promise = quic_transport->receiveDatagrams(
-      scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-  delegate->OnConnectionFailed("test_failure", /*from_remote=*/false);
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that the pending receiveDatagrams proimise will be rejected if
-// connection fails.
-TEST_F(RTCQuicTransportTest, ReceiveDatagramsPromiseRejectedWithRemoteStop) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-
-  ScriptPromise promise = quic_transport->receiveDatagrams(
-      scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kPending,
-            promise.V8Value().As<v8::Promise>()->State());
-  delegate->OnRemoteStopped();
-  RunUntilIdle();
-
-  EXPECT_EQ(v8::Promise::kRejected,
-            promise.V8Value().As<v8::Promise>()->State());
-}
-
-// Test that calling receiveDatagrams before the last promise has resolved
-// raises a kInvalidStateError.
-TEST_F(RTCQuicTransportTest, ReceiveDatagramsTwiceRaisesInvalidStateError) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-
-  quic_transport->receiveDatagrams(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  quic_transport->receiveDatagrams(scope.GetScriptState(),
-                                   scope.GetExceptionState());
-  EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
-            scope.GetExceptionState().CodeAs<DOMExceptionCode>());
-}
-
-// Test that if datagrams are buffered before asking for a receiveDatagrams
-// promise, that calling receiveDatagrams will return a promise immediately
-// resolved with buffered datagrams.
-TEST_F(RTCQuicTransportTest, ReceiveBufferedDatagrams) {
-  V8TestingScope scope;
-
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, &delegate);
-  DCHECK(delegate);
-
-  delegate->OnDatagramReceived({1, 2, 3});
-  delegate->OnDatagramReceived({4, 5, 6});
-  delegate->OnDatagramReceived({7, 8, 9});
-  RunUntilIdle();
-
-  ScriptPromise promise = quic_transport->receiveDatagrams(
-      scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  EXPECT_EQ(v8::Promise::kFulfilled,
-            promise.V8Value().As<v8::Promise>()->State());
-  HeapVector<Member<DOMArrayBuffer>> received_datagrams =
-      NativeValueTraits<IDLSequence<DOMArrayBuffer>>::NativeValue(
-          scope.GetIsolate(), promise.V8Value().As<v8::Promise>()->Result(),
-          ASSERT_NO_EXCEPTION);
-
-  ASSERT_EQ(3u, received_datagrams.size());
-  EXPECT_THAT(SpanFromDOMArrayBuffer(received_datagrams[0]),
-              ElementsAre(1, 2, 3));
-  EXPECT_THAT(SpanFromDOMArrayBuffer(received_datagrams[1]),
-              ElementsAre(4, 5, 6));
-  EXPECT_THAT(SpanFromDOMArrayBuffer(received_datagrams[2]),
-              ElementsAre(7, 8, 9));
-}
-
-// Test that if datagrams are dropped once we have buffered the max amount.
-TEST_F(RTCQuicTransportTest, ReceiveBufferedDatagramsLost) {
-  V8TestingScope scope;
-
-  auto mock_transport = std::make_unique<MockP2PQuicTransport>();
-  MockP2PQuicTransport* mock_transport_ptr = mock_transport.get();
-  P2PQuicTransport::Delegate* delegate = nullptr;
-  Persistent<RTCQuicTransport> quic_transport =
-      CreateConnectedQuicTransport(scope, std::move(mock_transport), &delegate);
-  DCHECK(delegate);
-
-  size_t num_dropped_datagrams = 5;
-  size_t num_received_datagrams =
-      kMaxBufferedRecvDatagrams + num_dropped_datagrams;
-  for (size_t i = 0; i < num_received_datagrams; ++i) {
-    delegate->OnDatagramReceived({1});
-  }
-  RunUntilIdle();
-
-  ScriptPromise received_datagrams_promise = quic_transport->receiveDatagrams(
-      scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  ASSERT_EQ(v8::Promise::kFulfilled,
-            received_datagrams_promise.V8Value().As<v8::Promise>()->State());
-  HeapVector<Member<DOMArrayBuffer>> received_datagrams =
-      NativeValueTraits<IDLSequence<DOMArrayBuffer>>::NativeValue(
-          scope.GetIsolate(),
-          received_datagrams_promise.V8Value().As<v8::Promise>()->Result(),
-          ASSERT_NO_EXCEPTION);
-
-  EXPECT_CALL(*mock_transport_ptr, GetStats())
-      .WillOnce(Return(P2PQuicTransportStats()));
-  ScriptPromise stats_promise =
-      quic_transport->getStats(scope.GetScriptState(), ASSERT_NO_EXCEPTION);
-  RunUntilIdle();
-  ASSERT_EQ(v8::Promise::kFulfilled,
-            stats_promise.V8Value().As<v8::Promise>()->State());
-
-  RTCQuicTransportStats* rtc_quic_stats =
-      NativeValueTraits<RTCQuicTransportStats>::NativeValue(
-          scope.GetIsolate(),
-          stats_promise.V8Value().As<v8::Promise>()->Result(),
-          ASSERT_NO_EXCEPTION);
-
-  EXPECT_EQ(kMaxBufferedRecvDatagrams, received_datagrams.size());
-  ASSERT_TRUE(rtc_quic_stats->hasNumReceivedDatagramsDropped());
-  EXPECT_EQ(num_dropped_datagrams,
-            rtc_quic_stats->numReceivedDatagramsDropped());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h
deleted file mode 100644
index 191e299d..0000000
--- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h
+++ /dev/null
@@ -1,52 +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 LQUICNSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_TEST_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_TEST_H_
-
-#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport.h"
-#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_transport_factory.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_certificate.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport_test.h"
-#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.h"
-
-namespace blink {
-
-class V8TestingScope;
-
-class RTCQuicTransportTest : public RTCIceTransportTest {
- public:
-  // Construct a new RTCQuicTransport with the given RTCIceTransport,
-  // certificates, and mock P2PQuicTransport.
-  // |delegate_out|, if non-null, will be populated once the P2PQuicTransport is
-  // constructed on the worker thread.
-  RTCQuicTransport* CreateQuicTransport(
-      V8TestingScope& scope,
-      RTCIceTransport* ice_transport,
-      const HeapVector<Member<RTCCertificate>>& certificates,
-      std::unique_ptr<MockP2PQuicTransport> mock_transport,
-      P2PQuicTransport::Delegate** delegate_out = nullptr);
-
-  // Construct a new RTCQuicTransport with the given RTCIceTransport,
-  // certificates, and mock P2PQuicTransportFactory.
-  RTCQuicTransport* CreateQuicTransport(
-      V8TestingScope& scope,
-      RTCIceTransport* ice_transport,
-      const HeapVector<Member<RTCCertificate>>& certificates,
-      std::unique_ptr<MockP2PQuicTransportFactory> mock_factory);
-
-  // Construct a new RTCQuicTransport and RTCIceTransport and call start() on
-  // both objects.
-  RTCQuicTransport* CreateConnectedQuicTransport(
-      V8TestingScope& scope,
-      P2PQuicTransport::Delegate** delegate_out = nullptr);
-  RTCQuicTransport* CreateConnectedQuicTransport(
-      V8TestingScope& scope,
-      std::unique_ptr<MockP2PQuicTransport> mock_transport,
-      P2PQuicTransport::Delegate** delegate_out = nullptr);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_QUIC_TRANSPORT_TEST_H_
diff --git a/third_party/blink/renderer/modules/plugins/navigator_plugins.cc b/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
index c1b446b..fdd8d03 100644
--- a/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
+++ b/third_party/blink/renderer/modules/plugins/navigator_plugins.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/navigator.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/modules/plugins/dom_mime_type.h"
 #include "third_party/blink/renderer/modules/plugins/dom_mime_type_array.h"
 #include "third_party/blink/renderer/modules/plugins/dom_plugin_array.h"
 #include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
@@ -91,11 +92,40 @@
 }
 
 DOMMimeTypeArray* NavigatorPlugins::mimeTypes(LocalFrame* frame) const {
-  if (!mime_types_)
+  if (!mime_types_) {
     mime_types_ = MakeGarbageCollected<DOMMimeTypeArray>(frame);
+    RecordMimeTypes(frame);
+  }
   return mime_types_.Get();
 }
 
+void NavigatorPlugins::RecordMimeTypes(LocalFrame* frame) const {
+  constexpr IdentifiableSurface surface = IdentifiableSurface::FromTypeAndToken(
+      IdentifiableSurface::Type::kWebFeature, WebFeature::kNavigatorMimeTypes);
+  if (!IdentifiabilityStudySettings::Get()->IsSurfaceAllowed(surface) || !frame)
+    return;
+  Document* document = frame->GetDocument();
+  if (!document)
+    return;
+  IdentifiableTokenBuilder builder;
+  for (unsigned i = 0; i < mime_types_->length(); i++) {
+    DOMMimeType* mime_type = mime_types_->item(i);
+    builder.AddToken(IdentifiabilityBenignStringToken(mime_type->type()));
+    builder.AddToken(
+        IdentifiabilityBenignStringToken(mime_type->description()));
+    builder.AddToken(IdentifiabilityBenignStringToken(mime_type->suffixes()));
+    DOMPlugin* plugin = mime_type->enabledPlugin();
+    if (plugin) {
+      builder.AddToken(IdentifiabilityBenignStringToken(plugin->name()));
+      builder.AddToken(IdentifiabilityBenignStringToken(plugin->filename()));
+      builder.AddToken(IdentifiabilityBenignStringToken(plugin->description()));
+    }
+  }
+  IdentifiabilityMetricBuilder(document->UkmSourceID())
+      .Set(surface, builder.GetToken())
+      .Record(document->UkmRecorder());
+}
+
 void NavigatorPlugins::Trace(Visitor* visitor) const {
   visitor->Trace(plugins_);
   visitor->Trace(mime_types_);
diff --git a/third_party/blink/renderer/modules/plugins/navigator_plugins.h b/third_party/blink/renderer/modules/plugins/navigator_plugins.h
index 7f424a4..e45d779 100644
--- a/third_party/blink/renderer/modules/plugins/navigator_plugins.h
+++ b/third_party/blink/renderer/modules/plugins/navigator_plugins.h
@@ -35,6 +35,8 @@
   DOMPluginArray* plugins(LocalFrame*) const;
   DOMMimeTypeArray* mimeTypes(LocalFrame*) const;
 
+  void RecordMimeTypes(LocalFrame*) const;
+
   mutable Member<DOMPluginArray> plugins_;
   mutable Member<DOMMimeTypeArray> mime_types_;
 };
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index 488ba741..d1c4c82 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -53,7 +53,7 @@
 std::unique_ptr<media::VideoEncoder> CreateAcceleratedVideoEncoder(
     media::VideoCodecProfile profile,
     const media::VideoEncoder::Options& options) {
-#if defined(OS_MAC) || defined(OS_LINUX)
+#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS)
   // TODO(https://crbug.com/1110279) Flush() is not implemented on MacOS'
   // accelerated video encoder, so we can't use it yet.
   return nullptr;
@@ -97,7 +97,7 @@
       media::AsyncDestroyVideoEncoder<media::VideoEncodeAcceleratorAdapter>>(
       std::make_unique<media::VideoEncodeAcceleratorAdapter>(
           gpu_factories, std::move(task_runner)));
-#endif  // defined(OS_MAC) || defined(OS_LINUX)
+#endif  // defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS)
 }
 
 std::unique_ptr<media::VideoEncoder> CreateVpxVideoEncoder() {
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 78974b8..e7ff7f9 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -221,10 +221,6 @@
   RuntimeEnabledFeatures::SetImplicitRootScrollerEnabled(enable);
 }
 
-void WebRuntimeFeatures::EnableCSSOMViewScrollCoordinates(bool enable) {
-  RuntimeEnabledFeatures::SetCSSOMViewScrollCoordinatesEnabled(enable);
-}
-
 void WebRuntimeFeatures::EnableInputMultipleFieldsUI(bool enable) {
   RuntimeEnabledFeatures::SetInputMultipleFieldsUIEnabled(enable);
 }
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
index d193ead..6058d91 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
@@ -158,7 +158,7 @@
 
 struct TestChunks {
   Vector<PaintChunk> chunks;
-  DisplayItemList items = DisplayItemList(0);
+  DisplayItemList items;
 
   // Add a paint chunk with a non-empty paint record and given property nodes.
   void AddChunk(
diff --git a/third_party/blink/renderer/platform/graphics/contiguous_container.cc b/third_party/blink/renderer/platform/graphics/contiguous_container.cc
index 9ea0c88d..c3ebdca0 100644
--- a/third_party/blink/renderer/platform/graphics/contiguous_container.cc
+++ b/third_party/blink/renderer/platform/graphics/contiguous_container.cc
@@ -14,10 +14,6 @@
 
 namespace blink {
 
-// Default number of max-sized elements to allocate space for, if there is no
-// initial buffer.
-static const unsigned kDefaultInitialBufferSize = 32;
-
 class ContiguousContainerBase::Buffer {
   USING_FAST_MALLOC(Buffer);
 
@@ -57,7 +53,7 @@
   }
 
  private:
-  // m_begin <= m_end <= m_begin + m_capacity
+  // begin_ <= end_ <= begin_ + capacity_
   char* begin_;
   char* end_;
   wtf_size_t capacity_;
@@ -65,12 +61,18 @@
   DISALLOW_COPY_AND_ASSIGN(Buffer);
 };
 
-ContiguousContainerBase::ContiguousContainerBase(wtf_size_t max_object_size)
-    : end_index_(0), max_object_size_(max_object_size) {}
+ContiguousContainerBase::ContiguousContainerBase(
+    wtf_size_t max_object_size,
+    wtf_size_t initial_capacity_in_bytes)
+    : end_index_(0),
+      max_object_size_(max_object_size),
+      initial_capacity_in_bytes_(
+          std::max(max_object_size, initial_capacity_in_bytes)) {}
 
 ContiguousContainerBase::ContiguousContainerBase(
     ContiguousContainerBase&& source)
-    : ContiguousContainerBase(source.max_object_size_) {
+    : ContiguousContainerBase(source.max_object_size_,
+                              source.initial_capacity_in_bytes_) {
   Swap(source);
 }
 
@@ -101,11 +103,6 @@
          elements_.capacity() * sizeof(elements_[0]);
 }
 
-void ContiguousContainerBase::ReserveInitialCapacity(wtf_size_t buffer_size,
-                                                     const char* type_name) {
-  AllocateNewBufferForNextAllocation(buffer_size, type_name);
-}
-
 void* ContiguousContainerBase::Allocate(wtf_size_t object_size,
                                         const char* type_name) {
   DCHECK_LE(object_size, max_object_size_);
@@ -120,9 +117,9 @@
   }
 
   if (!buffer_for_alloc) {
-    wtf_size_t new_buffer_size =
-        buffers_.IsEmpty() ? kDefaultInitialBufferSize * max_object_size_
-                           : 2 * buffers_.back()->Capacity();
+    wtf_size_t new_buffer_size = buffers_.IsEmpty()
+                                     ? initial_capacity_in_bytes_
+                                     : 2 * buffers_.back()->Capacity();
     buffer_for_alloc =
         AllocateNewBufferForNextAllocation(new_buffer_size, type_name);
   }
@@ -158,13 +155,7 @@
   buffers_.swap(other.buffers_);
   std::swap(end_index_, other.end_index_);
   std::swap(max_object_size_, other.max_object_size_);
-}
-
-void ContiguousContainerBase::ShrinkToFit() {
-  while (end_index_ < buffers_.size() - 1) {
-    DCHECK(buffers_.back()->IsEmpty());
-    buffers_.pop_back();
-  }
+  std::swap(initial_capacity_in_bytes_, other.initial_capacity_in_bytes_);
 }
 
 ContiguousContainerBase::Buffer*
diff --git a/third_party/blink/renderer/platform/graphics/contiguous_container.h b/third_party/blink/renderer/platform/graphics/contiguous_container.h
index c81241eb..4f684741 100644
--- a/third_party/blink/renderer/platform/graphics/contiguous_container.h
+++ b/third_party/blink/renderer/platform/graphics/contiguous_container.h
@@ -41,7 +41,9 @@
   DISALLOW_NEW();
 
  protected:
-  explicit ContiguousContainerBase(wtf_size_t max_object_size);
+  // The initial capacity will be allocated when the first item is added.
+  ContiguousContainerBase(wtf_size_t max_object_size,
+                          wtf_size_t initial_capacity_in_bytes);
   ContiguousContainerBase(ContiguousContainerBase&&);
   ~ContiguousContainerBase();
 
@@ -54,16 +56,11 @@
   wtf_size_t MemoryUsageInBytes() const;
 
   // These do not invoke constructors or destructors.
-  void ReserveInitialCapacity(wtf_size_t, const char* type_name);
   void* Allocate(wtf_size_t object_size, const char* type_name);
   void RemoveLast();
   void Clear();
   void Swap(ContiguousContainerBase&);
 
-  // Discards excess buffer capacity. Intended for use when no more appending
-  // is anticipated.
-  void ShrinkToFit();
-
   Vector<void*> elements_;
 
  private:
@@ -74,6 +71,7 @@
   Vector<std::unique_ptr<Buffer>> buffers_;
   unsigned end_index_;
   wtf_size_t max_object_size_;
+  wtf_size_t initial_capacity_in_bytes_;
 
   DISALLOW_COPY_AND_ASSIGN(ContiguousContainerBase);
 };
@@ -138,14 +136,10 @@
 
   using value_type = BaseElementType;
 
-  explicit ContiguousContainer(wtf_size_t max_object_size)
-      : ContiguousContainerBase(Align(max_object_size)) {}
-
-  ContiguousContainer(wtf_size_t max_object_size, wtf_size_t initial_size_bytes)
-      : ContiguousContainer(max_object_size) {
-    ReserveInitialCapacity(std::max(max_object_size, initial_size_bytes),
-                           WTF_HEAP_PROFILER_TYPE_NAME(BaseElementType));
-  }
+  ContiguousContainer(wtf_size_t max_object_size,
+                      wtf_size_t initial_capacity_in_bytes)
+      : ContiguousContainerBase(Align(max_object_size),
+                                initial_capacity_in_bytes) {}
 
   ContiguousContainer(ContiguousContainer&& source)
       : ContiguousContainerBase(std::move(source)) {}
@@ -169,7 +163,6 @@
   using ContiguousContainerBase::CapacityInBytes;
   using ContiguousContainerBase::IsEmpty;
   using ContiguousContainerBase::MemoryUsageInBytes;
-  using ContiguousContainerBase::ShrinkToFit;
   using ContiguousContainerBase::size;
   using ContiguousContainerBase::UsedCapacityInBytes;
 
diff --git a/third_party/blink/renderer/platform/graphics/contiguous_container_test.cc b/third_party/blink/renderer/platform/graphics/contiguous_container_test.cc
index 5ad0bd5..0545dce 100644
--- a/third_party/blink/renderer/platform/graphics/contiguous_container_test.cc
+++ b/third_party/blink/renderer/platform/graphics/contiguous_container_test.cc
@@ -25,16 +25,25 @@
 };
 
 // Maximum size of a subclass of Point2D.
-static const size_t kMaxPointSize = sizeof(Point3D);
+static const wtf_size_t kMaxPointSize = sizeof(Point3D);
 
 // Alignment for Point2D and its subclasses.
-static const size_t kPointAlignment = sizeof(int);
+static const wtf_size_t kPointAlignment = sizeof(int);
 
 // How many elements to use for tests with "plenty" of elements.
-static const unsigned kNumElements = 150;
+static const wtf_size_t kNumElements = 150;
+
+static const wtf_size_t kDefaultInitialCapacityInBytes = 256;
+
+class PointList : public ContiguousContainer<Point2D, kPointAlignment> {
+ public:
+  explicit PointList(
+      wtf_size_t initial_capacity_in_bytes = kDefaultInitialCapacityInBytes)
+      : ContiguousContainer(kMaxPointSize, initial_capacity_in_bytes) {}
+};
 
 TEST(ContiguousContainerTest, SimpleStructs) {
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
+  PointList list;
   list.AllocateAndConstruct<Point2D>(1, 2);
   list.AllocateAndConstruct<Point3D>(3, 4, 5);
   list.AllocateAndConstruct<Point2D>(6, 7);
@@ -50,14 +59,14 @@
 }
 
 TEST(ContiguousContainerTest, AllocateLots) {
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
-  for (int i = 0; i < (int)kNumElements; i++) {
+  PointList list;
+  for (int i = 0; i < static_cast<int>(kNumElements); i++) {
     list.AllocateAndConstruct<Point2D>(i, i);
     list.AllocateAndConstruct<Point2D>(i, i);
     list.RemoveLast();
   }
   ASSERT_EQ(kNumElements, list.size());
-  for (int i = 0; i < (int)kNumElements; i++) {
+  for (int i = 0; i < static_cast<int>(kNumElements); i++) {
     ASSERT_EQ(i, list[i].x);
     ASSERT_EQ(i, list[i].y);
   }
@@ -71,15 +80,23 @@
   MOCK_METHOD0(Destruct, void());
 };
 
+class MockDestructibleList : public ContiguousContainer<MockDestructible> {
+ public:
+  explicit MockDestructibleList(
+      wtf_size_t initial_capacity_in_bytes = kDefaultInitialCapacityInBytes)
+      : ContiguousContainer(sizeof(MockDestructible),
+                            initial_capacity_in_bytes) {}
+};
+
 TEST(ContiguousContainerTest, DestructorCalled) {
-  ContiguousContainer<MockDestructible> list(sizeof(MockDestructible));
+  MockDestructibleList list;
   auto& destructible = list.AllocateAndConstruct<MockDestructible>();
   EXPECT_EQ(&destructible, &list.First());
   EXPECT_CALL(destructible, Destruct());
 }
 
 TEST(ContiguousContainerTest, DestructorCalledOnceWhenClear) {
-  ContiguousContainer<MockDestructible> list(sizeof(MockDestructible));
+  MockDestructibleList list;
   auto& destructible = list.AllocateAndConstruct<MockDestructible>();
   EXPECT_EQ(&destructible, &list.First());
 
@@ -96,7 +113,7 @@
 }
 
 TEST(ContiguousContainerTest, DestructorCalledOnceWhenRemoveLast) {
-  ContiguousContainer<MockDestructible> list(sizeof(MockDestructible));
+  MockDestructibleList list;
   auto& destructible = list.AllocateAndConstruct<MockDestructible>();
   EXPECT_EQ(&destructible, &list.First());
 
@@ -115,8 +132,7 @@
 TEST(ContiguousContainerTest, DestructorCalledWithMultipleRemoveLastCalls) {
   // This container only requests space for one, but the implementation is
   // free to use more space if the allocator provides it.
-  ContiguousContainer<MockDestructible> list(sizeof(MockDestructible),
-                                             1 * sizeof(MockDestructible));
+  MockDestructibleList list(1 * sizeof(MockDestructible));
   testing::MockFunction<void()> separator;
 
   // We should be okay to allocate and remove a single one, like before.
@@ -170,7 +186,7 @@
 }
 
 TEST(ContiguousContainerTest, InsertionAndIndexedAccess) {
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
+  PointList list;
 
   auto& point1 = list.AllocateAndConstruct<Point2D>();
   auto& point2 = list.AllocateAndConstruct<Point2D>();
@@ -185,27 +201,35 @@
 }
 
 TEST(ContiguousContainerTest, InsertionAndClear) {
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
+  PointList list;
   EXPECT_TRUE(list.IsEmpty());
   EXPECT_EQ(0u, list.size());
+  EXPECT_EQ(0u, list.CapacityInBytes());
+  EXPECT_EQ(0u, list.UsedCapacityInBytes());
 
   list.AllocateAndConstruct<Point2D>();
   EXPECT_FALSE(list.IsEmpty());
   EXPECT_EQ(1u, list.size());
+  EXPECT_GE(list.CapacityInBytes(), kDefaultInitialCapacityInBytes);
+  EXPECT_EQ(sizeof(Point2D), list.UsedCapacityInBytes());
 
   list.Clear();
   EXPECT_TRUE(list.IsEmpty());
   EXPECT_EQ(0u, list.size());
+  EXPECT_EQ(0u, list.CapacityInBytes());
+  EXPECT_EQ(0u, list.UsedCapacityInBytes());
 
   list.AllocateAndConstruct<Point2D>();
   EXPECT_FALSE(list.IsEmpty());
   EXPECT_EQ(1u, list.size());
+  EXPECT_GE(list.CapacityInBytes(), kDefaultInitialCapacityInBytes);
+  EXPECT_EQ(sizeof(Point2D), list.UsedCapacityInBytes());
 }
 
 TEST(ContiguousContainerTest, ElementAddressesAreStable) {
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
+  PointList list;
   Vector<Point2D*> pointers;
-  for (int i = 0; i < (int)kNumElements; i++)
+  for (int i = 0; i < static_cast<int>(kNumElements); i++)
     pointers.push_back(&list.AllocateAndConstruct<Point2D>());
   EXPECT_EQ(kNumElements, list.size());
   EXPECT_EQ(kNumElements, pointers.size());
@@ -217,12 +241,12 @@
 }
 
 TEST(ContiguousContainerTest, ForwardIteration) {
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
-  for (int i = 0; i < (int)kNumElements; i++)
+  PointList list;
+  for (int i = 0; i < static_cast<int>(kNumElements); i++)
     list.AllocateAndConstruct<Point2D>(i, i);
-  unsigned count = 0;
+  wtf_size_t count = 0;
   for (Point2D& point : list) {
-    EXPECT_EQ((int)count, point.x);
+    EXPECT_EQ(static_cast<int>(count), point.x);
     count++;
   }
   EXPECT_EQ(kNumElements, count);
@@ -232,14 +256,14 @@
 }
 
 TEST(ContiguousContainerTest, ConstForwardIteration) {
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
-  for (int i = 0; i < (int)kNumElements; i++)
+  PointList list;
+  for (int i = 0; i < static_cast<int>(kNumElements); i++)
     list.AllocateAndConstruct<Point2D>(i, i);
 
   const auto& const_list = list;
-  unsigned count = 0;
+  wtf_size_t count = 0;
   for (const Point2D& point : const_list) {
-    EXPECT_EQ((int)count, point.x);
+    EXPECT_EQ(static_cast<int>(count), point.x);
     count++;
   }
   EXPECT_EQ(kNumElements, count);
@@ -250,13 +274,13 @@
 }
 
 TEST(ContiguousContainerTest, ReverseIteration) {
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
-  for (int i = 0; i < (int)kNumElements; i++)
+  PointList list;
+  for (int i = 0; i < static_cast<int>(kNumElements); i++)
     list.AllocateAndConstruct<Point2D>(i, i);
 
-  unsigned count = 0;
+  wtf_size_t count = 0;
   for (auto it = list.rbegin(); it != list.rend(); ++it) {
-    EXPECT_EQ((int)(kNumElements - 1 - count), it->x);
+    EXPECT_EQ(static_cast<int>(kNumElements - 1 - count), it->x);
     count++;
   }
   EXPECT_EQ(kNumElements, count);
@@ -331,7 +355,7 @@
 }
 
 TEST(ContiguousContainerTest, AppendByMovingSameList) {
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
+  PointList list;
   list.AllocateAndConstruct<Point3D>(1, 2, 3);
 
   // Moves the Point3D to the end, and default-constructs a Point2D in its
@@ -368,11 +392,13 @@
   };
 
   bool destroyed = false;
-  ContiguousContainer<DestructionNotifier> list1(sizeof(DestructionNotifier));
+  ContiguousContainer<DestructionNotifier> list1(
+      sizeof(DestructionNotifier), kDefaultInitialCapacityInBytes);
   list1.AllocateAndConstruct<DestructionNotifier>(&destroyed);
   {
     // Make sure destructor isn't called during appendByMoving.
-    ContiguousContainer<DestructionNotifier> list2(sizeof(DestructionNotifier));
+    ContiguousContainer<DestructionNotifier> list2(
+        sizeof(DestructionNotifier), kDefaultInitialCapacityInBytes);
     list2.AppendByMoving(list1.Last(), sizeof(DestructionNotifier));
     EXPECT_FALSE(destroyed);
   }
@@ -381,8 +407,8 @@
 }
 
 TEST(ContiguousContainerTest, AppendByMovingReturnsMovedPointer) {
-  ContiguousContainer<Point2D, kPointAlignment> list1(kMaxPointSize);
-  ContiguousContainer<Point2D, kPointAlignment> list2(kMaxPointSize);
+  PointList list1;
+  PointList list2;
 
   Point2D& point = list1.AllocateAndConstruct<Point2D>();
   Point2D& moved_point1 = list2.AppendByMoving(point, sizeof(Point2D));
@@ -394,8 +420,8 @@
 }
 
 TEST(ContiguousContainerTest, AppendByMovingReplacesSourceWithNewElement) {
-  ContiguousContainer<Point2D, kPointAlignment> list1(kMaxPointSize);
-  ContiguousContainer<Point2D, kPointAlignment> list2(kMaxPointSize);
+  PointList list1;
+  PointList list2;
 
   list1.AllocateAndConstruct<Point2D>(1, 2);
   EXPECT_EQ(1, list1.First().x);
@@ -412,7 +438,7 @@
 }
 
 TEST(ContiguousContainerTest, AppendByMovingElementsOfDifferentSizes) {
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
+  PointList list;
   list.AllocateAndConstruct<Point3D>(1, 2, 3);
   list.AllocateAndConstruct<Point2D>(4, 5);
 
@@ -440,9 +466,9 @@
 }
 
 TEST(ContiguousContainerTest, Swap) {
-  ContiguousContainer<Point2D, kPointAlignment> list1(kMaxPointSize);
+  PointList list1;
   list1.AllocateAndConstruct<Point2D>(1, 2);
-  ContiguousContainer<Point2D, kPointAlignment> list2(kMaxPointSize);
+  PointList list2;
   list2.AllocateAndConstruct<Point2D>(3, 4);
   list2.AllocateAndConstruct<Point2D>(5, 6);
 
@@ -469,46 +495,30 @@
 
 TEST(ContiguousContainerTest, CapacityInBytes) {
   const int kIterations = 500;
-  const size_t kInitialCapacity = 10 * kMaxPointSize;
-  const size_t kUpperBoundOnMinCapacity = kInitialCapacity;
+  const wtf_size_t kInitialCapacity = 10 * kMaxPointSize;
+  const wtf_size_t kUpperBoundOnMinCapacity = kInitialCapacity;
+  // In worst case, there are 2 buffers, and the second buffer contains only one
+  // element, so the factor is close to 3 as the second buffer is twice as big
+  // as the first buffer.
+  const size_t kMaxWasteFactor = 3;
 
-  // At time of writing, removing elements from the end can cause up to 7x the
-  // memory required to be consumed, in the worst case, since we can have up to
-  // two trailing inner lists that are empty (for 2*size + 4*size in unused
-  // memory, due to the exponential growth strategy).
-  // Unfortunately, this captures behaviour of the underlying allocator as
-  // well as this container, so we're pretty loose here. This constant may
-  // need to be adjusted.
-  const size_t kMaxWasteFactor = 8;
-
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize,
-                                                     kInitialCapacity);
+  PointList list(kInitialCapacity);
 
   // The capacity should grow with the list.
   for (int i = 0; i < kIterations; i++) {
     size_t capacity = list.CapacityInBytes();
     ASSERT_GE(capacity, list.size() * sizeof(Point2D));
-    ASSERT_LE(capacity, std::max(list.size() * sizeof(Point2D),
-                                 kUpperBoundOnMinCapacity) *
+    ASSERT_LE(capacity, std::max<wtf_size_t>(list.size() * sizeof(Point2D),
+                                             kUpperBoundOnMinCapacity) *
                             kMaxWasteFactor);
     list.AllocateAndConstruct<Point2D>();
   }
-
-  // The capacity should shrink with the list.
-  for (int i = 0; i < kIterations; i++) {
-    size_t capacity = list.CapacityInBytes();
-    ASSERT_GE(capacity, list.size() * sizeof(Point2D));
-    ASSERT_LE(capacity, std::max(list.size() * sizeof(Point2D),
-                                 kUpperBoundOnMinCapacity) *
-                            kMaxWasteFactor);
-    list.RemoveLast();
-  }
 }
 
 TEST(ContiguousContainerTest, CapacityInBytesAfterClear) {
   // Clearing should restore the capacity of the container to the same as a
   // newly allocated one (without reserved capacity requested).
-  ContiguousContainer<Point2D, kPointAlignment> list(kMaxPointSize);
+  PointList list;
   size_t empty_capacity = list.CapacityInBytes();
   list.AllocateAndConstruct<Point2D>();
   list.AllocateAndConstruct<Point2D>();
@@ -518,7 +528,8 @@
 
 TEST(ContiguousContainerTest, Alignment) {
   const size_t kMaxAlign = alignof(long double);
-  ContiguousContainer<Point2D, kMaxAlign> list(kMaxPointSize);
+  ContiguousContainer<Point2D, kMaxAlign> list(kMaxPointSize,
+                                               kDefaultInitialCapacityInBytes);
 
   list.AllocateAndConstruct<Point2D>();
   EXPECT_EQ(0u, reinterpret_cast<intptr_t>(&list.Last()) & (kMaxAlign - 1));
diff --git a/third_party/blink/renderer/platform/graphics/paint/display_item_list.h b/third_party/blink/renderer/platform/graphics/paint/display_item_list.h
index c6b83e17..0f6f30e 100644
--- a/third_party/blink/renderer/platform/graphics/paint/display_item_list.h
+++ b/third_party/blink/renderer/platform/graphics/paint/display_item_list.h
@@ -28,8 +28,16 @@
 class PLATFORM_EXPORT DisplayItemList
     : public ContiguousContainer<DisplayItem, kDisplayItemAlignment> {
  public:
-  DisplayItemList(wtf_size_t initial_size_bytes)
-      : ContiguousContainer(kMaximumDisplayItemSize, initial_size_bytes) {}
+  static constexpr wtf_size_t kDefaultCapacityInBytes = 512;
+
+  // Using 0 as the default value to make 0 also fall back to
+  // kDefaultCapacityInBytes.
+  explicit DisplayItemList(wtf_size_t initial_capacity_in_bytes = 0)
+      : ContiguousContainer(kMaximumDisplayItemSize,
+                            initial_capacity_in_bytes
+                                ? initial_capacity_in_bytes
+                                : kDefaultCapacityInBytes) {}
+
   DisplayItemList(DisplayItemList&& source)
       : ContiguousContainer(std::move(source)) {}
 
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc b/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc
index 56e5366..8da84c21 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_artifact.cc
@@ -14,8 +14,6 @@
 
 namespace blink {
 
-PaintArtifact::PaintArtifact() : display_item_list_(0) {}
-
 PaintArtifact::PaintArtifact(DisplayItemList display_items,
                              Vector<PaintChunk> chunks)
     : display_item_list_(std::move(display_items)), chunks_(std::move(chunks)) {
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h b/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h
index 83daf93..f67cf0c 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_artifact.h
@@ -90,7 +90,7 @@
                              const PaintChunkSubset& paint_chunks) const;
 
  private:
-  PaintArtifact();
+  PaintArtifact() = default;
   PaintArtifact(DisplayItemList, Vector<PaintChunk>);
 
   DisplayItemList display_item_list_;
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc b/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
index 700d609..3cd0438 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller.cc
@@ -15,9 +15,7 @@
 namespace blink {
 
 PaintController::PaintController(Usage usage)
-    : usage_(usage),
-      current_paint_artifact_(PaintArtifact::Empty()),
-      new_display_item_list_(0) {
+    : usage_(usage), current_paint_artifact_(PaintArtifact::Empty()) {
   // frame_first_paints_ should have one null frame since the beginning, so
   // that PaintController is robust even if it paints outside of BeginFrame
   // and EndFrame cycles. It will also enable us to combine the first paint
@@ -61,7 +59,6 @@
   }
 
   ++num_cached_new_items_;
-  EnsureNewDisplayItemListInitialCapacity();
   if (!RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled())
     ProcessNewItem(MoveItemFromCurrentListToNewList(cached_item));
 
@@ -127,8 +124,6 @@
     return false;
   }
 
-  EnsureNewDisplayItemListInitialCapacity();
-
   if (next_item_to_match_ == start_item_index) {
     // We are matching new and cached display items sequentially. Skip the
     // subsequence for later sequential matching of individual display items.
@@ -506,9 +501,6 @@
   new_cached_subsequences_.swap(current_cached_subsequences_);
   new_cached_subsequences_.clear();
 
-  // The new list will not be appended to again so we can release unused memory.
-  new_display_item_list_.ShrinkToFit();
-
   current_paint_artifact_ =
       PaintArtifact::Create(std::move(new_display_item_list_),
                             new_paint_chunks_.ReleasePaintChunks());
@@ -517,7 +509,8 @@
   out_of_order_item_id_index_map_.clear();
 
   // We'll allocate the initial buffer when we start the next paint.
-  new_display_item_list_ = DisplayItemList(0);
+  new_display_item_list_ =
+      DisplayItemList(GetDisplayItemList().UsedCapacityInBytes());
 
 #if DCHECK_IS_ON()
   num_indexed_items_ = 0;
diff --git a/third_party/blink/renderer/platform/graphics/paint/paint_controller.h b/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
index 0a718a8..5c02bbe 100644
--- a/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
+++ b/third_party/blink/renderer/platform/graphics/paint/paint_controller.h
@@ -29,8 +29,6 @@
 
 namespace blink {
 
-static constexpr wtf_size_t kInitialDisplayItemListCapacityBytes = 512;
-
 enum class PaintBenchmarkMode {
   kNormal,
   kForceRasterInvalidationAndConvert,
@@ -148,7 +146,6 @@
                   "DisplayItem subclass alignment is not a factor of "
                   "kDisplayItemAlignment.");
 
-    EnsureNewDisplayItemListInitialCapacity();
     DisplayItemClass& display_item =
         new_display_item_list_.AllocateAndConstruct<DisplayItemClass>(
             std::forward<Args>(args)...);
@@ -303,17 +300,6 @@
   void InvalidateAllForTesting() { InvalidateAllInternal(); }
   void InvalidateAllInternal();
 
-  void EnsureNewDisplayItemListInitialCapacity() {
-    if (new_display_item_list_.IsEmpty()) {
-      // TODO(wangxianzhu): Consider revisiting this heuristic.
-      new_display_item_list_ = DisplayItemList(
-          current_paint_artifact_->GetDisplayItemList().IsEmpty()
-              ? kInitialDisplayItemListCapacityBytes
-              : current_paint_artifact_->GetDisplayItemList()
-                    .UsedCapacityInBytes());
-    }
-  }
-
   // Set new item state (cache skipping, etc) for the last new display item.
   void ProcessNewItem(DisplayItem&);
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 0a8962b4..91e8178 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -547,10 +547,6 @@
       status: "experimental",
     },
     {
-      name: "CSSOMViewScrollCoordinates",
-      status: "stable",
-    },
-    {
       name: "CSSPaintAPIArguments",
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/testing/test_paint_artifact.cc b/third_party/blink/renderer/platform/testing/test_paint_artifact.cc
index 29353d7..7d1612d 100644
--- a/third_party/blink/renderer/platform/testing/test_paint_artifact.cc
+++ b/third_party/blink/renderer/platform/testing/test_paint_artifact.cc
@@ -18,10 +18,6 @@
 
 namespace blink {
 
-TestPaintArtifact::TestPaintArtifact() : display_item_list_(0) {}
-
-TestPaintArtifact::~TestPaintArtifact() = default;
-
 static DisplayItemClient& StaticDummyClient() {
   DEFINE_STATIC_LOCAL(FakeDisplayItemClient, client, ());
   client.Validate();
diff --git a/third_party/blink/renderer/platform/testing/test_paint_artifact.h b/third_party/blink/renderer/platform/testing/test_paint_artifact.h
index 773ce20..791dd8dd 100644
--- a/third_party/blink/renderer/platform/testing/test_paint_artifact.h
+++ b/third_party/blink/renderer/platform/testing/test_paint_artifact.h
@@ -50,9 +50,6 @@
   STACK_ALLOCATED();
 
  public:
-  TestPaintArtifact();
-  ~TestPaintArtifact();
-
   // Add a chunk to the artifact. Each chunk will have a different automatically
   // created client.
   TestPaintArtifact& Chunk() { return Chunk(NewClient()); }
diff --git a/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.cc b/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.cc
index 5e45f996..0ff43c13 100644
--- a/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.cc
+++ b/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.cc
@@ -57,8 +57,8 @@
     const TransformOperation* from,
     double progress,
     bool blend_to_identity) {
-  if (from && !from->IsSameType(*this))
-    return this;
+  DCHECK(!from || CanBlendWith(*from));
+
   TransformOperations to_operations;
   to_operations.Operations().push_back(this);
   TransformOperations from_operations;
diff --git a/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h b/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h
index 5c8d303..9621a42f 100644
--- a/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h
+++ b/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h
@@ -50,10 +50,6 @@
         new InterpolatedTransformOperation(from, to, starting_index, progress));
   }
 
-  bool CanBlendWith(const TransformOperation& other) const override {
-    return IsSameType(other);
-  }
-
  private:
   OperationType GetType() const override { return kInterpolated; }
 
diff --git a/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.cc b/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.cc
index 2d8da85b..f989a0e1 100644
--- a/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.cc
+++ b/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.cc
@@ -93,8 +93,7 @@
     const TransformOperation* from,
     double progress,
     bool blend_to_identity) {
-  if (from && !from->IsSameType(*this))
-    return this;
+  DCHECK(!from || CanBlendWith(*from));
 
   // Convert the TransformOperations into matrices. Fail the blend operation
   // if either of the matrices is non-invertible.
diff --git a/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h b/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h
index 81d3fd8..f33c3f2 100644
--- a/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h
+++ b/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h
@@ -41,10 +41,6 @@
 
   TransformationMatrix Matrix() const { return matrix_; }
 
-  bool CanBlendWith(const TransformOperation& other) const override {
-    return false;
-  }
-
   static bool IsMatchingOperationType(OperationType type) {
     return type == kMatrix3D;
   }
diff --git a/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc b/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc
index ba42dc2..cfc0196 100644
--- a/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc
+++ b/third_party/blink/renderer/platform/transforms/matrix_transform_operation.cc
@@ -64,8 +64,7 @@
     const TransformOperation* from,
     double progress,
     bool blend_to_identity) {
-  if (from && !from->IsSameType(*this))
-    return this;
+  DCHECK(!from || CanBlendWith(*from));
 
   // convert the TransformOperations into matrices
   TransformationMatrix from_t;
diff --git a/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h b/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h
index d601a30c..688c0c08 100644
--- a/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h
+++ b/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h
@@ -52,10 +52,6 @@
     return TransformationMatrix(a_, b_, c_, d_, e_, f_);
   }
 
-  bool CanBlendWith(const TransformOperation& other) const override {
-    return false;
-  }
-
   static bool IsMatchingOperationType(OperationType type) {
     return type == kMatrix;
   }
diff --git a/third_party/blink/renderer/platform/transforms/perspective_transform_operation.h b/third_party/blink/renderer/platform/transforms/perspective_transform_operation.h
index e89ec30..cae996b 100644
--- a/third_party/blink/renderer/platform/transforms/perspective_transform_operation.h
+++ b/third_party/blink/renderer/platform/transforms/perspective_transform_operation.h
@@ -40,10 +40,6 @@
 
   double Perspective() const { return p_; }
 
-  bool CanBlendWith(const TransformOperation& other) const override {
-    return IsSameType(other);
-  }
-
   static bool IsMatchingOperationType(OperationType type) {
     return type == kPerspective;
   }
diff --git a/third_party/blink/renderer/platform/transforms/rotate_transform_operation.cc b/third_party/blink/renderer/platform/transforms/rotate_transform_operation.cc
index 648e246..a493bb2 100644
--- a/third_party/blink/renderer/platform/transforms/rotate_transform_operation.cc
+++ b/third_party/blink/renderer/platform/transforms/rotate_transform_operation.cc
@@ -71,8 +71,7 @@
     const TransformOperation* from,
     double progress,
     bool blend_to_identity) {
-  if (from && !IsMatchingOperationType(from->GetType()))
-    return this;
+  DCHECK(!from || CanBlendWith(*from));
 
   if (blend_to_identity)
     return RotateTransformOperation::Create(
@@ -96,11 +95,6 @@
       Rotation::Slerp(from_rotate.rotation_, rotation_, progress), type);
 }
 
-bool RotateTransformOperation::CanBlendWith(
-    const TransformOperation& other) const {
-  return other.IsSameType(*this);
-}
-
 RotateAroundOriginTransformOperation::RotateAroundOriginTransformOperation(
     double angle,
     double origin_x,
@@ -134,8 +128,8 @@
     const TransformOperation* from,
     double progress,
     bool blend_to_identity) {
-  if (from && !from->IsSameType(*this))
-    return this;
+  DCHECK(!from || CanBlendWith(*from));
+
   if (blend_to_identity) {
     return RotateAroundOriginTransformOperation::Create(
         Angle() * (1 - progress), origin_x_, origin_y_);
diff --git a/third_party/blink/renderer/platform/transforms/rotate_transform_operation.h b/third_party/blink/renderer/platform/transforms/rotate_transform_operation.h
index b0e054c..d736a23a 100644
--- a/third_party/blink/renderer/platform/transforms/rotate_transform_operation.h
+++ b/third_party/blink/renderer/platform/transforms/rotate_transform_operation.h
@@ -70,9 +70,8 @@
                             double& result_angle_a,
                             double& result_angle_b);
 
-  bool CanBlendWith(const TransformOperation& other) const override;
   OperationType GetType() const override { return type_; }
-  OperationType PrimitiveType() const final { return kRotate3D; }
+  OperationType PrimitiveType() const override { return kRotate3D; }
 
   void Apply(TransformationMatrix& transform,
              const FloatSize& /*borderBoxSize*/) const override {
@@ -130,6 +129,7 @@
   static bool IsMatchingOperationType(OperationType type) {
     return type == kRotateAroundOrigin;
   }
+  OperationType PrimitiveType() const override { return kRotateAroundOrigin; }
 
  private:
   RotateAroundOriginTransformOperation(double angle,
diff --git a/third_party/blink/renderer/platform/transforms/scale_transform_operation.cc b/third_party/blink/renderer/platform/transforms/scale_transform_operation.cc
index b6fb9a86..e440c7a6 100644
--- a/third_party/blink/renderer/platform/transforms/scale_transform_operation.cc
+++ b/third_party/blink/renderer/platform/transforms/scale_transform_operation.cc
@@ -63,8 +63,7 @@
     const TransformOperation* from,
     double progress,
     bool blend_to_identity) {
-  if (from && !from->CanBlendWith(*this))
-    return this;
+  DCHECK(!from || CanBlendWith(*from));
 
   if (blend_to_identity)
     return ScaleTransformOperation::Create(
@@ -83,11 +82,4 @@
       blink::Blend(from_z, z_, progress), is_3d ? kScale3D : kScale);
 }
 
-bool ScaleTransformOperation::CanBlendWith(
-    const TransformOperation& other) const {
-  return other.GetType() == kScaleX || other.GetType() == kScaleY ||
-         other.GetType() == kScaleZ || other.GetType() == kScale3D ||
-         other.GetType() == kScale;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/transforms/scale_transform_operation.h b/third_party/blink/renderer/platform/transforms/scale_transform_operation.h
index 39c6788..c6352c030 100644
--- a/third_party/blink/renderer/platform/transforms/scale_transform_operation.h
+++ b/third_party/blink/renderer/platform/transforms/scale_transform_operation.h
@@ -54,8 +54,6 @@
   double Y() const { return y_; }
   double Z() const { return z_; }
 
-  bool CanBlendWith(const TransformOperation& other) const override;
-
   void Apply(TransformationMatrix& transform, const FloatSize&) const override {
     transform.Scale3d(x_, y_, z_);
   }
diff --git a/third_party/blink/renderer/platform/transforms/skew_transform_operation.cc b/third_party/blink/renderer/platform/transforms/skew_transform_operation.cc
index 30c27055d..d9d5a80 100644
--- a/third_party/blink/renderer/platform/transforms/skew_transform_operation.cc
+++ b/third_party/blink/renderer/platform/transforms/skew_transform_operation.cc
@@ -37,8 +37,7 @@
     const TransformOperation* from,
     double progress,
     bool blend_to_identity) {
-  if (from && !from->CanBlendWith(*this))
-    return this;
+  DCHECK(!from || CanBlendWith(*from));
 
   if (blend_to_identity)
     return SkewTransformOperation::Create(blink::Blend(angle_x_, 0.0, progress),
@@ -54,10 +53,4 @@
       blink::Blend(from_angle_y, angle_y_, progress), type_);
 }
 
-bool SkewTransformOperation::CanBlendWith(
-    const TransformOperation& other) const {
-  return other.GetType() == kSkew || other.GetType() == kSkewX ||
-         other.GetType() == kSkewY;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/transforms/skew_transform_operation.h b/third_party/blink/renderer/platform/transforms/skew_transform_operation.h
index ab38b71f..7a838f1 100644
--- a/third_party/blink/renderer/platform/transforms/skew_transform_operation.h
+++ b/third_party/blink/renderer/platform/transforms/skew_transform_operation.h
@@ -42,8 +42,6 @@
   double AngleX() const { return angle_x_; }
   double AngleY() const { return angle_y_; }
 
-  bool CanBlendWith(const TransformOperation& other) const override;
-
   static bool IsMatchingOperationType(OperationType type) {
     return type == kSkewX || type == kSkewY || type == kSkew;
   }
diff --git a/third_party/blink/renderer/platform/transforms/transform_operation.h b/third_party/blink/renderer/platform/transforms/transform_operation.h
index 21e2fe9a..e5a8f18b 100644
--- a/third_party/blink/renderer/platform/transforms/transform_operation.h
+++ b/third_party/blink/renderer/platform/transforms/transform_operation.h
@@ -92,7 +92,9 @@
   bool IsSameType(const TransformOperation& other) const {
     return other.GetType() == GetType();
   }
-  virtual bool CanBlendWith(const TransformOperation& other) const = 0;
+  bool CanBlendWith(const TransformOperation& other) const {
+    return PrimitiveType() == other.PrimitiveType();
+  }
 
   virtual bool PreservesAxisAlignment() const { return false; }
 
diff --git a/third_party/blink/renderer/platform/transforms/transform_operations.cc b/third_party/blink/renderer/platform/transforms/transform_operations.cc
index 2b3a92f7..222f0e5 100644
--- a/third_party/blink/renderer/platform/transforms/transform_operations.cc
+++ b/third_party/blink/renderer/platform/transforms/transform_operations.cc
@@ -98,10 +98,9 @@
   wtf_size_t num_operations =
       std::min(Operations().size(), other.Operations().size());
   for (wtf_size_t i = 0; i < num_operations; ++i) {
-    if (Operations()[i]->PrimitiveType() !=
-        other.Operations()[i]->PrimitiveType()) {
-      // Remaining operations in each operations list require matrix/matrix3d
-      // interpolation.
+    if (!Operations()[i]->CanBlendWith(*other.Operations()[i])) {
+      // Remaining operations in each operations list require merging for
+      // matrix/matrix3d interpolation.
       return i;
     }
   }
diff --git a/third_party/blink/renderer/platform/transforms/transform_operations_test.cc b/third_party/blink/renderer/platform/transforms/transform_operations_test.cc
index 88d776d..551db4e 100644
--- a/third_party/blink/renderer/platform/transforms/transform_operations_test.cc
+++ b/third_party/blink/renderer/platform/transforms/transform_operations_test.cc
@@ -571,6 +571,75 @@
   EXPECT_TRUE(ops.HasNonTrivial3DComponent());
 }
 
+TEST(TransformOperationsTest, CanBlendWithSkewTest) {
+  TransformOperations ops_x, ops_y, ops_skew, ops_skew2;
+  ops_x.Operations().push_back(
+      SkewTransformOperation::Create(45, 0, TransformOperation::kSkewX));
+  ops_y.Operations().push_back(
+      SkewTransformOperation::Create(0, 45, TransformOperation::kSkewY));
+  ops_skew.Operations().push_back(
+      SkewTransformOperation::Create(45, 0, TransformOperation::kSkew));
+  ops_skew2.Operations().push_back(
+      SkewTransformOperation::Create(0, 45, TransformOperation::kSkew));
+
+  EXPECT_TRUE(ops_x.Operations()[0]->CanBlendWith(*ops_x.Operations()[0]));
+  EXPECT_TRUE(ops_y.Operations()[0]->CanBlendWith(*ops_y.Operations()[0]));
+
+  EXPECT_FALSE(ops_x.Operations()[0]->CanBlendWith(*ops_y.Operations()[0]));
+  EXPECT_FALSE(ops_x.Operations()[0]->CanBlendWith(*ops_skew.Operations()[0]));
+  EXPECT_FALSE(ops_y.Operations()[0]->CanBlendWith(*ops_skew.Operations()[0]));
+
+  EXPECT_TRUE(
+      ops_skew.Operations()[0]->CanBlendWith(*ops_skew2.Operations()[0]));
+
+  ASSERT_TRUE(IsA<SkewTransformOperation>(
+      *ops_skew.Blend(ops_skew2, 0.5).Operations()[0]));
+  ASSERT_TRUE(IsA<Matrix3DTransformOperation>(
+      *ops_x.Blend(ops_y, 0.5).Operations()[0]));
+}
+
+TEST(TransformOperationsTest, CanBlendWithMatrixTest) {
+  TransformOperations ops_a, ops_b;
+  ops_a.Operations().push_back(
+      MatrixTransformOperation::Create(1, 0, 0, 1, 0, 0));
+  ops_a.Operations().push_back(
+      RotateTransformOperation::Create(0, TransformOperation::kRotate));
+  ops_b.Operations().push_back(
+      MatrixTransformOperation::Create(2, 0, 0, 2, 0, 0));
+  ops_b.Operations().push_back(
+      RotateTransformOperation::Create(360, TransformOperation::kRotate));
+
+  EXPECT_TRUE(ops_a.Operations()[0]->CanBlendWith(*ops_b.Operations()[0]));
+
+  TransformOperations ops_blended = ops_a.Blend(ops_b, 0.5);
+  ASSERT_EQ(ops_blended.Operations().size(), 2u);
+  ASSERT_TRUE(IsA<MatrixTransformOperation>(*ops_blended.Operations()[0]));
+  ASSERT_TRUE(IsA<RotateTransformOperation>(*ops_blended.Operations()[1]));
+  EXPECT_EQ(To<RotateTransformOperation>(*ops_blended.Operations()[1]).Angle(),
+            180.0);
+}
+
+TEST(TransformOperationsTest, CanBlendWithMatrix3DTest) {
+  TransformOperations ops_a, ops_b;
+  ops_a.Operations().push_back(Matrix3DTransformOperation::Create(
+      TransformationMatrix(1, 0, 0, 1, 0, 0)));
+  ops_a.Operations().push_back(
+      RotateTransformOperation::Create(0, TransformOperation::kRotate));
+  ops_b.Operations().push_back(Matrix3DTransformOperation::Create(
+      TransformationMatrix(2, 0, 0, 2, 0, 0)));
+  ops_b.Operations().push_back(
+      RotateTransformOperation::Create(360, TransformOperation::kRotate));
+
+  EXPECT_TRUE(ops_a.Operations()[0]->CanBlendWith(*ops_b.Operations()[0]));
+
+  TransformOperations ops_blended = ops_a.Blend(ops_b, 0.5);
+  ASSERT_EQ(ops_blended.Operations().size(), 2u);
+  ASSERT_TRUE(IsA<Matrix3DTransformOperation>(*ops_blended.Operations()[0]));
+  ASSERT_TRUE(IsA<RotateTransformOperation>(*ops_blended.Operations()[1]));
+  EXPECT_EQ(To<RotateTransformOperation>(*ops_blended.Operations()[1]).Angle(),
+            180.0);
+}
+
 TEST(TransformOperationsTest, InterpolatedTransformBlendIdentityTest) {
   // When interpolating transform lists of differing lengths, the length of the
   // shorter list behaves as if it is padded with identity transforms.
diff --git a/third_party/blink/renderer/platform/transforms/translate_transform_operation.cc b/third_party/blink/renderer/platform/transforms/translate_transform_operation.cc
index 43dfa1f..da798565 100644
--- a/third_party/blink/renderer/platform/transforms/translate_transform_operation.cc
+++ b/third_party/blink/renderer/platform/transforms/translate_transform_operation.cc
@@ -74,8 +74,7 @@
     const TransformOperation* from,
     double progress,
     bool blend_to_identity) {
-  if (from && !from->CanBlendWith(*this))
-    return this;
+  DCHECK(!from || CanBlendWith(*from));
 
   const Length zero_length = Length::Fixed(0);
   if (blend_to_identity) {
@@ -97,13 +96,6 @@
       blink::Blend(from_z, z_, progress), is_3d ? kTranslate3D : kTranslate);
 }
 
-bool TranslateTransformOperation::CanBlendWith(
-    const TransformOperation& other) const {
-  return other.GetType() == kTranslate || other.GetType() == kTranslateX ||
-         other.GetType() == kTranslateY || other.GetType() == kTranslateZ ||
-         other.GetType() == kTranslate3D;
-}
-
 scoped_refptr<TranslateTransformOperation>
 TranslateTransformOperation::ZoomTranslate(double factor) {
   return Create(x_.Zoom(factor), y_.Zoom(factor), z_ * factor, type_);
diff --git a/third_party/blink/renderer/platform/transforms/translate_transform_operation.h b/third_party/blink/renderer/platform/transforms/translate_transform_operation.h
index 6cdf6d9..5b59533 100644
--- a/third_party/blink/renderer/platform/transforms/translate_transform_operation.h
+++ b/third_party/blink/renderer/platform/transforms/translate_transform_operation.h
@@ -52,7 +52,6 @@
     return *this == static_cast<const TransformOperation&>(other);
   }
 
-  bool CanBlendWith(const TransformOperation& other) const override;
   bool DependsOnBoxSize() const override {
     return x_.IsPercentOrCalc() || y_.IsPercentOrCalc();
   }
diff --git a/third_party/blink/renderer/platform/widget/input/scroll_predictor.cc b/third_party/blink/renderer/platform/widget/input/scroll_predictor.cc
index 64858a6..95e5f3f 100644
--- a/third_party/blink/renderer/platform/widget/input/scroll_predictor.cc
+++ b/third_party/blink/renderer/platform/widget/input/scroll_predictor.cc
@@ -13,7 +13,8 @@
 
 namespace blink {
 
-ScrollPredictor::ScrollPredictor() {
+ScrollPredictor::ScrollPredictor()
+    : metrics_handler_("Event.InputEventPrediction.Scroll") {
   // Get the predictor from feature flags
   std::string predictor_name = GetFieldTrialParamValueByFeature(
       blink::features::kResamplingScrollEvents, "predictor");
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 441c3109..93e2776 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -471,6 +471,11 @@
 external/wpt/css/css-text/white-space/trailing-ogham-002.html [ Skip ]
 external/wpt/css/css-text/white-space/trailing-ogham-003.html [ Skip ]
 
+# 1px pixel differences that are not relevant to the tests.
+external/wpt/css/CSS2/text/text-transform-bicameral-007.xht [ Skip ]
+[ Mac ] external/wpt/css/CSS2/text/text-transform-bicameral-014.xht [ Skip ]
+[ Mac ] external/wpt/css/CSS2/text/text-transform-bicameral-009.xht [ Skip ]
+
 external/wpt/css/CSS2/linebox/inline-formatting-context-010b.xht [ Skip ]
 external/wpt/css/CSS2/normal-flow/inline-block-replaced-height-008.xht [ Skip ]
 external/wpt/css/CSS2/normal-flow/inline-replaced-height-008.xht [ Skip ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index e7c1afe3..a12138c 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2609,14 +2609,6 @@
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-206.xht [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
-crbug.com/626703 external/wpt/css/CSS2/text/text-transform-bicameral-007.xht [ Failure ]
-crbug.com/626703 [ Mac10.12 ] external/wpt/css/CSS2/text/text-transform-bicameral-014.xht [ Failure ]
-crbug.com/626703 [ Mac10.13 ] external/wpt/css/CSS2/text/text-transform-bicameral-014.xht [ Failure ]
-crbug.com/626703 [ Mac10.14 ] external/wpt/css/CSS2/text/text-transform-bicameral-014.xht [ Failure ]
-crbug.com/626703 [ Mac ] external/wpt/css/CSS2/text/text-transform-bicameral-009.xht [ Failure ]
-crbug.com/626703 external/wpt/css/CSS2/text/text-indent-101.xht [ Failure ]
-crbug.com/626703 external/wpt/css/CSS2/text/text-indent-100.xht [ Failure ]
-crbug.com/626703 external/wpt/css/CSS2/text/text-indent-102.xht [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/letter-spacing/letter-spacing-203.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/letter-spacing/letter-spacing-201.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/letter-spacing/letter-spacing-206.html [ Failure ]
@@ -6622,6 +6614,9 @@
 crbug.com/1057060 virtual/scroll-unification/fast/scrolling/scrollbars/mouse-autoscrolling-on-scrollbar.html [ Pass Failure Timeout ]
 crbug.com/1045599 fast/css-grid-layout/flex-content-sized-columns-resize.html [ Pass Failure Timeout ]
 
+# TODO(michaelludwig) - Remove after Skia roll and rebaseline
+crbug.com/1135225 fast/sub-pixel/transformed-iframe-copy-on-scroll.html [ Pass Failure ]
+
 # Sheriff 2020-09-29
 crbug.com/1133342 external/wpt/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html [ Pass Failure Timeout ]
 crbug.com/1083605 media/controls-styling-strict.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-100.xht b/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-100.xht
index 7c498d2b..977d321 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-100.xht
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-100.xht
@@ -23,7 +23,7 @@
         </style>
     </head>
     <body>
-        <p>Test passes if there is only one black box on this page (with no jagged edges).</p>
+        <p>Test passes if there is one black box on this page (with no jagged edges).</p>
         <div id="parent">
             <div>X</div>
             <div id="test">X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-101.xht b/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-101.xht
index 5007ff6..35e155a 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-101.xht
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-101.xht
@@ -23,7 +23,7 @@
         </style>
     </head>
     <body>
-        <p>Test passes if there is only one black box on this page (with no jagged edges).</p>
+        <p>Test passes if there is one black box on this page (with no jagged edges).</p>
         <div id="parent">
             <div>X</div>
             <div id="test">X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-102.xht b/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-102.xht
index b187c79..a0352dea 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-102.xht
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/text/text-indent-102.xht
@@ -23,7 +23,7 @@
         </style>
     </head>
     <body>
-        <p>Test passes if there is only one black box on this page (with no jagged edges).</p>
+        <p>Test passes if there is one black box on this page (with no jagged edges).</p>
         <div id="parent">
             <div>X</div>
             <div id="test">X</div>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.html
index 091cfd06..6f0b77f22 100644
--- a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.html
+++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-deltas.html
@@ -11,6 +11,11 @@
   height: 500px;
   background: red;
 }
+html, body {
+  /* Prevent any built-in browser overscroll features from consuming the scroll
+   * deltas */
+  overscroll-behavior: none;
+}
 
 </style>
 
@@ -46,6 +51,11 @@
     await waitFor(() => { return scrollend_received; },
         'Document did not receive scrollend event.');
 
+    // Even though we request 300 pixels of scroll, the API above doesn't
+    // guarantee how much scroll delta will be generated - different browsers
+    // can consume different amounts for "touch slop" (for example). Ensure the
+    // overscroll reaches at least 100 pixels which is a fairly conservative
+    // value.
     assert_greater_than(overscrolled_y_deltas.length, 0, "There should be at least one overscroll events when overscrolling.");
     assert_equals(overscrolled_x_deltas.filter(function(x){ return x!=0; }).length, 0, "The deltaX attribute must be 0 when there is no scrolling in x direction.");
     assert_less_than_equal(Math.max(...overscrolled_y_deltas), 0, "The deltaY attribute must be <= 0 when there is overscrolling in up direction.");
@@ -61,10 +71,14 @@
     await waitFor(() => { return scrollend_received; },
         'Document did not receive scrollend event.');
 
+    // TODO(bokan): It looks like Chrome inappropriately filters some scroll
+    // events despite |overscroll-behavior| being set to none. The overscroll
+    // amount here has been loosened but this should be fixed in Chrome.
+    // https://crbug.com/1112183.
     assert_greater_than(overscrolled_y_deltas.length, 0, "There should be at least one overscroll events when overscrolling.");
     assert_equals(overscrolled_y_deltas.filter(function(x){ return x!=0; }).length, 0, "The deltaY attribute must be 0 when there is no scrolling in y direction.");
     assert_less_than_equal(Math.max(...overscrolled_x_deltas), 0, "The deltaX attribute must be <= 0 when there is overscrolling in left direction.");
-    assert_less_than_equal(Math.min(...overscrolled_x_deltas),-100, "The deltaX attribute must be the number of pixels overscrolled.");
+    assert_less_than_equal(Math.min(...overscrolled_x_deltas),-50, "The deltaX attribute must be the number of pixels overscrolled.");
 
   }, 'Tests that the document gets overscroll event with right deltaX/Y attributes.');
 }
diff --git a/third_party/blink/web_tests/external/wpt/editing/run/caret-navigation-around-line-break.html b/third_party/blink/web_tests/external/wpt/editing/run/caret-navigation-around-line-break.html
deleted file mode 100644
index 7f8576c..0000000
--- a/third_party/blink/web_tests/external/wpt/editing/run/caret-navigation-around-line-break.html
+++ /dev/null
@@ -1,136 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Caret navigation around line break</title>
-<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
-<meta name="assert" content="This test checks that caret navigation works well around various kinds of line breaks." />
-<style>
-.test {
-  font-size: 16px;
-  line-height: 20px;
-  padding: 4px;
-  width: 5.5ch;
-  padding: 5px;
-  font-family: monospace;
-  word-wrap: break-word;
-}
-</style>
-
-<div class="test" contenteditable data-title="no separator"
-    >line1line2</div>
-<div class="test" contenteditable data-title="<br> separator"
-    >line1<br>line2</div>
-<div class="test" contenteditable data-title="<wbr> separator"
-    >line1<wbr>line2</div>
-<div class="test" contenteditable data-title="<span> separator"
-    >line1<span></span>line2</div>
-<div class="test" contenteditable data-title="two <span> separators"
-    >line1<span></span><span></span>line2</div>
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
-<script src="/resources/testdriver-vendor.js"></script>
-<script src="/resources/testdriver-actions.js"></script>
-<script>
-const KEY_CODE_MAP = {
-  'ArrowLeft':  '\uE012',
-  'ArrowUp':    '\uE013',
-  'ArrowRight': '\uE014',
-  'ArrowDown':  '\uE015',
-};
-
-function click(target, x, y) {
-  return new test_driver.Actions()
-    .pointerMove(x, y, {origin: target})
-    .pointerDown()
-    .pointerUp()
-    .send();
-}
-
-const s = getSelection();
-for (const test of document.querySelectorAll(".test")) {
-  const padding = 4;
-  const halfLineWidth = Math.floor((test.offsetWidth - padding) / 2);
-  const halfLineHeight = Math.floor(20 / 2);
-  const hasSeparator = test.firstChild !== test.lastChild;
-  const line1 = {
-    node: test.firstChild,
-    start: 0,
-    end: "line1".length,
-  };
-  const line2 = {
-    node: test.lastChild,
-    start: hasSeparator ? 0 : "line1".length,
-    end: hasSeparator ? "line2".length : "line1line2".length,
-  };
-
-  promise_test(async t => {
-    // Click at the start of line 1
-    await click(test, -halfLineWidth, -halfLineHeight);
-    assert_equals(s.anchorNode, line1.node, "Caret is in line 1");
-    assert_equals(s.anchorOffset, line1.start, "Caret is at the start of line 1");
-
-    // Move down, expect start of line 2
-    await test_driver.send_keys(test, KEY_CODE_MAP.ArrowDown);
-    assert_equals(s.anchorNode, line2.node, "Caret moved to line 2");
-    assert_equals(s.anchorOffset, line2.start, "Caret moved to the start of line 2");
-
-    // Click at the end of line 1
-    await click(test, +halfLineWidth, -halfLineHeight);
-    range = getSelection().getRangeAt(0);
-    assert_equals(s.anchorNode, line1.node, "Caret is in line 1");
-    assert_equals(s.anchorOffset, line1.end, "Caret is at the end of line 1");
-
-    // Move down, expect end of line 2
-    await test_driver.send_keys(test, KEY_CODE_MAP.ArrowDown);
-    assert_equals(s.anchorNode, line2.node, "Caret moved to line 2");
-    assert_equals(s.anchorOffset, line2.end, "Caret moved to the end of line 2");
-  }, test.dataset.title + " - move down");
-
-  promise_test(async t => {
-    // Click at the start of line 2
-    await click(test, -halfLineWidth, +halfLineHeight);
-    assert_equals(s.anchorNode, line2.node, "Caret is in line 2");
-    assert_equals(s.anchorOffset, line2.start, "Caret is at the start of line 2");
-
-    // Move up, expect start of line 1
-    await test_driver.send_keys(test, KEY_CODE_MAP.ArrowUp);
-    assert_equals(s.anchorNode, line1.node, "Caret moved to line 1");
-    assert_equals(s.anchorOffset, line1.start, "Caret moved to the start of line 1");
-
-    // Click at the end of line 2
-    await click(test, +halfLineWidth, +halfLineHeight);
-    assert_equals(s.anchorNode, line2.node, "Caret is in line 2");
-    assert_equals(s.anchorOffset, line2.end, "Caret is at the end of line 2");
-
-    // Move up, expect end of line 1
-    await test_driver.send_keys(test, KEY_CODE_MAP.ArrowUp);
-    assert_equals(s.anchorNode, line1.node, "Caret moved to line 1");
-    assert_equals(s.anchorOffset, line1.end, "Caret moved to the end of line 1");
-  }, test.dataset.title + " - move up");
-
-  promise_test(async t => {
-    // Click at the end of line 1
-    await click(test, +halfLineWidth, -halfLineHeight);
-    assert_equals(s.anchorNode, line1.node, "Caret is in line 1");
-    assert_equals(s.anchorOffset, line1.end, "Caret is at the end of line 1");
-
-    // Move right, expect start or start+1 of line 2
-    await test_driver.send_keys(test, KEY_CODE_MAP.ArrowRight);
-    assert_equals(s.anchorNode, line2.node, "Caret moved to line 2");
-    assert_in_array(s.anchorOffset, [line2.start, line2.start + 1], "Caret moved to the start or start+1 of line 2");
-  }, test.dataset.title + " - move right");
-
-  promise_test(async t => {
-    // Click at the start of line 2
-    await click(test, -halfLineWidth, +halfLineHeight);
-    assert_equals(s.anchorNode, line2.node, "Caret is in line 2");
-    assert_equals(s.anchorOffset, line2.start, "Caret is at the start of line 2");
-
-    // Move left, expect end or end-1 of line 1
-    await test_driver.send_keys(test, KEY_CODE_MAP.ArrowLeft);
-    assert_equals(s.anchorNode, line1.node, "Caret moved to line 1");
-    assert_in_array(s.anchorOffset, [line1.end, line1.end - 1], "Caret moved to the end or end-1 of line 1");
-  }, test.dataset.title + " - move left");
-}
-</script>
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/rtc-quic-transport-origin-trial-interfaces.html b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/rtc-quic-transport-origin-trial-interfaces.html
index 4ae1c795..54e4fd7 100644
--- a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/rtc-quic-transport-origin-trial-interfaces.html
+++ b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/rtc-quic-transport-origin-trial-interfaces.html
@@ -4,32 +4,23 @@
 tools/origin_trials/generate_token.py http://127.0.0.1:8000 RTCQuicTransport --expire-timestamp=2000000000
 -->
 <meta http-equiv="origin-trial" content="Atq6Jbo2/q1/mFJ9lErFsAqkyeHIwkjR2qIq0jIhkh3UCvNEYAwfwd0cMLR9EF/qobLllgi4vGKKAJ23kdnCNgUAAABYeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiUlRDUXVpY1RyYW5zcG9ydCIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ==" />
-<title>RTCQuicTransport and RTCIceTransport - interfaces exposed by origin trial</title>
+<title>RTCIceTransport - interfaces exposed by origin trial</title>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../../resources/origin-trials-helper.js"></script>
 <script>
 
 properties_to_check = {
-    'RTCQuicTransport': ['transport', 'state', 'getKey', 'connect', 'listen',
-                         'stop', 'createStream', 'onstatechange', 'onerror',
-                         'onquicstream'],
     'RTCIceTransport': ['role', 'state', 'gatheringState', 'getLocalCandidates',
                         'getRemoteCandidates', 'getSelectedCandidatePair',
                         'getLocalParameters', 'getRemoteParameters',
                         'onstatechange', 'ongatheringstatechange',
                         'onselectedcandidatepairchange', 'gather', 'start',
                         'addRemoteCandidate', 'onicecandidate'],
-    'RTCQuicStream': ['transport', 'state', 'readBufferedAmount',
-                      'maxReadBufferedAmount', 'writeBufferedAmount',
-                      'readInto', 'write', 'reset',
-                      'waitForWriteBufferedAmountBelow',
-                      'waitForReadable', 'onstatechange'],
-    'RTCQuicStreamEvent': ['stream']
 };
 
 test(t => {
   OriginTrialsHelper.check_properties_exist(this, properties_to_check);
-}, 'RTCQuicTransport and RTCIceTransport properties are available.');
+}, 'RTCIceTransport properties are available.');
 
 </script>
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 394b5ef..13c3d00 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -6490,47 +6490,6 @@
     attribute @@toStringTag
     getter candidate
     method constructor
-interface RTCQuicStream : EventTarget
-    attribute @@toStringTag
-    getter maxReadBufferedAmount
-    getter maxWriteBufferedAmount
-    getter onstatechange
-    getter readBufferedAmount
-    getter state
-    getter transport
-    getter writeBufferedAmount
-    method constructor
-    method readInto
-    method reset
-    method waitForReadable
-    method waitForWriteBufferedAmountBelow
-    method write
-    setter onstatechange
-interface RTCQuicStreamEvent : Event
-    attribute @@toStringTag
-    getter stream
-    method constructor
-interface RTCQuicTransport : EventTarget
-    attribute @@toStringTag
-    getter maxDatagramLength
-    getter onerror
-    getter onquicstream
-    getter onstatechange
-    getter state
-    getter transport
-    method connect
-    method constructor
-    method createStream
-    method getKey
-    method getStats
-    method listen
-    method readyToSendDatagram
-    method receiveDatagrams
-    method sendDatagram
-    method stop
-    setter onerror
-    setter onquicstream
-    setter onstatechange
 interface RTCRtpReceiver
     static method getCapabilities
     attribute @@toStringTag
diff --git a/third_party/node/node_modules.py b/third_party/node/node_modules.py
index 7e38863..d45f1c3 100755
--- a/third_party/node/node_modules.py
+++ b/third_party/node/node_modules.py
@@ -38,8 +38,8 @@
   return _path_in_node_modules('svgo', 'bin', 'svgo')
 
 
-def PathToUglify():
-  return _path_in_node_modules('uglify-es', 'bin', 'uglifyjs')
+def PathToTerser():
+  return _path_in_node_modules('terser', 'bin', 'terser')
 
 # Typescript is not approved for general use in Chromium. Email chromium-dev
 # if you want to use it.
diff --git a/third_party/node/node_modules.tar.gz.sha1 b/third_party/node/node_modules.tar.gz.sha1
index 3a89d20..4cc191db 100644
--- a/third_party/node/node_modules.tar.gz.sha1
+++ b/third_party/node/node_modules.tar.gz.sha1
@@ -1 +1 @@
-a9603a3dc03fa41af9cc5c8ac28d23d1f98dfe3c
+57ebd65121c4ed969896f4bd8441077850951083
diff --git a/third_party/node/package-lock.json b/third_party/node/package-lock.json
index 5795bd76..2f766bb 100644
--- a/third_party/node/package-lock.json
+++ b/third_party/node/package-lock.json
@@ -485,6 +485,11 @@
         "concat-map": "0.0.1"
       }
     },
+    "buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
+    },
     "callsites": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -607,11 +612,6 @@
         "typical": "^2.6.0"
       }
     },
-    "commander": {
-      "version": "2.13.0",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
-      "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA=="
-    },
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -2212,6 +2212,22 @@
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
       "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
     },
+    "source-map-support": {
+      "version": "0.5.19",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+      "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+        }
+      }
+    },
     "sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -2367,6 +2383,28 @@
         "wordwrapjs": "^2.0.0-0"
       }
     },
+    "terser": {
+      "version": "5.3.3",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.3.tgz",
+      "integrity": "sha512-vRQDIlD+2Pg8YMwVK9kMM3yGylG95EIwzBai1Bw7Ot4OBfn3VP1TZn3EWx4ep2jERN/AmnVaTiGuelZSN7ds/A==",
+      "requires": {
+        "commander": "^2.20.0",
+        "source-map": "~0.7.2",
+        "source-map-support": "~0.5.19"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.20.3",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+        },
+        "source-map": {
+          "version": "0.7.3",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
+        }
+      }
+    },
     "test-value": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz",
@@ -2435,22 +2473,6 @@
       "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz",
       "integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0="
     },
-    "uglify-es": {
-      "version": "3.3.9",
-      "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
-      "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==",
-      "requires": {
-        "commander": "~2.13.0",
-        "source-map": "~0.6.1"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
-        }
-      }
-    },
     "unquote": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
diff --git a/third_party/node/package.json b/third_party/node/package.json
index d0801ae..c3c1a14 100644
--- a/third_party/node/package.json
+++ b/third_party/node/package.json
@@ -8,7 +8,7 @@
     "eslint": "5.16.0",
     "polymer-bundler": "4.0.10",
     "polymer-css-build": "0.7.0",
-    "uglify-es": "3.3.9",
+    "terser": "5.3.3",
     "svgo": "1.2.0",
     "typescript": "3.5.3"
   }
diff --git a/tools/grit/minify_with_uglify.py b/tools/grit/minify_with_uglify.py
index 788ffa6..1c12140 100755
--- a/tools/grit/minify_with_uglify.py
+++ b/tools/grit/minify_with_uglify.py
@@ -23,8 +23,8 @@
        tempfile.NamedTemporaryFile(suffix='.js') as outfile:
     infile.write(source)
     infile.flush();
-    node.RunNode([
-        node_modules.PathToUglify(), infile.name, '--output', outfile.name])
+    node.RunNode(
+        [node_modules.PathToTerser(), infile.name, '--output', outfile.name])
     result = outfile.read()
     return result
 
diff --git a/tools/memory/OWNERS b/tools/memory/OWNERS
index b17b756c..98b6a02264 100644
--- a/tools/memory/OWNERS
+++ b/tools/memory/OWNERS
@@ -1,4 +1,4 @@
-bruening@chromium.org
 glider@chromium.org
 thestig@chromium.org
 rnk@chromium.org
+vitalybuka@chromium.org
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9a926e3..3e3b6dd 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -35168,7 +35168,7 @@
   <int value="2" label="Last session crashed"/>
   <int value="3" label="Received survey in current milestone"/>
   <int value="4" label="Profile too new"/>
-  <int value="5" label="Last survey too recent"/>
+  <int value="5" label="Last instance of this survey too recent"/>
   <int value="6" label="Below probability limit"/>
   <int value="7" label="Trigger string mismatch"/>
   <int value="8" label="Not regular browser"/>
@@ -35182,6 +35182,7 @@
     The survey is over its capacity.
   </int>
   <int value="14" label="A survey is already in progress"/>
+  <int value="15" label="Last instance of any survey too recent"/>
 </enum>
 
 <enum name="HardwareVerifierQualificationStatus">
diff --git a/tools/metrics/histograms/expand_owners.py b/tools/metrics/histograms/expand_owners.py
index e57f6e59..762d2267 100644
--- a/tools/metrics/histograms/expand_owners.py
+++ b/tools/metrics/histograms/expand_owners.py
@@ -5,7 +5,10 @@
 """Functions for extracting emails and components from OWNERS files."""
 
 import extract_histograms
+import json
 import os
+import subprocess
+import sys
 import re
 
 _EMAIL_PATTERN = r'^[\w\-\+\%\.]+\@[\w\-\+\%\.]+$'
@@ -193,6 +196,57 @@
   return extracted_emails
 
 
+def _ComponentFromDirmd(json_data, subpath):
+  """Returns the component for a subpath based on dirmd output.
+
+  Returns an empty string if no component can be extracted
+
+  Args:
+    json_data: json object output from dirmd.
+    subpath: The subpath for the directory being queried, e.g. src/storage'.
+  """
+  # If no component exists for the directory, or if METADATA migration is
+  # incomplete there will be no component information.
+  return json_data.get('dirs', {}).get(subpath,
+                                       {}).get('monorail',
+                                               {}).get('component', '')
+
+
+def _ExtractComponentViaDirmd(path):
+  """Returns the component for monorail issues at the given path.
+
+  Examples are 'Blink>Storage>FileAPI' and 'UI'.
+
+  Uses dirmd in third_party/depot_tools to parse metadata and walk parent
+  directories up to the top level of the repo.
+
+  Returns an empty string if no component can be extracted.
+
+  Args:
+    path: The path to an directory to query, e.g. 'src/storage'.
+  """
+  # Verify that the paths are absolute and the root is a parent of the
+  # passed in path.
+  root_path = os.path.abspath(os.path.join(*_DIR_ABOVE_TOOLS))
+  path = os.path.abspath(path)
+  if not path.startswith(root_path):
+    raise Error('Path {} is not a subpath of the root path {}.'.format(
+        path, root_path))
+  subpath = path[len(root_path) + 1:] or '.'  # E.g. content/public.
+  dirmd_exe = 'dirmd'
+  if sys.platform == 'win32':
+    dirmd_exe = 'dirmd.bat'
+  dirmd_path = os.path.join(*(_DIR_ABOVE_TOOLS +
+                              ['third_party', 'depot_tools', dirmd_exe]))
+  dirmd = subprocess.Popen([dirmd_path, 'compute', '--root', root_path, path],
+                           stdout=subprocess.PIPE)
+  if dirmd.wait() != 0:
+    raise Error('dirmd failed.')
+  json_out = json.load(dirmd.stdout)
+  return _ComponentFromDirmd(json_out, subpath)
+
+
+# TODO(crbug/1102997): remove once metadata migration is complete
 def _ExtractComponentFromOWNERS(path):
   """Returns the string component associated with the file at the given path.
 
@@ -361,7 +415,9 @@
 
       _UpdateHistogramOwners(histogram, owner, owners_to_add)
 
-      component = _ExtractComponentFromOWNERS(path)
+      component = _ExtractComponentViaDirmd(os.path.dirname(path))
+      if not component:
+        component = _ExtractComponentFromOWNERS(path)
       if component and component not in components_with_dom_elements:
         components_with_dom_elements.add(component)
         _AddHistogramComponent(histogram, component)
diff --git a/tools/metrics/histograms/expand_owners_unittest.py b/tools/metrics/histograms/expand_owners_unittest.py
index a8457a1..6605362 100644
--- a/tools/metrics/histograms/expand_owners_unittest.py
+++ b/tools/metrics/histograms/expand_owners_unittest.py
@@ -32,6 +32,7 @@
   Args:
     path: An absolute path, e.g. '/some/directory/chromium/src/tools/OWNERS'.
   """
+  # TODO(crbug/1126653): This fails if chromium is not in the path.
   return path.split('chromium/')[1]
 
 
@@ -62,6 +63,61 @@
     super(ExpandOwnersTest, self).tearDown()
     shutil.rmtree(self.temp_dir)
 
+  def testExpandOwnersUsesMetadataOverOwners(self):
+    """Checks that DIR_METADATA is used if available"""
+    with open(os.path.join(self.temp_dir, 'DIR_METADATA'), "w+") as md:
+      md.write("\n".join(['monorail {', 'component: "Bees"', '}']))
+    absolute_path = _MakeOwnersFile('simple_OWNERS', self.temp_dir)
+    with open(absolute_path, 'w') as owners_file:
+      owners_file.write('\n'.join(
+          ['amy@chromium.org', _DEFAULT_COMPONENT, 'rae@chromium.org']))
+    self.maxDiff = None
+    src_relative_path = _GetSrcRelativePath(absolute_path)
+    histograms = xml.dom.minidom.parseString("""
+<histograms>
+
+<histogram name="Caffeination" units="mg">
+  <owner>joe@chromium.org</owner>
+  <owner>{path}</owner>
+  <summary>I like coffee.</summary>
+</histogram>
+
+<histogram name="Maple.Syrup" units="units">
+  <owner>joe@chromium.org</owner>
+  <owner>{path}</owner>
+  <owner>kim@chromium.org</owner>
+  <summary>I like maple syrup, too.</summary>
+</histogram>
+
+</histograms>
+""".format(path=src_relative_path))
+
+    expected_histograms = xml.dom.minidom.parseString("""
+<histograms>
+
+<histogram name="Caffeination" units="mg">
+  <owner>joe@chromium.org</owner>
+  <owner>amy@chromium.org</owner>
+  <owner>rae@chromium.org</owner>
+  <summary>I like coffee.</summary>
+  <component>Bees</component>
+</histogram>
+
+<histogram name="Maple.Syrup" units="units">
+  <owner>joe@chromium.org</owner>
+  <owner>amy@chromium.org</owner>
+  <owner>rae@chromium.org</owner>
+  <owner>kim@chromium.org</owner>
+  <summary>I like maple syrup, too.</summary>
+  <component>Bees</component>
+</histogram>
+
+</histograms>
+""")
+
+    expand_owners.ExpandHistogramsOWNERS(histograms)
+    self.assertMultiLineEqual(histograms.toxml(), expected_histograms.toxml())
+
   def testExpandOwnersWithSimpleOWNERSFilePath(self):
     """Checks that OWNERS files are expanded."""
     absolute_path = _MakeOwnersFile('simple_OWNERS', self.temp_dir)
@@ -326,7 +382,7 @@
 
     with self.assertRaisesRegexp(
         expand_owners.Error,
-        'The histogram Caffeination must have a valid first owner, i.e. a '
+        'The histogram Caffeination must have a valid primary owner, i.e. a '
         'person with an @google.com or @chromium.org email address.'):
       expand_owners.ExpandHistogramsOWNERS(histograms_without_valid_first_owner)
 
@@ -349,7 +405,7 @@
 
     with self.assertRaisesRegexp(
         expand_owners.Error,
-        'The histogram Caffeination must have a valid first owner, i.e. a '
+        'The histogram Caffeination must have a valid primary owner, i.e. a '
         'person with an @google.com or @chromium.org email address.'):
       expand_owners.ExpandHistogramsOWNERS(histograms_without_valid_first_owner)
 
@@ -372,7 +428,7 @@
 
     with self.assertRaisesRegexp(
         expand_owners.Error,
-        'The histogram Caffeination must have a valid first owner, i.e. a '
+        'The histogram Caffeination must have a valid primary owner, i.e. a '
         'person with an @google.com or @chromium.org email address.'):
       expand_owners.ExpandHistogramsOWNERS(histograms_without_valid_first_owner)
 
@@ -420,11 +476,6 @@
         r'No emails could be derived from .*empty_OWNERS\.'):
       expand_owners.ExpandHistogramsOWNERS(histograms_without_owners_from_file)
 
-    with self.assertRaisesRegexp(
-        expand_owners.Error,
-        r'The file at .*src/medium/medium/roast/OWNERS does not exist\.'):
-      expand_owners.ExpandHistogramsOWNERS(histograms_with_fake_file_path)
-
   def testExpandOwnersWithSameOwners(self):
     """
     Checks that no error is raised when all owners in a file are already in
@@ -449,8 +500,7 @@
 </histograms>
 """.format(src_relative_path))
 
-    self.assertEqual(
-        expand_owners.ExpandHistogramsOWNERS(histograms_string), [])
+    self.assertIsNone(expand_owners.ExpandHistogramsOWNERS(histograms_string))
 
   def testExpandOwnersWithoutOWNERSPathPrefix(self):
     """Checks that an error is raised when the path is not well-formatted."""
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index 74c5dab..4200739 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -546,7 +546,11 @@
   </suffix>
   <suffix name="PercentSameOrigin2"
       label="The percentage of bytes loaded from the same origin as the root
-             frame of the page or ad."/>
+             frame of the page or ad.">
+    <obsolete>
+      Removed 09/20.
+    </obsolete>
+  </suffix>
   <suffix name="SameOrigin"
       label="The number of bytes loaded from the same origin as the root frame
              of the page or ad.">
@@ -555,9 +559,13 @@
     </obsolete>
   </suffix>
   <suffix name="SameOrigin2"
-      label="The number of bytes (including those from both the HTTP cache
-             and memory cache) loaded from the same origin as the root frame
-             of the page or ad."/>
+      label="The number of bytes (including those from both the HTTP cache and
+             memory cache) loaded from the same origin as the root frame of
+             the page or ad.">
+    <obsolete>
+      Removed 09/20.
+    </obsolete>
+  </suffix>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes.AdFrames.PerFrame"/>
   <affected-histogram name="PageLoad.Clients.Ads.Bytes.FullPage"/>
   <affected-histogram
diff --git a/tools/metrics/histograms/histograms_xml/notifications/histograms.xml b/tools/metrics/histograms/histograms_xml/notifications/histograms.xml
index 952472e..206327d 100644
--- a/tools/metrics/histograms/histograms_xml/notifications/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/notifications/histograms.xml
@@ -592,7 +592,7 @@
 </histogram>
 
 <histogram name="Notifications.Triggers.DisplayDelay" units="ms"
-    expires_after="M82">
+    expires_after="M91">
   <owner>knollr@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -601,6 +601,27 @@
   </summary>
 </histogram>
 
+<histogram name="Notifications.Triggers.HasShowTrigger" enum="Boolean"
+    expires_after="M91">
+  <owner>knollr@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Indicates if the notificaiton has a show trigger. This is recorded before a
+    notification is written to the database if the notification triggers feature
+    is enabled.
+  </summary>
+</histogram>
+
+<histogram name="Notifications.Triggers.ShowTriggerDelay" units="days"
+    expires_after="M91">
+  <owner>knollr@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    The specified delay until the notification is displayed. This is recorded
+    before writing a notification with a valid show trigger to the database.
+  </summary>
+</histogram>
+
 <histogram name="Notifications.UsingNativeNotificationCenter"
     enum="BooleanNativeNotifications" expires_after="never">
 <!-- expires-never: core to the notification user experience. -->
diff --git a/tools/metrics/histograms/histograms_xml/obsolete_histograms.xml b/tools/metrics/histograms/histograms_xml/obsolete_histograms.xml
index 092784b..53e31c4 100644
--- a/tools/metrics/histograms/histograms_xml/obsolete_histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/obsolete_histograms.xml
@@ -47725,33 +47725,6 @@
   </summary>
 </histogram>
 
-<histogram name="Notifications.Triggers.HasShowTrigger" enum="Boolean"
-    expires_after="M86">
-  <obsolete>
-    Removed July 2020 as the Origin Trial is ramping down.
-  </obsolete>
-  <owner>knollr@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    Indicates if the notificaiton has a show trigger. This is recorded before a
-    notification is written to the database if the notification triggers feature
-    is enabled.
-  </summary>
-</histogram>
-
-<histogram name="Notifications.Triggers.ShowTriggerDelay" units="days"
-    expires_after="M86">
-  <obsolete>
-    Removed July 2020 as the Origin Trial is ramping down.
-  </obsolete>
-  <owner>knollr@chromium.org</owner>
-  <owner>peter@chromium.org</owner>
-  <summary>
-    The specified delay until the notification is displayed. This is recorded
-    before writing a notification with a valid show trigger to the database.
-  </summary>
-</histogram>
-
 <histogram name="Notifications.Windows.ImageRetainerDestructionTime" units="ms"
     expires_after="2018-10-23">
   <obsolete>
diff --git a/tools/metrics/histograms/histograms_xml/payment/histograms.xml b/tools/metrics/histograms/histograms_xml/payment/histograms.xml
index 3fb4d9d..510fc01 100644
--- a/tools/metrics/histograms/histograms_xml/payment/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/payment/histograms.xml
@@ -22,7 +22,7 @@
 <histograms>
 
 <histogram name="PaymentRequest.CheckoutFunnel"
-    enum="PaymentRequestCheckoutFunnelSteps" expires_after="M90">
+    enum="PaymentRequestCheckoutFunnelSteps" expires_after="2021-08-01">
   <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
@@ -35,14 +35,14 @@
 </histogram>
 
 <histogram name="PaymentRequest.CheckoutFunnel.Aborted"
-    enum="PaymentRequestAbortReason" expires_after="M85">
+    enum="PaymentRequestAbortReason" expires_after="2021-08-01">
   <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>The reason that lead to an abort of the Payment Request.</summary>
 </histogram>
 
 <histogram name="PaymentRequest.CheckoutFunnel.NoShow"
-    enum="PaymentRequestNoShowReason" expires_after="2020-05-24">
+    enum="PaymentRequestNoShowReason" expires_after="2021-08-01">
   <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
@@ -51,7 +51,7 @@
 </histogram>
 
 <histogram name="PaymentRequest.Events" units="bitfield value"
-    expires_after="2021-01-31">
+    expires_after="2021-08-01">
   <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
@@ -61,8 +61,8 @@
 </histogram>
 
 <histogram name="PaymentRequest.JourneyLoggerHasRecorded" enum="Boolean"
-    expires_after="2021-01-31">
-  <owner>sahel@chromium.org</owner>
+    expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     Whether a journey logger has recorded an events bit field or not.
@@ -70,8 +70,8 @@
 </histogram>
 
 <histogram name="PaymentRequest.JourneyLoggerHasRecordedMultipleTimes"
-    enum="Boolean" expires_after="M85">
-  <owner>sahel@chromium.org</owner>
+    enum="Boolean" expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     When a journey logger attempts to record multiple events bit fields.
@@ -79,8 +79,8 @@
 </histogram>
 
 <histogram name="PaymentRequest.MissingContactFields"
-    enum="PaymentRequestMissingContactFields" expires_after="2021-03-01">
-  <owner>sahel@chromium.org</owner>
+    enum="PaymentRequestMissingContactFields" expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     A bitfield representing different missing fields of the contact section in
@@ -92,8 +92,8 @@
 </histogram>
 
 <histogram name="PaymentRequest.MissingPaymentFields"
-    enum="PaymentRequestMissingPaymentFields" expires_after="2021-03-01">
-  <owner>sahel@chromium.org</owner>
+    enum="PaymentRequestMissingPaymentFields" expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     A bitfield representing different missing fields of the payment info section
@@ -105,8 +105,8 @@
 </histogram>
 
 <histogram name="PaymentRequest.MissingShippingFields"
-    enum="PaymentRequestMissingShippingFields" expires_after="2021-03-01">
-  <owner>sahel@chromium.org</owner>
+    enum="PaymentRequestMissingShippingFields" expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     A bitfield representing different missing fields of the shipping section in
@@ -118,7 +118,7 @@
 </histogram>
 
 <histogram name="PaymentRequest.NumberOfSuggestionsShown" units="units"
-    expires_after="2021-01-24">
+    expires_after="2021-08-01">
   <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
@@ -127,8 +127,8 @@
 </histogram>
 
 <histogram name="PaymentRequest.RefetchIconForInstalledApp" enum="Boolean"
-    expires_after="2021-06-24">
-  <owner>sahel@chromium.org</owner>
+    expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     True when chrome crawls to refetch the missing icon of an already installed
@@ -138,7 +138,7 @@
 
 <histogram
     name="PaymentRequest.SecurePaymentConfirmationCredentialIdSizeInBytes"
-    units="bytes" expires_after="M93">
+    units="bytes" expires_after="2021-08-01">
   <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
@@ -148,15 +148,15 @@
 </histogram>
 
 <histogram name="PaymentRequest.ServiceWorkerStatusCodeTimeout" enum="Boolean"
-    expires_after="2021-05-24">
-  <owner>sahel@chromium.org</owner>
+    expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>True when a service worker times out 5 mins after request.</summary>
 </histogram>
 
 <histogram name="PaymentRequest.TimeToCheckout.Completed" units="ms"
-    expires_after="2021-01-31">
-  <owner>sahel@chromium.org</owner>
+    expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     Records the time between a payment request .show() and its completion.
@@ -164,10 +164,10 @@
 </histogram>
 
 <histogram name="PaymentRequest.TimeToCheckout.Completed.Shown" units="ms"
-    expires_after="2021-01-31">
+    expires_after="2021-08-01">
 <!-- Name completed by histogram_suffixes name="PaymentRequestCompletedInstrument" -->
 
-  <owner>sahel@chromium.org</owner>
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     Records the time between a payment request .show() and its completion when
@@ -176,10 +176,10 @@
 </histogram>
 
 <histogram name="PaymentRequest.TimeToCheckout.Completed.SkippedShow"
-    units="ms" expires_after="2021-01-31">
+    units="ms" expires_after="2021-08-01">
 <!-- Name completed by histogram_suffixes name="PaymentRequestCompletedInstrument" -->
 
-  <owner>sahel@chromium.org</owner>
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     Records the time between a payment request .show() and its completion when
@@ -188,8 +188,8 @@
 </histogram>
 
 <histogram name="PaymentRequest.TimeToCheckout.OtherAborted" units="ms"
-    expires_after="2021-01-31">
-  <owner>sahel@chromium.org</owner>
+    expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     Records the time between a payment request .show() and its termination by
@@ -198,10 +198,10 @@
 </histogram>
 
 <histogram name="PaymentRequest.TimeToCheckout.UserAborted" units="ms"
-    expires_after="2021-01-31">
+    expires_after="2021-08-01">
 <!-- Name completed by histogram_suffixes name="PaymentRequestPaymentSheetShowStatus" -->
 
-  <owner>sahel@chromium.org</owner>
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     Records the time between a payment request .show() and its termination by
@@ -210,8 +210,8 @@
 </histogram>
 
 <histogram name="PaymentRequest.TransactionAmount.Completed"
-    enum="PaymentRequestTransactionSize" expires_after="2021-01-24">
-  <owner>sahel@chromium.org</owner>
+    enum="PaymentRequestTransactionSize" expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     Records the transaction amounts completed using payment request API after
@@ -220,8 +220,8 @@
 </histogram>
 
 <histogram name="PaymentRequest.TransactionAmount.Triggered"
-    enum="PaymentRequestTransactionSize" expires_after="2021-01-31">
-  <owner>sahel@chromium.org</owner>
+    enum="PaymentRequestTransactionSize" expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
   <owner>web-payments-team@google.com</owner>
   <summary>
     Records the transaction amounts triggered using payment request API after
diff --git a/tools/metrics/histograms/histograms_xml/service/histograms.xml b/tools/metrics/histograms/histograms_xml/service/histograms.xml
index 9fd509f0..799de5b 100644
--- a/tools/metrics/histograms/histograms_xml/service/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/service/histograms.xml
@@ -22,8 +22,9 @@
 <histograms>
 
 <histogram name="ServiceWorker.AbortPaymentEvent.Time" units="ms"
-    expires_after="M85">
-  <owner>nhiroki@chromium.org</owner>
+    expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
+  <owner>web-payments-team@google.com</owner>
   <owner>jinho.bang@samsung.com</owner>
   <summary>
     The time taken between dispatching an AbortPaymentEvent to a Service Worker
@@ -169,8 +170,9 @@
 </histogram>
 
 <histogram name="ServiceWorker.CanMakePaymentEvent.Time" units="ms"
-    expires_after="2020-04-19">
-  <owner>nhiroki@chromium.org</owner>
+    expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
+  <owner>web-payments-team@google.com</owner>
   <owner>jinho.bang@samsung.com</owner>
   <summary>
     The time taken between dispatching an CanMakePaymentEvent to a Service
@@ -661,8 +663,9 @@
 </histogram>
 
 <histogram name="ServiceWorker.PaymentRequestEvent.Time" units="ms"
-    expires_after="M81">
-  <owner>nhiroki@chromium.org</owner>
+    expires_after="2021-08-01">
+  <owner>danyao@chromium.org</owner>
+  <owner>web-payments-team@google.com</owner>
   <owner>jinho.bang@samsung.com</owner>
   <summary>
     The time taken between dispatching an PaymentRequestEvent to a Service
diff --git a/tools/metrics/histograms/histograms_xml/windows/histograms.xml b/tools/metrics/histograms/histograms_xml/windows/histograms.xml
index 727b22f..e30e2381 100644
--- a/tools/metrics/histograms/histograms_xml/windows/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/windows/histograms.xml
@@ -154,7 +154,7 @@
   <owner>wfh@chromium.org</owner>
   <owner>brucedawson@chromium.org</owner>
   <summary>
-    The Windows version (base::win::Version) as reported by VeryQueryValue() on
+    The Windows version (base::win::Version) as reported by VerQueryValue() on
     kernel32.dll. This is queried shortly after startup.
   </summary>
 </histogram>
@@ -222,11 +222,28 @@
   <owner>brucedawson@chromium.org</owner>
   <summary>
     A 32-bit value formed from combining the minor and patch level of the
-    currently running Windows operating system. E.g. &quot;Windows 10 OS Version
-    1809 (Build 17763.503)&quot; would be 17763 (0x4563), combined with 503
-    (0x1F7) = 0x456301F7. If either minor or patch level exceeds the value that
-    can fit in a 16-bit unsigned integer, then this histogram will report 0.
-    Reported once, shortly after browser startup.
+    currently running Windows operating system as reported by GetVersionEx().
+    E.g. &quot;Windows 10 OS Version 1809 (Build 17763.503)&quot; would be 17763
+    (0x4563), combined with 503 (0x1F7) = 0x456301F7. If either minor or patch
+    level exceeds the value that can fit in a 16-bit unsigned integer, then this
+    histogram will report 0. Reported once, shortly after browser startup.
+  </summary>
+</histogram>
+
+<histogram name="Windows.PatchLevelKernel32" enum="WindowsPatchLevel"
+    expires_after="never">
+<!-- expires-never: Needed to measure Windows ecosystem. -->
+
+  <owner>wfh@chromium.org</owner>
+  <owner>brucedawson@chromium.org</owner>
+  <summary>
+    A 32-bit value formed from combining the minor and patch level of the
+    currently running Windows operating system as reported by VerQueryValue() of
+    kernel32.dll. E.g. &quot;Windows 10 OS Version 1809 (Build 17763.503)&quot;
+    would be 17763 (0x4563), combined with 503 (0x1F7) = 0x456301F7. If either
+    minor or patch level exceeds the value that can fit in a 16-bit unsigned
+    integer, then this histogram will report 0. Reported once, shortly after
+    browser startup.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/merge_xml.py b/tools/metrics/histograms/merge_xml.py
index 510a7d6..697412f 100755
--- a/tools/metrics/histograms/merge_xml.py
+++ b/tools/metrics/histograms/merge_xml.py
@@ -128,8 +128,8 @@
   """
   node = doc.createElement(tag)
   for child in children:
-    # if child.tagName == 'histograms':
-    #   expand_owners.ExpandHistogramsOWNERS(child)
+    if child.tagName == 'histograms':
+      expand_owners.ExpandHistogramsOWNERS(child)
     node.appendChild(child)
   return node
 
diff --git a/tools/metrics/metrics_python_tests.py b/tools/metrics/metrics_python_tests.py
index a51946ec..5c9cafa 100755
--- a/tools/metrics/metrics_python_tests.py
+++ b/tools/metrics/metrics_python_tests.py
@@ -23,6 +23,8 @@
 sys.exit(
     typ.main(tests=resolve(
         'actions/extract_actions_test.py',
+        # TODO(crbug/1126653): Turn back on once tests can pass again.
+        # 'histograms/expand_owners_unittest.py',
         'histograms/extract_histograms_test.py',
         'histograms/generate_expired_histograms_array_unittest.py',
         'histograms/pretty_print_test.py',
diff --git a/tools/perf/core/tbmv3/metrics/webview_power_usage_metric.proto b/tools/perf/core/tbmv3/metrics/webview_power_usage_metric.proto
index 53141c8..2809a8253 100644
--- a/tools/perf/core/tbmv3/metrics/webview_power_usage_metric.proto
+++ b/tools/perf/core/tbmv3/metrics/webview_power_usage_metric.proto
@@ -11,21 +11,28 @@
 // power use through the CPU time they consume at different core frequencies.
 // Output values are in milliampere-seconds.
 
+message UsageByCoreType {
+  double little_cores_mas = 1;
+  double big_cores_mas = 2;
+  double bigger_core_mas = 3;
+  double total_mas = 4;  // sum of the fields above
+}
+
 message EstimatedWebViewAppPowerUsage {
   // Host app package name.
   string app_name = 1;
 
-  // Total app’s power consumption in milliampere-seconds.
-  // Includes renderer processes.
-  double total_app_power_mas = 2;
+  // Only browser + in-process renderer slices.
+  double webview_browser_slices_mas = 2;
 
-  // This is the sum of the following 3 fields.
-  // Includes renderer processes.
-  double webview_power_mas = 3;
+  // WebView-only browser + in-process renderer threads.
+  UsageByCoreType webview_only_usage = 3;
 
-  double webview_power_little_cores_mas = 4;
-  double webview_power_big_cores_mas = 5;
-  double webview_power_bigger_cores_mas = 6;
+  // All threads of the host app.
+  UsageByCoreType total_app_usage = 4;
+
+  // All out-of-process renderers.
+  UsageByCoreType renderer_usage = 5;
 }
 
 message WebViewPowerUsageMetric {
diff --git a/tools/perf/core/tbmv3/metrics/webview_power_usage_metric.sql b/tools/perf/core/tbmv3/metrics/webview_power_usage_metric.sql
index c9a0dc98..f66c37b 100644
--- a/tools/perf/core/tbmv3/metrics/webview_power_usage_metric.sql
+++ b/tools/perf/core/tbmv3/metrics/webview_power_usage_metric.sql
@@ -13,15 +13,38 @@
   'estimated_webview_app_power_usage',
   (SELECT RepeatedField(
       EstimatedWebViewAppPowerUsage(
-        'app_name', app_name,
-        'webview_power_mas', webview_power_mas,
-        'total_app_power_mas', total_app_power_mas,
-        'webview_power_little_cores_mas', webview_power_little_cores_mas,
-        'webview_power_big_cores_mas', webview_power_big_cores_mas,
-        'webview_power_bigger_cores_mas', webview_power_bigger_cores_mas
-       )
+        'app_name', webview_browser_slices_power_summary.app_name,
+        'webview_browser_slices_mas', webview_browser_slices_power_summary.power_mas,
+        'webview_only_usage',
+        (SELECT UsageByCoreType(
+          'little_cores_mas', webview_only_power_output.little_cores_mas,
+          'big_cores_mas', webview_only_power_output.big_cores_mas,
+          'bigger_cores_mas', webview_only_power_output.bigger_cores_mas,
+          'total_mas', webview_only_power_output.total_mas
+        )),
+        'total_app_usage',
+        (SELECT UsageByCoreType(
+          'little_cores_mas', total_app_power_output.little_cores_mas,
+          'big_cores_mas', total_app_power_output.big_cores_mas,
+          'bigger_cores_mas', total_app_power_output.bigger_cores_mas,
+          'total_mas', total_app_power_output.total_mas
+        )),
+        'renderer_usage',
+        (SELECT UsageByCoreType(
+          'little_cores_mas', webview_renderer_power_output.little_cores_mas,
+          'big_cores_mas', webview_renderer_power_output.big_cores_mas,
+          'bigger_cores_mas', webview_renderer_power_output.bigger_cores_mas,
+          'total_mas', webview_renderer_power_output.total_mas
+        ))
+      )
    )
-   FROM webview_power_summary
+   FROM webview_browser_slices_power_summary
+     INNER JOIN webview_only_power_output
+       ON webview_browser_slices_power_summary.app_name = webview_only_power_output.app_name
+     INNER JOIN total_app_power_output
+       ON webview_browser_slices_power_summary.app_name = total_app_power_output.app_name
+     INNER JOIN webview_renderer_power_output
+       ON webview_browser_slices_power_summary.app_name = webview_renderer_power_output.app_name
   ),
   'total_device_power_mas',
   (SELECT power_mas FROM total_device_power)
diff --git a/tools/valgrind/OWNERS b/tools/valgrind/OWNERS
index 2989131..e52b970 100644
--- a/tools/valgrind/OWNERS
+++ b/tools/valgrind/OWNERS
@@ -1,3 +1 @@
-bruening@chromium.org
-glider@chromium.org
-thestig@chromium.org
+file://tools/memory/OWNERS
diff --git a/tools/vscode/keybindings.json5 b/tools/vscode/keybindings.json5
index e1e0b06..3a83b89f 100644
--- a/tools/vscode/keybindings.json5
+++ b/tools/vscode/keybindings.json5
@@ -1,6 +1,6 @@
 // Place your key bindings in this file to overwrite the defaults
 [
-  // Run the task marked as "isTestCommand": true, see tasks.json.
+  // Run the task marked as "group": "test", see tasks.json.
   { "key": "ctrl+shift+t",       "command": "workbench.action.tasks.test" },
   // Jump to the previous change in the built-in diff tool.
   { "key": "ctrl+up",            "command": "workbench.action.compareEditor.previousChange" },
@@ -16,7 +16,7 @@
   // key binding from the C/C++ extension as I found it to be slow).
   { "key": "alt+o",              "command": "togglehs.toggleHS" },
   // Quickly run a task, see tasks.json. Since we named them 1-, 2- etc., it is
-  // suffucient to press the corresponding number.
+  // sufficient to press the corresponding number.
   { "key": "ctrl+r",             "command": "workbench.action.tasks.runTask",
                                     "when": "!inDebugMode" },
   // The following keybindings are useful on laptops with small keyboards such as
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index 73789da..403fc18 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -21,7 +21,7 @@
 // Enable exposing the <html> element to the browser process AXTree
 // (as an ignored node).
 const base::Feature kEnableAccessibilityExposeHTMLElement{
-    "AccessibilityExposeHTMLElement", base::FEATURE_DISABLED_BY_DEFAULT};
+    "AccessibilityExposeHTMLElement", base::FEATURE_ENABLED_BY_DEFAULT};
 
 bool IsAccessibilityExposeHTMLElementEnabled() {
   return base::FeatureList::IsEnabled(
diff --git a/ui/base/prediction/prediction_metrics_handler.cc b/ui/base/prediction/prediction_metrics_handler.cc
index e782e67..f1d9b1d8 100644
--- a/ui/base/prediction/prediction_metrics_handler.cc
+++ b/ui/base/prediction/prediction_metrics_handler.cc
@@ -2,14 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "ui/base/prediction/prediction_metrics_handler.h"
 
 #include "base/metrics/histogram_functions.h"
+#include "base/strings/strcat.h"
 
 namespace ui {
 
-PredictionMetricsHandler::PredictionMetricsHandler() {}
-PredictionMetricsHandler::~PredictionMetricsHandler() {}
+PredictionMetricsHandler::PredictionMetricsHandler(const char* histogram_name)
+    : histogram_name_(std::move(histogram_name)) {}
+PredictionMetricsHandler::~PredictionMetricsHandler() = default;
 
 void PredictionMetricsHandler::AddRealEvent(const gfx::PointF& pos,
                                             const base::TimeTicks& time_stamp,
@@ -130,25 +134,25 @@
   for (int i = 0; i < first_needed_event - 1; i++)
     events_queue_.pop_front();
 
-  std::string kPredictionMetrics = "Event.InputEventPrediction.Scroll.";
-
   double score = ComputeOverUnderPredictionMetric();
   if (score >= 0) {
-    base::UmaHistogramCounts1000(kPredictionMetrics + "OverPrediction", score);
+    base::UmaHistogramCounts1000(
+        base::StrCat({histogram_name_, ".OverPrediction"}), score);
   } else {
-    base::UmaHistogramCounts1000(kPredictionMetrics + "UnderPrediction",
-                                 -score);
+    base::UmaHistogramCounts1000(
+        base::StrCat({histogram_name_, ".UnderPrediction"}), -score);
   }
 
   // Need |last_predicted_| to compute WrongDirection and Jitter metrics.
   if (!last_predicted_.has_value())
     return;
 
-  base::UmaHistogramBoolean(kPredictionMetrics + "WrongDirection",
+  base::UmaHistogramBoolean(base::StrCat({histogram_name_, ".WrongDirection"}),
                             ComputeWrongDirectionMetric());
-  base::UmaHistogramCounts1000(kPredictionMetrics + "PredictionJitter",
-                               ComputePredictionJitterMetric());
-  base::UmaHistogramCounts1000(kPredictionMetrics + "VisualJitter",
+  base::UmaHistogramCounts1000(
+      base::StrCat({histogram_name_, ".PredictionJitter"}),
+      ComputePredictionJitterMetric());
+  base::UmaHistogramCounts1000(base::StrCat({histogram_name_, ".VisualJitter"}),
                                ComputeVisualJitterMetric());
 }
 
diff --git a/ui/base/prediction/prediction_metrics_handler.h b/ui/base/prediction/prediction_metrics_handler.h
index 648ccdd..24167f5 100644
--- a/ui/base/prediction/prediction_metrics_handler.h
+++ b/ui/base/prediction/prediction_metrics_handler.h
@@ -25,7 +25,7 @@
 // few metrics.
 class COMPONENT_EXPORT(UI_BASE_PREDICTION) PredictionMetricsHandler {
  public:
-  explicit PredictionMetricsHandler();
+  explicit PredictionMetricsHandler(const char* histogram_name);
   ~PredictionMetricsHandler();
 
   // Struct used to store predicted and real event information.
@@ -103,6 +103,12 @@
   base::Optional<gfx::PointF> last_predicted_ = base::nullopt;
   // The first real event position which time is later than the predicted time.
   gfx::PointF next_real_;
+
+  // Beginning of the full histogram name. It will have the various metrics'
+  // names (.OverPrediction, .UnderPrediction, .WrongDirection,
+  // .PredictionJitter, .VisualJitter) appended to it when counting the metric
+  // in a histogram.
+  const char* const histogram_name_;
 };
 
 }  // namespace ui
diff --git a/ui/base/prediction/prediction_metrics_handler_unittest.cc b/ui/base/prediction/prediction_metrics_handler_unittest.cc
index f44df0d..fcfa9c0 100644
--- a/ui/base/prediction/prediction_metrics_handler_unittest.cc
+++ b/ui/base/prediction/prediction_metrics_handler_unittest.cc
@@ -29,7 +29,8 @@
   explicit PredictionMetricsHandlerTest() {}
 
   void SetUp() override {
-    metrics_handler_ = std::make_unique<PredictionMetricsHandler>();
+    metrics_handler_ = std::make_unique<PredictionMetricsHandler>(
+        "Event.InputEventPrediction.Scroll");
     histogram_tester_ = std::make_unique<base::HistogramTester>();
   }
 
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
index e15964c0..c3d7fdc 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.cc
@@ -152,6 +152,19 @@
   plane_list->atomic_property_set.reset(drmModeAtomicAlloc());
 }
 
+void HardwareDisplayPlaneManager::RestoreCurrentPlaneList(
+    HardwareDisplayPlaneList* plane_list) const {
+  for (auto* plane : plane_list->plane_list) {
+    plane->set_in_use(false);
+  }
+  for (auto* plane : plane_list->old_plane_list) {
+    plane->set_in_use(true);
+  }
+  plane_list->plane_list.clear();
+  plane_list->legacy_page_flips.clear();
+  plane_list->atomic_property_set.reset(drmModeAtomicAlloc());
+}
+
 void HardwareDisplayPlaneManager::BeginFrame(
     HardwareDisplayPlaneList* plane_list) {
   for (auto* plane : plane_list->old_plane_list) {
@@ -174,8 +187,7 @@
     HardwareDisplayPlane* hw_plane =
         FindNextUnusedPlane(&plane_idx, crtc_index, plane);
     if (!hw_plane) {
-      LOG(ERROR) << "Failed to find a free plane for crtc " << crtc_id;
-      ResetCurrentPlaneList(plane_list);
+      RestoreCurrentPlaneList(plane_list);
       return false;
     }
 
@@ -191,7 +203,7 @@
                   crop_rect.width() << 16, crop_rect.height() << 16);
 
     if (!SetPlaneData(plane_list, hw_plane, plane, crtc_id, fixed_point_rect)) {
-      ResetCurrentPlaneList(plane_list);
+      RestoreCurrentPlaneList(plane_list);
       return false;
     }
 
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
index e5d3448..92d24a5 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
@@ -223,7 +223,13 @@
                             const DrmOverlayPlane& overlay,
                             uint32_t crtc_index) const;
 
+  // Resets |plane_list| setting all planes to unused.
+  // Frees any temporary data structure in |plane_list| used for pageflipping.
   void ResetCurrentPlaneList(HardwareDisplayPlaneList* plane_list) const;
+  // Restores |plane_list| planes |in_use| flag to what it was before
+  // BeginFrame was called.
+  // Frees any temporary data structure in |plane_list| used for pageflipping.
+  void RestoreCurrentPlaneList(HardwareDisplayPlaneList* plane_list) const;
 
   // Populates scanout formats supported by all planes.
   void PopulateSupportedFormats();
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
index a79fea8..27db5f99 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.cc
@@ -168,9 +168,12 @@
   }
 
   if (test_only) {
-    for (HardwareDisplayPlane* plane : plane_list->plane_list) {
+    for (auto* plane : plane_list->plane_list) {
       plane->set_in_use(false);
     }
+    for (auto* plane : plane_list->old_plane_list) {
+      plane->set_in_use(true);
+    }
   } else {
     plane_list->plane_list.swap(plane_list->old_plane_list);
   }
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
index 5e0beab9..a14bfff1 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_unittest.cc
@@ -619,6 +619,72 @@
   EXPECT_EQ(0u, GetPlanePropertyValue(kPlaneOffset + 1, "FB_ID"));
 }
 
+TEST_P(HardwareDisplayPlaneManagerAtomicTest, AssignPlanesRestoresInUse) {
+  InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2);
+  fake_drm_->InitializeState(crtc_properties_, connector_properties_,
+                             plane_properties_, property_names_, use_atomic_);
+
+  ui::DrmOverlayPlaneList assigns;
+  scoped_refptr<ui::DrmFramebuffer> primary_buffer =
+      CreateBuffer(kDefaultBufferSize);
+  scoped_refptr<ui::DrmFramebuffer> overlay_buffer =
+      CreateBuffer(gfx::Size(1, 1));
+  assigns.push_back(ui::DrmOverlayPlane(primary_buffer, nullptr));
+  assigns.push_back(ui::DrmOverlayPlane(overlay_buffer, nullptr));
+  ui::HardwareDisplayPlaneList hdpl;
+
+  scoped_refptr<ui::PageFlipRequest> page_flip_request =
+      base::MakeRefCounted<ui::PageFlipRequest>(base::TimeDelta());
+  fake_drm_->plane_manager()->BeginFrame(&hdpl);
+  EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+      &hdpl, assigns, crtc_properties_[0].id));
+  EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+      &hdpl, /*should_modeset*/ false, page_flip_request, nullptr));
+  EXPECT_TRUE(fake_drm_->plane_manager()->planes().front()->in_use());
+  assigns.push_back(ui::DrmOverlayPlane(overlay_buffer, nullptr));
+
+  fake_drm_->plane_manager()->BeginFrame(&hdpl);
+  // Assign overlay planes will fail since there aren't enough planes.
+  EXPECT_FALSE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+      &hdpl, assigns, crtc_properties_[0].id));
+
+  // The primary plane should still be in use since we failed to assign
+  // planes and did not commit a new configuration.
+  EXPECT_TRUE(fake_drm_->plane_manager()->planes().front()->in_use());
+}
+
+TEST_P(HardwareDisplayPlaneManagerAtomicTest, PageflipTestRestoresInUse) {
+  InitializeDrmState(/*crtc_count=*/2, /*planes_per_crtc=*/2);
+  fake_drm_->InitializeState(crtc_properties_, connector_properties_,
+                             plane_properties_, property_names_, use_atomic_);
+
+  ui::DrmOverlayPlaneList assigns;
+  scoped_refptr<ui::DrmFramebuffer> primary_buffer =
+      CreateBuffer(kDefaultBufferSize);
+  scoped_refptr<ui::DrmFramebuffer> overlay_buffer =
+      CreateBuffer(gfx::Size(1, 1));
+  assigns.push_back(ui::DrmOverlayPlane(primary_buffer, nullptr));
+  assigns.push_back(ui::DrmOverlayPlane(overlay_buffer, nullptr));
+  ui::HardwareDisplayPlaneList hdpl;
+
+  scoped_refptr<ui::PageFlipRequest> page_flip_request =
+      base::MakeRefCounted<ui::PageFlipRequest>(base::TimeDelta());
+  fake_drm_->plane_manager()->BeginFrame(&hdpl);
+  EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+      &hdpl, assigns, crtc_properties_[0].id));
+  EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+      &hdpl, /*should_modeset*/ false, page_flip_request, nullptr));
+  assigns.clear();
+  fake_drm_->plane_manager()->BeginFrame(&hdpl);
+  EXPECT_TRUE(fake_drm_->plane_manager()->AssignOverlayPlanes(
+      &hdpl, assigns, crtc_properties_[0].id));
+  EXPECT_TRUE(fake_drm_->plane_manager()->Commit(
+      &hdpl, /*should_modeset*/ false, nullptr, nullptr));
+  // The primary plane should still be in use since the commit was
+  // a pageflip test and did not change any KMS state.
+  EXPECT_TRUE(fake_drm_->plane_manager()->planes().front()->in_use());
+}
+
 TEST_P(HardwareDisplayPlaneManagerAtomicTest, MultipleFrames) {
   ui::DrmOverlayPlaneList assigns;
   assigns.push_back(ui::DrmOverlayPlane(fake_buffer_, nullptr));
diff --git a/ui/views/bubble/bubble_dialog_model_host.cc b/ui/views/bubble/bubble_dialog_model_host.cc
index 64376a9b..f467c97f 100644
--- a/ui/views/bubble/bubble_dialog_model_host.cc
+++ b/ui/views/bubble/bubble_dialog_model_host.cc
@@ -207,7 +207,11 @@
   // TODO(pbos): Note that this is in place because GridLayout doesn't handle
   // View removal correctly (keeps stale pointers). This is in place to prevent
   // UAFs between Widget::Close() and destroying |this|.
-  SetLayoutManager(nullptr);
+  // TODO(pbos): This uses a non-nullptr LayoutManager only to prevent infinite
+  // recursion in CalculatePreferredSize(). CalculatePreferredSize calls
+  // GetHeightForWidth(), which if there is no LayoutManager calls
+  // GetPreferredSize(). See https://crbug.com/1128500.
+  SetLayoutManager(std::make_unique<GridLayout>());
 
   // TODO(pbos): Consider turning this into for-each-field remove field.
   RemoveAllChildViews(true);
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc
index 8143051..36ee16f 100644
--- a/ui/views/controls/scroll_view.cc
+++ b/ui/views/controls/scroll_view.cc
@@ -24,12 +24,28 @@
 #include "ui/views/border.h"
 #include "ui/views/controls/focus_ring.h"
 #include "ui/views/style/platform_style.h"
+#include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
 namespace views {
 
 namespace {
 
+// Returns the combined scroll amount given separate x and y offsets. This is
+// used in the "treat all scroll events as horizontal" case when there is both
+// an x and y offset and we do not want them to add in unintuitive ways.
+//
+// The current approach is to return whichever offset has the larger absolute
+// value, which should at least handle the case in which the gesture is mostly
+// vertical or horizontal. It does mean that for a gesture at 135° or 315° from
+// the x axis there is a breakpoint where scroll direction reverses, but we do
+// not typically expect users to try to scroll a horizontal-scroll-only view at
+// this exact angle.
+template <class T>
+T CombineScrollOffsets(T x, T y) {
+  return std::abs(x) >= std::abs(y) ? x : y;
+}
+
 class ScrollCornerView : public View {
  public:
   ScrollCornerView() = default;
@@ -303,11 +319,42 @@
                    contents_viewport_->height());
 }
 
-void ScrollView::SetHideHorizontalScrollBar(bool visible) {
-  if (hide_horizontal_scrollbar_ == visible)
+void ScrollView::SetHorizontalScrollBarMode(
+    ScrollBarMode horizontal_scroll_bar_mode) {
+  if (horizontal_scroll_bar_mode_ == horizontal_scroll_bar_mode)
     return;
-  hide_horizontal_scrollbar_ = visible;
-  OnPropertyChanged(&hide_horizontal_scrollbar_, kPropertyEffectsPaint);
+  horizontal_scroll_bar_mode_ = horizontal_scroll_bar_mode;
+  OnPropertyChanged(&horizontal_scroll_bar_mode_, kPropertyEffectsPaint);
+}
+
+void ScrollView::SetVerticalScrollBarMode(
+    ScrollBarMode vertical_scroll_bar_mode) {
+  if (vertical_scroll_bar_mode_ == vertical_scroll_bar_mode)
+    return;
+
+  // Enabling vertical scrolling is incompatible with all scrolling being
+  // interpreted as horizontal.
+  DCHECK(!treat_all_scroll_events_as_horizontal_ ||
+         vertical_scroll_bar_mode == ScrollBarMode::kDisabled);
+
+  vertical_scroll_bar_mode_ = vertical_scroll_bar_mode;
+  OnPropertyChanged(&vertical_scroll_bar_mode_, kPropertyEffectsPaint);
+}
+
+void ScrollView::SetTreatAllScrollEventsAsHorizontal(
+    bool treat_all_scroll_events_as_horizontal) {
+  if (treat_all_scroll_events_as_horizontal_ ==
+      treat_all_scroll_events_as_horizontal) {
+    return;
+  }
+  treat_all_scroll_events_as_horizontal_ =
+      treat_all_scroll_events_as_horizontal;
+  OnPropertyChanged(&treat_all_scroll_events_as_horizontal_,
+                    kPropertyEffectsNone);
+
+  // Since this effectively disables vertical scrolling, don't show a
+  // vertical scrollbar.
+  SetVerticalScrollBarMode(ScrollBarMode::kDisabled);
 }
 
 void ScrollView::SetDrawOverflowIndicator(bool draw_overflow_indicator) {
@@ -383,9 +430,10 @@
 }
 
 void ScrollView::Layout() {
-  // When horizontal scrollbar is disabled, it should not matter
-  // if its OverlapsContent matches vertical bar's.
-  if (!hide_horizontal_scrollbar_) {
+  // When either scrollbar is disabled, it should not matter
+  // if its OverlapsContent matches other bar's.
+  if (horizontal_scroll_bar_mode_ == ScrollBarMode::kEnabled &&
+      vertical_scroll_bar_mode_ == ScrollBarMode::kEnabled) {
 #if defined(OS_APPLE)
     // On Mac, scrollbars may update their style one at a time, so they may
     // temporarily be of different types. Refuse to lay out at this point.
@@ -578,10 +626,10 @@
   bool processed = false;
 
   // Give vertical scrollbar priority
-  if (vert_sb_->GetVisible())
+  if (IsVerticalScrollEnabled())
     processed = vert_sb_->OnKeyPressed(event);
 
-  if (!processed && horiz_sb_->GetVisible())
+  if (!processed && IsHorizontalScrollEnabled())
     processed = horiz_sb_->OnKeyPressed(event);
 
   return processed;
@@ -590,12 +638,21 @@
 bool ScrollView::OnMouseWheel(const ui::MouseWheelEvent& e) {
   bool processed = false;
 
-  // TODO(https://crbug.com/615948): Use composited scrolling.
-  if (vert_sb_->GetVisible())
-    processed = vert_sb_->OnMouseWheel(e);
+  const ui::MouseWheelEvent to_propagate =
+      treat_all_scroll_events_as_horizontal_
+          ? ui::MouseWheelEvent(
+                e, CombineScrollOffsets(e.x_offset(), e.y_offset()), 0)
+          : e;
 
-  if (horiz_sb_->GetVisible())
-    processed = horiz_sb_->OnMouseWheel(e) || processed;
+  // TODO(https://crbug.com/615948): Use composited scrolling.
+  if (IsVerticalScrollEnabled())
+    processed = vert_sb_->OnMouseWheel(to_propagate);
+
+  if (IsHorizontalScrollEnabled()) {
+    // When there is no vertical scrollbar, allow vertical scroll events to be
+    // interpreted as horizontal scroll events.
+    processed |= horiz_sb_->OnMouseWheel(to_propagate);
+  }
 
   return processed;
 }
@@ -604,13 +661,28 @@
   if (!contents_)
     return;
 
+  // Possibly force the scroll event to horizontal based on the configuration
+  // option.
+  ui::ScrollEvent e =
+      treat_all_scroll_events_as_horizontal_
+          ? ui::ScrollEvent(
+                event->type(), event->location_f(), event->root_location_f(),
+                event->time_stamp(), event->flags(),
+                CombineScrollOffsets(event->x_offset(), event->y_offset()),
+                0.0f,
+                CombineScrollOffsets(event->y_offset_ordinal(),
+                                     event->x_offset_ordinal()),
+                0.0f, event->finger_count(), event->momentum_phase(),
+                event->scroll_event_phase())
+          : *event;
+
   ui::ScrollInputHandler* compositor_scroller =
       GetWidget()->GetCompositor()->scroll_input_handler();
   if (compositor_scroller) {
     DCHECK(scroll_with_layers_enabled_);
-    if (compositor_scroller->OnScrollEvent(*event, contents_->layer())) {
-      event->SetHandled();
-      event->StopPropagation();
+    if (compositor_scroller->OnScrollEvent(e, contents_->layer())) {
+      e.SetHandled();
+      e.StopPropagation();
     }
   }
 
@@ -618,9 +690,15 @@
   // scrollbars that they may be about scroll, or that they may need to cancel
   // UI feedback once the scrolling direction is known.
   if (horiz_sb_)
-    horiz_sb_->ObserveScrollEvent(*event);
+    horiz_sb_->ObserveScrollEvent(e);
   if (vert_sb_)
-    vert_sb_->ObserveScrollEvent(*event);
+    vert_sb_->ObserveScrollEvent(e);
+
+  // Need to copy state back to original event.
+  if (e.handled())
+    event->SetHandled();
+  if (e.stopped_propagation())
+    event->StopPropagation();
 }
 
 void ScrollView::OnGestureEvent(ui::GestureEvent* event) {
@@ -632,14 +710,20 @@
                       event->type() == ui::ET_GESTURE_SCROLL_END ||
                       event->type() == ui::ET_SCROLL_FLING_START;
 
+  // Note: we will not invert gesture events because it will be confusing to
+  // have a vertical finger gesture on a touchscreen cause the scroll pane to
+  // scroll horizontally.
+
   // TODO(https://crbug.com/615948): Use composited scrolling.
-  if (vert_sb_->GetVisible()) {
-    if (vert_sb_->bounds().Contains(event->location()) || scroll_event)
-      vert_sb_->OnGestureEvent(event);
+  if (IsVerticalScrollEnabled() &&
+      (scroll_event || (vert_sb_->GetVisible() &&
+                        vert_sb_->bounds().Contains(event->location())))) {
+    vert_sb_->OnGestureEvent(event);
   }
-  if (!event->handled() && horiz_sb_->GetVisible()) {
-    if (horiz_sb_->bounds().Contains(event->location()) || scroll_event)
-      horiz_sb_->OnGestureEvent(event);
+  if (!event->handled() && IsHorizontalScrollEnabled() &&
+      (scroll_event || (horiz_sb_->GetVisible() &&
+                        horiz_sb_->bounds().Contains(event->location())))) {
+    horiz_sb_->OnGestureEvent(event);
   }
 }
 
@@ -719,13 +803,13 @@
     return;
 
   gfx::ScrollOffset offset = CurrentOffset();
-  if (source == horiz_sb_.get() && horiz_sb_->GetVisible()) {
+  if (source == horiz_sb_.get() && IsHorizontalScrollEnabled()) {
     position = AdjustPosition(offset.x(), position, contents_->width(),
                               contents_viewport_->width());
     if (offset.x() == position)
       return;
     offset.set_x(position);
-  } else if (source == vert_sb_.get() && vert_sb_->GetVisible()) {
+  } else if (source == vert_sb_.get() && IsVerticalScrollEnabled()) {
     position = AdjustPosition(offset.y(), position, contents_->height(),
                               contents_viewport_->height());
     if (offset.y() == position)
@@ -783,8 +867,10 @@
 }
 
 void ScrollView::ScrollContentsRegionToBeVisible(const gfx::Rect& rect) {
-  if (!contents_ || (!horiz_sb_->GetVisible() && !vert_sb_->GetVisible()))
+  if (!contents_ ||
+      (!IsHorizontalScrollEnabled() && !IsVerticalScrollEnabled())) {
     return;
+  }
 
   // Figure out the maximums for this scroll view.
   const int contents_max_x =
@@ -830,9 +916,19 @@
                                              const gfx::Size& content_size,
                                              bool* horiz_is_shown,
                                              bool* vert_is_shown) const {
-  if (hide_horizontal_scrollbar_) {
+  const bool horizontal_enabled =
+      horizontal_scroll_bar_mode_ == ScrollBarMode::kEnabled;
+  const bool vertical_enabled =
+      vertical_scroll_bar_mode_ == ScrollBarMode::kEnabled;
+  if (!horizontal_enabled) {
     *horiz_is_shown = false;
-    *vert_is_shown = content_size.height() > vp_size.height();
+    *vert_is_shown =
+        vertical_enabled && content_size.height() > vp_size.height();
+    return;
+  }
+  if (!vertical_enabled) {
+    *vert_is_shown = false;
+    *horiz_is_shown = content_size.width() > vp_size.width();
     return;
   }
 
@@ -876,12 +972,12 @@
     return;
 
   const gfx::ScrollOffset offset = CurrentOffset();
-  if (horiz_sb_->GetVisible()) {
+  if (IsHorizontalScrollEnabled()) {
     int vw = contents_viewport_->width();
     int cw = contents_->width();
     horiz_sb_->Update(vw, cw, offset.x());
   }
-  if (vert_sb_->GetVisible()) {
+  if (IsVerticalScrollEnabled()) {
     int vh = contents_viewport_->height();
     int ch = contents_->height();
     vert_sb_->Update(vh, ch, offset.y());
@@ -919,6 +1015,28 @@
   return contents_viewport_->layer() != nullptr;
 }
 
+bool ScrollView::IsHorizontalScrollEnabled() const {
+  switch (horizontal_scroll_bar_mode_) {
+    case ScrollBarMode::kDisabled:
+      return false;
+    case ScrollBarMode::kHiddenButEnabled:
+      return bool{horiz_sb_};
+    case ScrollBarMode::kEnabled:
+      return horiz_sb_ && horiz_sb_->GetVisible();
+  }
+}
+
+bool ScrollView::IsVerticalScrollEnabled() const {
+  switch (vertical_scroll_bar_mode_) {
+    case ScrollBarMode::kDisabled:
+      return false;
+    case ScrollBarMode::kHiddenButEnabled:
+      return bool{vert_sb_};
+    case ScrollBarMode::kEnabled:
+      return vert_sb_ && vert_sb_->GetVisible();
+  }
+}
+
 void ScrollView::EnableViewportLayer() {
   if (DoesViewportOrScrollViewHaveLayer())
     return;
@@ -1013,20 +1131,21 @@
 void ScrollView::UpdateOverflowIndicatorVisibility(
     const gfx::ScrollOffset& offset) {
   SetControlVisibility(more_content_top_.get(),
-                       !draw_border_ && !header_ && vert_sb_->GetVisible() &&
+                       !draw_border_ && !header_ && IsVerticalScrollEnabled() &&
                            offset.y() > vert_sb_->GetMinPosition() &&
                            draw_overflow_indicator_);
   SetControlVisibility(
       more_content_bottom_.get(),
       !draw_border_ && vert_sb_->GetVisible() && !horiz_sb_->GetVisible() &&
           offset.y() < vert_sb_->GetMaxPosition() && draw_overflow_indicator_);
+
   SetControlVisibility(more_content_left_.get(),
-                       !draw_border_ && horiz_sb_->GetVisible() &&
+                       !draw_border_ && IsHorizontalScrollEnabled() &&
                            offset.x() > horiz_sb_->GetMinPosition() &&
                            draw_overflow_indicator_);
   SetControlVisibility(
       more_content_right_.get(),
-      !draw_border_ && horiz_sb_->GetVisible() && !vert_sb_->GetVisible() &&
+      !draw_border_ && IsHorizontalScrollEnabled() && !vert_sb_->GetVisible() &&
           offset.x() < horiz_sb_->GetMaxPosition() && draw_overflow_indicator_);
 }
 
@@ -1038,7 +1157,9 @@
                       BackgroundThemeColorId)
 ADD_PROPERTY_METADATA(bool, DrawOverflowIndicator)
 ADD_PROPERTY_METADATA(bool, HasFocusIndicator)
-ADD_PROPERTY_METADATA(bool, HideHorizontalScrollBar)
+ADD_PROPERTY_METADATA(ScrollView::ScrollBarMode, HorizontalScrollBarMode)
+ADD_PROPERTY_METADATA(ScrollView::ScrollBarMode, VerticalScrollBarMode)
+ADD_PROPERTY_METADATA(bool, TreatAllScrollEventsAsHorizontal)
 END_METADATA
 
 // VariableRowHeightScrollHelper ----------------------------------------------
diff --git a/ui/views/controls/scroll_view.h b/ui/views/controls/scroll_view.h
index e37d0f6..690b2a4 100644
--- a/ui/views/controls/scroll_view.h
+++ b/ui/views/controls/scroll_view.h
@@ -50,6 +50,19 @@
   // Indicates whether or not scroll view is initialized with layer-scrolling.
   enum class ScrollWithLayers { kDisabled, kEnabled };
 
+  // Controls how a scroll bar appears and functions.
+  enum class ScrollBarMode {
+    // The scrollbar is hidden, and the pane will not respond to e.g. mousewheel
+    // events even if the contents are larger than the viewport.
+    kDisabled,
+    // The scrollbar is hidden whether or not the contents are larger than the
+    // viewport, but the pane will respond to scroll events.
+    kHiddenButEnabled,
+    // The scrollbar will be visible if the contents are larger than the
+    // viewport and the pane will respond to scroll events.
+    kEnabled
+  };
+
   ScrollView();
 
   // Additional constructor for overriding scrolling as defined by
@@ -110,8 +123,19 @@
 
   bool GetUseColorId() const { return !!background_color_id_; }
 
-  bool GetHideHorizontalScrollBar() const { return hide_horizontal_scrollbar_; }
-  void SetHideHorizontalScrollBar(bool visible);
+  ScrollBarMode GetHorizontalScrollBarMode() const {
+    return horizontal_scroll_bar_mode_;
+  }
+  ScrollBarMode GetVerticalScrollBarMode() const {
+    return vertical_scroll_bar_mode_;
+  }
+  bool GetTreatAllScrollEventsAsHorizontal() const {
+    return treat_all_scroll_events_as_horizontal_;
+  }
+  void SetHorizontalScrollBarMode(ScrollBarMode horizontal_scroll_bar_mode);
+  void SetVerticalScrollBarMode(ScrollBarMode vertical_scroll_bar_mode);
+  void SetTreatAllScrollEventsAsHorizontal(
+      bool treat_all_scroll_events_as_horizontal);
 
   bool GetDrawOverflowIndicator() const { return draw_overflow_indicator_; }
   void SetDrawOverflowIndicator(bool draw_overflow_indicator);
@@ -165,6 +189,9 @@
 
   class Viewport;
 
+  bool IsHorizontalScrollEnabled() const;
+  bool IsVerticalScrollEnabled() const;
+
   // Forces |contents_viewport_| to have a Layer (assuming it doesn't already).
   void EnableViewportLayer();
 
@@ -269,9 +296,14 @@
   base::Optional<ui::NativeTheme::ColorId> background_color_id_ =
       ui::NativeTheme::kColorId_DialogBackground;
 
-  // If true, never show the horizontal scrollbar (even if the contents is wider
-  // than the viewport).
-  bool hide_horizontal_scrollbar_ = false;
+  // How to handle the case when the contents overflow the viewport.
+  ScrollBarMode horizontal_scroll_bar_mode_ = ScrollBarMode::kEnabled;
+  ScrollBarMode vertical_scroll_bar_mode_ = ScrollBarMode::kEnabled;
+
+  // Causes vertical scroll events (e.g. scrolling with the mousewheel) as
+  // horizontal events, to make scrolling in horizontal-only scroll situations
+  // easier for the user.
+  bool treat_all_scroll_events_as_horizontal_ = false;
 
   // In Harmony, the indicator is a focus ring. Pre-Harmony, the indicator is a
   // different border painter.
@@ -298,7 +330,9 @@
 VIEW_BUILDER_VIEW_TYPE_PROPERTY(View, Header)
 VIEW_BUILDER_PROPERTY(base::Optional<ui::NativeTheme::ColorId>,
                       BackgroundThemeColorId)
-VIEW_BUILDER_PROPERTY(bool, HideHorizontalScrollBar)
+VIEW_BUILDER_PROPERTY(ScrollView::ScrollBarMode, HorizontalScrollBarMode)
+VIEW_BUILDER_PROPERTY(ScrollView::ScrollBarMode, VerticalScrollBarMode)
+VIEW_BUILDER_PROPERTY(bool, TreatAllScrollEventsAsHorizontal)
 VIEW_BUILDER_PROPERTY(bool, DrawOverflowIndicator)
 VIEW_BUILDER_PROPERTY(base::Optional<SkColor>, BackgroundColor)
 VIEW_BUILDER_VIEW_PROPERTY(ScrollBar, HorizontalScrollBar)
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc
index 0bf6354..3eb0d52 100644
--- a/ui/views/controls/scroll_view_unittest.cc
+++ b/ui/views/controls/scroll_view_unittest.cc
@@ -65,7 +65,9 @@
     return gfx::Point() - gfx::ScrollOffsetToFlooredVector2d(CurrentOffset());
   }
 
-  gfx::ScrollOffset CurrentOffset() { return scroll_view_->CurrentOffset(); }
+  gfx::ScrollOffset CurrentOffset() const {
+    return scroll_view_->CurrentOffset();
+  }
 
   base::RetainingOneShotTimer* GetScrollBarHideTimer(
       ScrollBarOrientation orientation) {
@@ -183,6 +185,21 @@
   DISALLOW_COPY_AND_ASSIGN(VerticalResizingView);
 };
 
+// Same as VerticalResizingView, but horizontal instead.
+class HorizontalResizingView : public View {
+ public:
+  HorizontalResizingView() = default;
+  ~HorizontalResizingView() override = default;
+  void Layout() override {
+    int height = 10000;
+    int width = parent()->width();
+    SetBounds(x(), y(), width, height);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HorizontalResizingView);
+};
+
 class TestScrollBarThumb : public BaseScrollBarThumb {
  public:
   using BaseScrollBarThumb::BaseScrollBarThumb;
@@ -469,6 +486,53 @@
   EXPECT_TRUE(scroll_view_->horizontal_scroll_bar()->GetVisible());
 }
 
+// Same as above, but setting horizontal scroll bar to hidden.
+TEST_F(ScrollViewTest, HorizontalScrollbarDoesNotAppearIfHidden) {
+  const gfx::Rect default_outer_bounds(0, 0, 100, 100);
+  scroll_view_->SetHorizontalScrollBarMode(
+      ScrollView::ScrollBarMode::kHiddenButEnabled);
+  scroll_view_->SetContents(std::make_unique<VerticalResizingView>());
+  scroll_view_->SetBoundsRect(default_outer_bounds);
+  scroll_view_->Layout();
+  EXPECT_FALSE(scroll_view_->vertical_scroll_bar()->GetVisible());
+  EXPECT_FALSE(scroll_view_->horizontal_scroll_bar()->GetVisible());
+}
+
+// Same as above, but setting vertical scrollbar instead.
+TEST_F(ScrollViewTest, VerticalScrollbarDoesNotAppearIfHidden) {
+  const gfx::Rect default_outer_bounds(0, 0, 100, 100);
+  scroll_view_->SetVerticalScrollBarMode(
+      ScrollView::ScrollBarMode::kHiddenButEnabled);
+  scroll_view_->SetContents(std::make_unique<HorizontalResizingView>());
+  scroll_view_->SetBoundsRect(default_outer_bounds);
+  scroll_view_->Layout();
+  EXPECT_FALSE(scroll_view_->vertical_scroll_bar()->GetVisible());
+  EXPECT_FALSE(scroll_view_->horizontal_scroll_bar()->GetVisible());
+}
+
+// Same as above, but setting horizontal scroll bar to disabled.
+TEST_F(ScrollViewTest, HorizontalScrollbarDoesNotAppearIfDisabled) {
+  const gfx::Rect default_outer_bounds(0, 0, 100, 100);
+  scroll_view_->SetHorizontalScrollBarMode(
+      ScrollView::ScrollBarMode::kDisabled);
+  scroll_view_->SetContents(std::make_unique<VerticalResizingView>());
+  scroll_view_->SetBoundsRect(default_outer_bounds);
+  scroll_view_->Layout();
+  EXPECT_FALSE(scroll_view_->vertical_scroll_bar()->GetVisible());
+  EXPECT_FALSE(scroll_view_->horizontal_scroll_bar()->GetVisible());
+}
+
+// Same as above, but setting vertical scrollbar instead.
+TEST_F(ScrollViewTest, VerticallScrollbarDoesNotAppearIfDisabled) {
+  const gfx::Rect default_outer_bounds(0, 0, 100, 100);
+  scroll_view_->SetVerticalScrollBarMode(ScrollView::ScrollBarMode::kDisabled);
+  scroll_view_->SetContents(std::make_unique<HorizontalResizingView>());
+  scroll_view_->SetBoundsRect(default_outer_bounds);
+  scroll_view_->Layout();
+  EXPECT_FALSE(scroll_view_->vertical_scroll_bar()->GetVisible());
+  EXPECT_FALSE(scroll_view_->horizontal_scroll_bar()->GetVisible());
+}
+
 // Verifies the scrollbars are added as necessary.
 // If on Mac, test the non-overlay scrollbars.
 TEST_F(ScrollViewTest, ScrollBars) {
@@ -742,6 +806,46 @@
   EXPECT_GT(scroll_bar->GetPosition(), 0);
 }
 
+// Test that calling ScrollToPosition() also updates the position of the
+// child view even when the horizontal scrollbar is hidden.
+TEST_F(ScrollViewTest, ScrollToPositionUpdatesWithHiddenHorizontalScrollBar) {
+  scroll_view_->SetHorizontalScrollBarMode(
+      ScrollView::ScrollBarMode::kHiddenButEnabled);
+  ScrollViewTestApi test_api(scroll_view_.get());
+  View* contents = InstallContents();
+
+  contents->SetBounds(0, 0, 400, 50);
+  scroll_view_->Layout();
+  auto* scroll_bar = test_api.GetScrollBar(HORIZONTAL);
+  ASSERT_TRUE(scroll_bar);
+  EXPECT_FALSE(scroll_bar->GetVisible());
+  // We can't rely on the scrollbar, which may not be updated as it's not
+  // visible, but we can check the scroll offset itself.
+  EXPECT_EQ(0, test_api.CurrentOffset().x());
+  scroll_view_->ScrollToPosition(scroll_bar, 20);
+  EXPECT_GT(test_api.CurrentOffset().x(), 0);
+}
+
+// Test that calling ScrollToPosition() also updates the position of the
+// child view even when the horizontal scrollbar is hidden.
+TEST_F(ScrollViewTest, ScrollToPositionUpdatesWithHiddenVerticalScrollBar) {
+  scroll_view_->SetVerticalScrollBarMode(
+      ScrollView::ScrollBarMode::kHiddenButEnabled);
+  ScrollViewTestApi test_api(scroll_view_.get());
+  View* contents = InstallContents();
+
+  contents->SetBounds(0, 0, 50, 400);
+  scroll_view_->Layout();
+  auto* scroll_bar = test_api.GetScrollBar(VERTICAL);
+  ASSERT_TRUE(scroll_bar);
+  EXPECT_FALSE(scroll_bar->GetVisible());
+  // We can't rely on the scrollbar, which may not be updated as it's not
+  // visible, but we can check the scroll offset itself.
+  EXPECT_EQ(0, test_api.CurrentOffset().y());
+  scroll_view_->ScrollToPosition(scroll_bar, 20);
+  EXPECT_GT(test_api.CurrentOffset().y(), 0);
+}
+
 // Verifies ScrollRectToVisible() on the child works.
 TEST_F(ScrollViewTest, ScrollRectToVisible) {
   ScrollViewTestApi test_api(scroll_view_.get());
@@ -769,6 +873,66 @@
   EXPECT_EQ(415 - viewport_height, test_api.CurrentOffset().y());
 }
 
+// Verifies ScrollRectToVisible() scrolls the view horizontally even if the
+// horizontal scrollbar is hidden (but not disabled).
+TEST_F(ScrollViewTest, ScrollRectToVisibleWithHiddenHorizontalScrollbar) {
+  scroll_view_->SetHorizontalScrollBarMode(
+      ScrollView::ScrollBarMode::kHiddenButEnabled);
+  ScrollViewTestApi test_api(scroll_view_.get());
+  auto contents = std::make_unique<CustomView>();
+  contents->SetPreferredSize(gfx::Size(500, 1000));
+  auto* contents_ptr = scroll_view_->SetContents(std::move(contents));
+
+  scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+  scroll_view_->Layout();
+  EXPECT_EQ("0,0", test_api.IntegralViewOffset().ToString());
+
+  // Scroll to x=305 width=10, this should make the x position of the content
+  // at (305 + 10) - viewport_width (scroll region right aligned).
+  contents_ptr->ScrollRectToVisible(gfx::Rect(305, 0, 10, 10));
+  const int viewport_width = test_api.contents_viewport()->width();
+
+  // Expect there to be a vertical scrollbar, making the viewport shorter.
+  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutWidth(), viewport_width);
+
+  gfx::ScrollOffset offset = test_api.CurrentOffset();
+  EXPECT_EQ(315 - viewport_width, offset.x());
+
+  // Scroll to the current x-location and 10x10; should do nothing.
+  contents_ptr->ScrollRectToVisible(gfx::Rect(offset.x(), 0, 10, 10));
+  EXPECT_EQ(315 - viewport_width, test_api.CurrentOffset().x());
+}
+
+// Verifies ScrollRectToVisible() scrolls the view horizontally even if the
+// horizontal scrollbar is hidden (but not disabled).
+TEST_F(ScrollViewTest, ScrollRectToVisibleWithHiddenVerticalScrollbar) {
+  scroll_view_->SetVerticalScrollBarMode(
+      ScrollView::ScrollBarMode::kHiddenButEnabled);
+  ScrollViewTestApi test_api(scroll_view_.get());
+  auto contents = std::make_unique<CustomView>();
+  contents->SetPreferredSize(gfx::Size(1000, 500));
+  auto* contents_ptr = scroll_view_->SetContents(std::move(contents));
+
+  scroll_view_->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+  scroll_view_->Layout();
+  EXPECT_EQ("0,0", test_api.IntegralViewOffset().ToString());
+
+  // Scroll to y=305 height=10, this should make the y position of the content
+  // at (305 + 10) - viewport_height (scroll region bottom aligned).
+  contents_ptr->ScrollRectToVisible(gfx::Rect(0, 305, 10, 10));
+  const int viewport_height = test_api.contents_viewport()->height();
+
+  // Expect there to be a vertical scrollbar, making the viewport shorter.
+  EXPECT_EQ(100 - scroll_view_->GetScrollBarLayoutHeight(), viewport_height);
+
+  gfx::ScrollOffset offset = test_api.CurrentOffset();
+  EXPECT_EQ(315 - viewport_height, offset.y());
+
+  // Scroll to the current x-location and 10x10; should do nothing.
+  contents_ptr->ScrollRectToVisible(gfx::Rect(0, offset.y(), 10, 10));
+  EXPECT_EQ(315 - viewport_height, test_api.CurrentOffset().y());
+}
+
 // Verifies that child scrolls into view when it's focused.
 TEST_F(ScrollViewTest, ScrollChildToVisibleOnFocus) {
   ScrollViewTestApi test_api(scroll_view_.get());
@@ -1576,8 +1740,34 @@
   EXPECT_FALSE(test_api.more_content_right()->GetVisible());
 }
 
-// Ensure ScrollView::Layout succeeds if a hidden scrollbar's overlap style
+// Ensure ScrollView::Layout succeeds if a disabled scrollbar's overlap style
 // does not match the other scrollbar.
+TEST_F(ScrollViewTest, IgnoreOverlapWithDisabledHorizontalScroll) {
+  ScrollViewTestApi test_api(scroll_view_.get());
+
+  constexpr int kThickness = 1;
+  // Assume horizontal scroll bar is the default and is overlapping.
+  scroll_view_->SetHorizontalScrollBar(std::make_unique<TestScrollBar>(
+      /* horizontal */ true, /* overlaps_content */ true, kThickness));
+  // Assume vertical scroll bar is custom and it we want it to not overlap.
+  scroll_view_->SetVerticalScrollBar(std::make_unique<TestScrollBar>(
+      /* horizontal */ false, /* overlaps_content */ false, kThickness));
+
+  // Also, let's turn off horizontal scroll bar.
+  scroll_view_->SetHorizontalScrollBarMode(
+      ScrollView::ScrollBarMode::kDisabled);
+
+  View* contents = InstallContents();
+  contents->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
+  scroll_view_->Layout();
+
+  gfx::Size expected_size = scroll_view_->size();
+  expected_size.Enlarge(-kThickness, 0);
+  EXPECT_EQ(expected_size, test_api.contents_viewport()->size());
+}
+
+// Ensure ScrollView::Layout succeeds if a hidden but enabled scrollbar's
+// overlap style does not match the other scrollbar.
 TEST_F(ScrollViewTest, IgnoreOverlapWithHiddenHorizontalScroll) {
   ScrollViewTestApi test_api(scroll_view_.get());
 
@@ -1590,7 +1780,8 @@
       /* horizontal */ false, /* overlaps_content */ false, kThickness));
 
   // Also, let's turn off horizontal scroll bar.
-  scroll_view_->SetHideHorizontalScrollBar(true);
+  scroll_view_->SetHorizontalScrollBarMode(
+      ScrollView::ScrollBarMode::kHiddenButEnabled);
 
   View* contents = InstallContents();
   contents->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
@@ -1601,6 +1792,57 @@
   EXPECT_EQ(expected_size, test_api.contents_viewport()->size());
 }
 
+// Ensure ScrollView::Layout succeeds if a disabled scrollbar's overlap style
+// does not match the other scrollbar.
+TEST_F(ScrollViewTest, IgnoreOverlapWithDisabledVerticalScroll) {
+  ScrollViewTestApi test_api(scroll_view_.get());
+
+  constexpr int kThickness = 1;
+  // Assume horizontal scroll bar is custom and it we want it to not overlap.
+  scroll_view_->SetHorizontalScrollBar(std::make_unique<TestScrollBar>(
+      /* horizontal */ true, /* overlaps_content */ false, kThickness));
+  // Assume vertical scroll bar is the default and is overlapping.
+  scroll_view_->SetVerticalScrollBar(std::make_unique<TestScrollBar>(
+      /* horizontal */ false, /* overlaps_content */ true, kThickness));
+
+  // Also, let's turn off horizontal scroll bar.
+  scroll_view_->SetVerticalScrollBarMode(ScrollView::ScrollBarMode::kDisabled);
+
+  View* contents = InstallContents();
+  contents->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
+  scroll_view_->Layout();
+
+  gfx::Size expected_size = scroll_view_->size();
+  expected_size.Enlarge(0, -kThickness);
+  EXPECT_EQ(expected_size, test_api.contents_viewport()->size());
+}
+
+// Ensure ScrollView::Layout succeeds if a hidden but enabled scrollbar's
+// overlap style does not match the other scrollbar.
+TEST_F(ScrollViewTest, IgnoreOverlapWithHiddenVerticalScroll) {
+  ScrollViewTestApi test_api(scroll_view_.get());
+
+  constexpr int kThickness = 1;
+  // Assume horizontal scroll bar is custom and it we want it to not overlap.
+  scroll_view_->SetHorizontalScrollBar(std::make_unique<TestScrollBar>(
+      /* horizontal */ true, /* overlaps_content */ false, kThickness));
+  // Assume vertical scroll bar is the default and is overlapping.
+  scroll_view_->SetVerticalScrollBar(std::make_unique<TestScrollBar>(
+      /* horizontal */ false, /* overlaps_content */ true, kThickness));
+
+  // Also, let's turn off horizontal scroll bar.
+  scroll_view_->SetVerticalScrollBarMode(
+      ScrollView::ScrollBarMode::kHiddenButEnabled);
+
+  View* contents = InstallContents();
+  contents->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
+  scroll_view_->Layout();
+
+  gfx::Size expected_size = scroll_view_->size();
+  expected_size.Enlarge(0, -kThickness);
+  EXPECT_EQ(expected_size, test_api.contents_viewport()->size());
+}
+
 // Test scrolling behavior when clicking on the scroll track.
 TEST_F(WidgetScrollViewTest, ScrollTrackScrolling) {
   // Set up with a vertical scroller.
@@ -1847,6 +2089,38 @@
   EXPECT_EQ(gfx::ScrollOffset(offset.x(), offset.y()), impl_offset);
 }
 
+namespace {
+
+// Applies |scroll_event| to |scroll_view| and verifies that the event is
+// applied correctly whether or not compositor scrolling is enabled.
+static void ApplyScrollEvent(const ScrollViewTestApi& test_api,
+                             ScrollView* scroll_view,
+                             ui::ScrollEvent& scroll_event) {
+  EXPECT_FALSE(scroll_event.handled());
+  EXPECT_FALSE(scroll_event.stopped_propagation());
+  scroll_view->OnScrollEvent(&scroll_event);
+
+  // Check to see if the scroll event is handled by the scroll view.
+  if (base::FeatureList::IsEnabled(::features::kUiCompositorScrollWithLayers)) {
+    // If UiCompositorScrollWithLayers is enabled, the event is set handled
+    // and its propagation is stopped.
+    EXPECT_TRUE(scroll_event.handled());
+    EXPECT_TRUE(scroll_event.stopped_propagation());
+  } else {
+    // If UiCompositorScrollWithLayers is disabled, the event isn't handled.
+    // This informs Widget::OnScrollEvent() to convert to a MouseWheel event
+    // and dispatch again. Simulate that.
+    EXPECT_FALSE(scroll_event.handled());
+    EXPECT_FALSE(scroll_event.stopped_propagation());
+    EXPECT_EQ(gfx::ScrollOffset(), test_api.CurrentOffset());
+
+    ui::MouseWheelEvent wheel(scroll_event);
+    scroll_view->OnMouseEvent(&wheel);
+  }
+}
+
+}  // namespace
+
 // Tests to see the scroll events are handled correctly in composited and
 // non-composited scrolling.
 TEST_F(WidgetScrollViewTest, CompositedScrollEvents) {
@@ -1858,32 +2132,80 @@
   // Create a fake scroll event and send it to the scroll view.
   ui::ScrollEvent scroll(ui::ET_SCROLL, gfx::Point(), base::TimeTicks::Now(), 0,
                          0, -10, 0, -10, 3);
-  EXPECT_FALSE(scroll.handled());
-  EXPECT_FALSE(scroll.stopped_propagation());
-  scroll_view->OnScrollEvent(&scroll);
-
-  // Check to see if the scroll event is handled by the scroll view.
-  if (base::FeatureList::IsEnabled(::features::kUiCompositorScrollWithLayers)) {
-    // If UiCompositorScrollWithLayers is enabled, the event is set handled
-    // and its propagation is stopped.
-    EXPECT_TRUE(scroll.handled());
-    EXPECT_TRUE(scroll.stopped_propagation());
-  } else {
-    // If UiCompositorScrollWithLayers is disabled, the event isn't handled.
-    // This informs Widget::OnScrollEvent() to convert to a MouseWheel event
-    // and dispatch again. Simulate that.
-    EXPECT_FALSE(scroll.handled());
-    EXPECT_FALSE(scroll.stopped_propagation());
-    EXPECT_EQ(gfx::ScrollOffset(), test_api.CurrentOffset());
-
-    ui::MouseWheelEvent wheel(scroll);
-    scroll_view->OnMouseEvent(&wheel);
-  }
+  ApplyScrollEvent(test_api, scroll_view, scroll);
 
   // Check if the scroll view has been offset.
   EXPECT_EQ(gfx::ScrollOffset(0, 10), test_api.CurrentOffset());
 }
 
+// Tests to see that transposed (treat-as-horizontal) scroll events are handled
+// correctly in composited and non-composited scrolling.
+TEST_F(WidgetScrollViewTest, CompositedTransposedScrollEvents) {
+  // Set up with a vertical scroll bar.
+  ScrollView* scroll_view =
+      AddScrollViewWithContentSize(gfx::Size(kDefaultHeight * 5, 10));
+  scroll_view->SetTreatAllScrollEventsAsHorizontal(true);
+  ScrollViewTestApi test_api(scroll_view);
+
+  // Create a fake scroll event and send it to the scroll view.
+  // Note that this is still a VERTICAL scroll event, but we'll be looking for
+  // HORIZONTAL motion later because we're transposed.
+  ui::ScrollEvent scroll(ui::ET_SCROLL, gfx::Point(), base::TimeTicks::Now(), 0,
+                         0, -10, 0, -10, 3);
+  ApplyScrollEvent(test_api, scroll_view, scroll);
+
+  // Check if the scroll view has been offset.
+  EXPECT_EQ(gfx::ScrollOffset(10, 0), test_api.CurrentOffset());
+}
+
+// Tests to see that transposed (treat-as-horizontal) scroll events are handled
+// correctly in composited and non-composited scrolling when the scroll offset
+// is somewhat ambiguous. This is the case where the horizontal component is
+// larger than the vertical.
+TEST_F(WidgetScrollViewTest,
+       CompositedTransposedScrollEventsHorizontalComponentIsLarger) {
+  // Set up with a vertical scroll bar.
+  ScrollView* scroll_view =
+      AddScrollViewWithContentSize(gfx::Size(kDefaultHeight * 5, 10));
+  scroll_view->SetTreatAllScrollEventsAsHorizontal(true);
+  ScrollViewTestApi test_api(scroll_view);
+
+  // Create a fake scroll event and send it to the scroll view.
+  // This will be a horizontal scroll event but there will be a conflicting
+  // vertical element. We should still scroll horizontally, since the horizontal
+  // component is greater.
+  ui::ScrollEvent scroll(ui::ET_SCROLL, gfx::Point(), base::TimeTicks::Now(), 0,
+                         -10, 7, -10, 7, 3);
+  ApplyScrollEvent(test_api, scroll_view, scroll);
+
+  // Check if the scroll view has been offset.
+  EXPECT_EQ(gfx::ScrollOffset(10, 0), test_api.CurrentOffset());
+}
+
+// Tests to see that transposed (treat-as-horizontal) scroll events are handled
+// correctly in composited and non-composited scrolling when the scroll offset
+// is somewhat ambiguous. This is the case where the vertical component is
+// larger than the horizontal.
+TEST_F(WidgetScrollViewTest,
+       CompositedTransposedScrollEventsVerticalComponentIsLarger) {
+  // Set up with a vertical scroll bar.
+  ScrollView* scroll_view =
+      AddScrollViewWithContentSize(gfx::Size(kDefaultHeight * 5, 10));
+  scroll_view->SetTreatAllScrollEventsAsHorizontal(true);
+  ScrollViewTestApi test_api(scroll_view);
+
+  // Create a fake scroll event and send it to the scroll view.
+  // This will be a vertical scroll event but there will be a conflicting
+  // horizontal element. We should still scroll horizontally, since the vertical
+  // component is greater.
+  ui::ScrollEvent scroll(ui::ET_SCROLL, gfx::Point(), base::TimeTicks::Now(), 0,
+                         7, -10, 7, -10, 3);
+  ApplyScrollEvent(test_api, scroll_view, scroll);
+
+  // Check if the scroll view has been offset.
+  EXPECT_EQ(gfx::ScrollOffset(10, 0), test_api.CurrentOffset());
+}
+
 INSTANTIATE_TEST_SUITE_P(All,
                          WidgetScrollViewTestRTLAndLayers,
                          ::testing::Values(UiConfig::kLtr,
diff --git a/ui/views/metadata/type_conversion.cc b/ui/views/metadata/type_conversion.cc
index 579052a9..ac0cf76 100644
--- a/ui/views/metadata/type_conversion.cc
+++ b/ui/views/metadata/type_conversion.cc
@@ -14,6 +14,7 @@
 #include "ui/base/ime/text_input_type.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/native_theme/native_theme.h"
+#include "ui/views/controls/scroll_view.h"
 
 namespace views {
 namespace metadata {
@@ -354,6 +355,14 @@
                        {ui::MenuSeparatorType::PADDED_SEPARATOR,
                         base::ASCIIToUTF16("PADDED_SEPARATOR")})
 
+DEFINE_ENUM_CONVERTERS(views::ScrollView::ScrollBarMode,
+                       {views::ScrollView::ScrollBarMode::kDisabled,
+                        base::ASCIIToUTF16("kDisabled")},
+                       {views::ScrollView::ScrollBarMode::kHiddenButEnabled,
+                        base::ASCIIToUTF16("kHiddenButEnabled")},
+                       {views::ScrollView::ScrollBarMode::kEnabled,
+                        base::ASCIIToUTF16("kEnabled")})
+
 #define OP(enum_name) \
   { ui::NativeTheme::enum_name, base::ASCIIToUTF16(#enum_name) }
 DEFINE_ENUM_CONVERTERS(ui::NativeTheme::ColorId, NATIVE_THEME_COLOR_IDS)
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java
index efb3a41..0c0e5cf 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java
@@ -11,8 +11,10 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.weblayer.NewTabCallback;
 import org.chromium.weblayer.Tab;
 import org.chromium.weblayer.shell.InstrumentationActivity;
 
@@ -51,6 +53,31 @@
 
     @Test
     @SmallTest
+    public void testDestroyTabInOnNewTab() throws Throwable {
+        String url = mActivityTestRule.getTestDataURL("new_browser.html");
+        mActivity = mActivityTestRule.launchShellWithUrl(url);
+        Assert.assertNotNull(mActivity);
+        CallbackHelper callbackHelper = new CallbackHelper();
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            Tab tab = mActivity.getBrowser().getActiveTab();
+            tab.setNewTabCallback(new NewTabCallback() {
+                @Override
+                public void onNewTab(Tab newTab, int mode) {
+                    newTab.getBrowser().destroyTab(newTab);
+                    Assert.assertTrue(newTab.isDestroyed());
+                    Assert.assertEquals(1, mActivity.getBrowser().getTabs().size());
+                    Assert.assertFalse(mActivity.getBrowser().getActiveTab().isDestroyed());
+                    callbackHelper.notifyCalled();
+                }
+            });
+        });
+
+        EventUtils.simulateTouchCenterOfView(mActivity.getWindow().getDecorView());
+        callbackHelper.waitForFirst();
+    }
+
+    @Test
+    @SmallTest
     public void testNewTabHasFocus() {
         String url = mActivityTestRule.getTestDataURL("new_browser.html");
         mActivity = mActivityTestRule.launchShellWithUrl(url);
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java
index 3ef535d..a76b13c3 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java
@@ -15,5 +15,5 @@
      *
      * @see WebLayer#isAvailable()
      */
-    int MAX_SKEW = 3;
+    int MAX_SKEW = 4;
 }
diff --git a/weblayer/browser/new_tab_delegate_browsertest.cc b/weblayer/browser/new_tab_delegate_browsertest.cc
new file mode 100644
index 0000000..5c13568
--- /dev/null
+++ b/weblayer/browser/new_tab_delegate_browsertest.cc
@@ -0,0 +1,58 @@
+// Copyright 2020 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 "weblayer/public/new_tab_delegate.h"
+
+#include "base/strings/stringprintf.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "weblayer/browser/tab_impl.h"
+#include "weblayer/public/browser.h"
+#include "weblayer/public/new_tab_delegate.h"
+#include "weblayer/public/tab.h"
+#include "weblayer/shell/browser/shell.h"
+#include "weblayer/test/weblayer_browser_test.h"
+#include "weblayer/test/weblayer_browser_test_utils.h"
+
+namespace weblayer {
+
+namespace {
+
+class DestroyingNewTabDelegate : public NewTabDelegate {
+ public:
+  void WaitForOnNewTab() { run_loop_.Run(); }
+
+  bool was_on_new_tab_called() const { return was_on_new_tab_called_; }
+
+  // NewTabDelegate:
+  void OnNewTab(Tab* new_tab, NewTabType type) override {
+    was_on_new_tab_called_ = true;
+    new_tab->GetBrowser()->DestroyTab(new_tab);
+    run_loop_.Quit();
+  }
+
+ private:
+  base::RunLoop run_loop_;
+  bool was_on_new_tab_called_ = false;
+};
+
+}  // namespace
+
+using NewTabDelegateTest = WebLayerBrowserTest;
+
+IN_PROC_BROWSER_TEST_F(NewTabDelegateTest, DestroyTabOnNewTab) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  NavigateAndWaitForCompletion(embedded_test_server()->GetURL("/echo"),
+                               shell()->tab());
+  DestroyingNewTabDelegate new_tab_delegate;
+  shell()->tab()->SetNewTabDelegate(&new_tab_delegate);
+  GURL popup_url = embedded_test_server()->GetURL("/echo?popup");
+  ExecuteScriptWithUserGesture(
+      shell()->tab(),
+      base::StringPrintf("window.open('%s')", popup_url.spec().c_str()));
+  new_tab_delegate.WaitForOnNewTab();
+  EXPECT_TRUE(new_tab_delegate.was_on_new_tab_called());
+  EXPECT_EQ(1u, shell()->tab()->GetBrowser()->GetTabs().size());
+}
+
+}  // namespace weblayer
diff --git a/weblayer/browser/tab_impl.cc b/weblayer/browser/tab_impl.cc
index 56cc817..bbb893b 100644
--- a/weblayer/browser/tab_impl.cc
+++ b/weblayer/browser/tab_impl.cc
@@ -401,6 +401,10 @@
   data_observers_.RemoveObserver(observer);
 }
 
+Browser* TabImpl::GetBrowser() {
+  return browser_;
+}
+
 void TabImpl::SetErrorPageDelegate(ErrorPageDelegate* delegate) {
   error_page_delegate_ = delegate;
 }
diff --git a/weblayer/browser/tab_impl.h b/weblayer/browser/tab_impl.h
index 14cb683b..e21928bc9 100644
--- a/weblayer/browser/tab_impl.h
+++ b/weblayer/browser/tab_impl.h
@@ -214,6 +214,7 @@
   }
 
   // Tab:
+  Browser* GetBrowser() override;
   void SetErrorPageDelegate(ErrorPageDelegate* delegate) override;
   void SetFullscreenDelegate(FullscreenDelegate* delegate) override;
   void SetNewTabDelegate(NewTabDelegate* delegate) override;
diff --git a/weblayer/public/tab.h b/weblayer/public/tab.h
index 6d26eb6..2485fef0 100644
--- a/weblayer/public/tab.h
+++ b/weblayer/public/tab.h
@@ -25,6 +25,7 @@
 #endif
 
 namespace weblayer {
+class Browser;
 class ErrorPageDelegate;
 class FaviconFetcher;
 class FaviconFetcherDelegate;
@@ -40,6 +41,9 @@
  public:
   virtual ~Tab() = default;
 
+  // Returns the Browser that owns this.
+  virtual Browser* GetBrowser() = 0;
+
   // Sets the ErrorPageDelegate. If none is set, a default action will be taken
   // for any given interaction with an error page.
   virtual void SetErrorPageDelegate(ErrorPageDelegate* delegate) = 0;
diff --git a/weblayer/test/BUILD.gn b/weblayer/test/BUILD.gn
index 60f7b96..34c37e65 100644
--- a/weblayer/test/BUILD.gn
+++ b/weblayer/test/BUILD.gn
@@ -142,6 +142,7 @@
     "../browser/js_communication/web_message_browsertest.cc",
     "../browser/navigation_browsertest.cc",
     "../browser/navigation_error_navigation_throttle_browsertest.cc",
+    "../browser/new_tab_delegate_browsertest.cc",
     "../browser/no_state_prefetch/no_state_prefetch_browsertest.cc",
     "../browser/page_load_metrics_browsertest.cc",
     "../browser/popup_blocker_browsertest.cc",