diff --git a/DEPS b/DEPS
index 9f01522d8..b179dfb7 100644
--- a/DEPS
+++ b/DEPS
@@ -145,11 +145,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': '6e86c1b05eeedc3b6be0e98001b7b5d6bab71b74',
+  'skia_revision': '6980c4e0aef8ab9546e25d8160c05a716f1c3ce3',
   # 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': '781babd0c9ef5d62a23b0a54ed64586c3236db6c',
+  'v8_revision': 'b38939a8ea53d5e0240cededcad4f08d96deab68',
   # 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.
@@ -157,15 +157,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '8b2dfa0fc657d64903849421f7aa0885f39a0eb0',
+  'angle_revision': '1ebe6014389e022dfb1d89ae47cb8b4c7593a733',
   # 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': 'fa0175c0988dd542f008257232207a8b87ad6c63',
+  'swiftshader_revision': '324bdfed069236dad85a49e1baace6b2fa52bc8c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '12bc1c4dae87f210dc1b379d658a7f329c74d469',
+  'pdfium_revision': '7264bc930f9bd39168a2e7b2c15b2e2c0d54ab47',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -280,7 +280,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '35ad5221fb556c7aa80961d42537e4d9c825bf49',
+  'dawn_revision': 'd08611b7a8dca46cd82046575e202c4b713140f6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -809,7 +809,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '019109290b69be57b47b2e0cde3db2499d16edf5',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '67d90245bad48cb92cb8b884dfd6c15d7fac472b',
       'condition': 'checkout_linux',
   },
 
@@ -903,7 +903,7 @@
   },
 
   'src/third_party/glslang/src':
-    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'f04f1f93a70f4608ffa9903b20bfb95f20a063f5',
+    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'eea340047eca2119516d79ad059ce33632ea366e',
 
   'src/third_party/google_toolbox_for_mac/src': {
       'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'),
@@ -1207,7 +1207,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '6ce7935230e8bcd8e4da9f8ffd68df2e6fc581c0',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '334a2b1fa8b9c2210d6b5dc307a580e68c2fc76b',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1277,7 +1277,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'rLiAA9o9m-A_sa-HdXeWBwW3OiySYlJz5KqwhP83wk4C',
+              'version': '1ceH-5pheRe3OUeFz4TzVc2xcu6sm45yeFQBTT4rd6IC',
           },
       ],
       'condition': 'checkout_android',
@@ -1375,7 +1375,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '425d6aaa4ce256b263e307322195bd113c55d59f',
+    Var('webrtc_git') + '/src.git' + '@' + 'e08ca23ec9fe146aaeee316274e791ee11567369',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1416,7 +1416,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b63730a701a417073edd4645d0330bf1c31cd5df',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b9c76515a890b997165d29f603b1e43f1283527e',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 0363d74..76da440 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1912,7 +1912,8 @@
                       'yuzo+watch@chromium.org'],
     'add_to_homescreen': ['dominickn+watch-a2hs@chromium.org',
                           'hanxi+watch@chromium.org',
-                          'pkotwicz+watch@chromium.org'],
+                          'pkotwicz+watch@chromium.org',
+                          'webapks-watchlist@chromium.org'],
     'android_crash_reporting': ['asvitkine+watch@chromium.org',
                                 'wnwen+watch@chromium.org'],
     'android_crazy_linker': ['johnmaguire+watch@google.com'],
@@ -2510,7 +2511,8 @@
     'runtime_enabled_features': ['jmedley+watch@chromium.org'],
     'safe_browsing': ['drubery@chromium.org',
                       'timvolodine@chromium.org',
-                      'vakh+watch@chromium.org'],
+                      'vakh+watch@chromium.org',
+                      'xinghuilu+watch@chromium.org'],
     'sampling_profiler': ['wittman+watch@chromium.org'],
     'screen_orientation': ['mlamouri+watch-screen-orientation@chromium.org'],
     'security': ['security-watchlist@chromium.org'],
@@ -2595,12 +2597,14 @@
                'jordynass+watch-tether@chromium.org',
                'khorimoto+watch-tether@chromium.org',
                'nohle+watch-tether@chromium.org'],
-    'textinput': ['nona+watch@chromium.org',
+    'textinput': ['keithlee+watch@chromium.org',
+                  'nona+watch@chromium.org',
                   'shuchen+watch@chromium.org',
                   'suzhe@chromium.org',
                   'yhanada+watch@chromium.org',
                   'yusukes+watch@chromium.org'],
-    'textinput_chromeos': ['nona+watch@chromium.org',
+    'textinput_chromeos': ['keithlee+watch@chromium.org',
+                           'nona+watch@chromium.org',
                            'shuchen+watch@chromium.org',
                            'yhanada+watch@chromium.org',
                            'yusukes+watch@chromium.org'],
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 7c14693..54e874e 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -957,7 +957,7 @@
 
 bool AwContentBrowserClient::HandleExternalProtocol(
     const GURL& url,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    content::WebContents::Getter web_contents_getter,
     int child_id,
     content::NavigationUIData* navigation_data,
     bool is_main_frame,
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index 80fdffd1..fba268f 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -203,7 +203,7 @@
       LoginAuthRequiredCallback auth_required_callback) override;
   bool HandleExternalProtocol(
       const GURL& url,
-      content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+      content::WebContents::Getter web_contents_getter,
       int child_id,
       content::NavigationUIData* navigation_data,
       bool is_main_frame,
diff --git a/android_webview/browser/aw_contents_client_bridge.cc b/android_webview/browser/aw_contents_client_bridge.cc
index 1fbcb210..789d25e 100644
--- a/android_webview/browser/aw_contents_client_bridge.cc
+++ b/android_webview/browser/aw_contents_client_bridge.cc
@@ -91,8 +91,7 @@
 
 // static
 AwContentsClientBridge* AwContentsClientBridge::FromWebContentsGetter(
-    const content::ResourceRequestInfo::WebContentsGetter&
-        web_contents_getter) {
+    const content::WebContents::Getter& web_contents_getter) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   WebContents* web_contents = web_contents_getter.Run();
   return UserData::GetContents(web_contents);
diff --git a/android_webview/browser/aw_contents_client_bridge.h b/android_webview/browser/aw_contents_client_bridge.h
index 50c4a39..3eaf642 100644
--- a/android_webview/browser/aw_contents_client_bridge.h
+++ b/android_webview/browser/aw_contents_client_bridge.h
@@ -17,7 +17,7 @@
 #include "components/security_interstitials/content/unsafe_resource.h"
 #include "content/public/browser/certificate_request_result_type.h"
 #include "content/public/browser/javascript_dialog_manager.h"
-#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
 #include "net/http/http_response_headers.h"
 
 class GURL;
@@ -69,8 +69,7 @@
   static AwContentsClientBridge* FromWebContents(
       content::WebContents* web_contents);
   static AwContentsClientBridge* FromWebContentsGetter(
-      const content::ResourceRequestInfo::WebContentsGetter&
-          web_contents_getter);
+      const content::WebContents::Getter& web_contents_getter);
   static AwContentsClientBridge* FromID(int render_process_id,
                                         int render_frame_id);
   AwContentsClientBridge(JNIEnv* env,
diff --git a/android_webview/browser/aw_contents_io_thread_client.cc b/android_webview/browser/aw_contents_io_thread_client.cc
index 7a472d02..5c118ba2 100644
--- a/android_webview/browser/aw_contents_io_thread_client.cc
+++ b/android_webview/browser/aw_contents_io_thread_client.cc
@@ -28,7 +28,6 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "net/base/data_url.h"
diff --git a/android_webview/browser/aw_feature_list.cc b/android_webview/browser/aw_feature_list.cc
index d5001eec..928f0e64 100644
--- a/android_webview/browser/aw_feature_list.cc
+++ b/android_webview/browser/aw_feature_list.cc
@@ -51,6 +51,19 @@
 const base::Feature kWebViewConnectionlessSafeBrowsing{
     "WebViewConnectionlessSafeBrowsing", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Sniff the content stream to guess the MIME type when the application doesn't
+// tell us the MIME type explicitly.
+//
+// This only applies:
+// * when NetworkService is enabled (if disabled, the legacy net path sniffs
+//   content anyway, as an implementation detail).
+// * to app-provided content (shouldInterceptRequest,
+//   file:///android_{asset,res} URLs, content:// URLs), rather than content
+//   from the net stack (we may sniff content from the net stack anyway,
+//   depending on headers, but that's a NetworkService implementation detail).
+const base::Feature kWebViewSniffMimeType{"WebViewSniffMimeType",
+                                          base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Enable raster in wide color gamut for apps that use webview in a wide color
 // gamut activity.
 const base::Feature kWebViewWideColorGamutSupport{
diff --git a/android_webview/browser/aw_feature_list.h b/android_webview/browser/aw_feature_list.h
index 5768d5033..a642e2a 100644
--- a/android_webview/browser/aw_feature_list.h
+++ b/android_webview/browser/aw_feature_list.h
@@ -16,6 +16,7 @@
 // Alphabetical:
 extern const base::Feature kWebViewBrotliSupport;
 extern const base::Feature kWebViewConnectionlessSafeBrowsing;
+extern const base::Feature kWebViewSniffMimeType;
 extern const base::Feature kWebViewWideColorGamutSupport;
 
 }  // namespace features
diff --git a/android_webview/browser/net/aw_network_delegate.cc b/android_webview/browser/net/aw_network_delegate.cc
index 192a351..83e8cbab 100644
--- a/android_webview/browser/net/aw_network_delegate.cc
+++ b/android_webview/browser/net/aw_network_delegate.cc
@@ -29,7 +29,7 @@
 namespace {
 
 void OnReceivedHttpErrorOnUiThread(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const content::WebContents::Getter& web_contents_getter,
     const AwWebResourceRequest& request,
     std::unique_ptr<AwContentsClientBridge::HttpErrorInfo> http_error_info) {
   AwContentsClientBridge* client =
diff --git a/android_webview/browser/network_service/android_stream_reader_url_loader.cc b/android_webview/browser/network_service/android_stream_reader_url_loader.cc
index 56fdfe6..17bd726 100644
--- a/android_webview/browser/network_service/android_stream_reader_url_loader.cc
+++ b/android_webview/browser/network_service/android_stream_reader_url_loader.cc
@@ -4,16 +4,19 @@
 
 #include "android_webview/browser/network_service/android_stream_reader_url_loader.h"
 
+#include "android_webview/browser/aw_feature_list.h"
 #include "android_webview/browser/input_stream.h"
 #include "android_webview/browser/net/input_stream_reader.h"
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/feature_list.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/io_buffer.h"
+#include "net/base/mime_sniffer.h"
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
@@ -96,6 +99,8 @@
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
     std::unique_ptr<ResponseDelegate> response_delegate)
     : resource_request_(resource_request),
+      resource_response_head_(
+          std::make_unique<network::ResourceResponseHead>()),
       client_(std::move(client)),
       traffic_annotation_(traffic_annotation),
       response_delegate_(std::move(response_delegate)),
@@ -213,7 +218,7 @@
   // HttpResponseHeaders expects its input string to be terminated by two NULs.
   status.append("\0\0", 2);
 
-  network::ResourceResponseHead head;
+  network::ResourceResponseHead& head = *resource_response_head_;
   head.request_start = base::TimeTicks::Now();
   head.response_start = base::TimeTicks::Now();
   head.headers = new net::HttpResponseHeaders(status);
@@ -256,18 +261,14 @@
   // file resources?). The old path does this as well.
   head.headers->AddHeader(kResponseHeaderViaShouldInterceptRequest);
 
-  DCHECK(client_.is_bound());
-  client_->OnReceiveResponse(head);
-
   SendBody();
 }
 
 void AndroidStreamReaderURLLoader::SendBody() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  mojo::ScopedDataPipeConsumerHandle consumer_handle;
   if (CreateDataPipe(nullptr /*options*/, &producer_handle_,
-                     &consumer_handle) != MOJO_RESULT_OK) {
+                     &consumer_handle_) != MOJO_RESULT_OK) {
     RequestComplete(net::ERR_FAILED);
     return;
   }
@@ -275,11 +276,30 @@
       producer_handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
       base::BindRepeating(&AndroidStreamReaderURLLoader::OnDataPipeWritable,
                           base::Unretained(this)));
-  client_->OnStartLoadingResponseBody(std::move(consumer_handle));
 
+  // Send the response if possible now for 2 reasons:
+  // 1. If we don't need any more MIME type sniffing, there's no reason not to
+  //    tell the URLLoaderClient right away. Sending now should preserve
+  //    ordering between app-visible callbacks and the first read of the
+  //    InputStream (although we do not generally guarantee the ordering).
+  // 2. Sending this now lets us unittest the net::ERR_ABORTED case. The case
+  //    needs the ability to break the stream after getting the headers but
+  //    before finishing the read.
+  if (!base::FeatureList::IsEnabled(features::kWebViewSniffMimeType) ||
+      !resource_response_head_->mime_type.empty()) {
+    SendResponseToClient();
+  }
   ReadMore();
 }
 
+void AndroidStreamReaderURLLoader::SendResponseToClient() {
+  DCHECK(consumer_handle_.is_valid());
+  DCHECK(client_.is_bound());
+  client_->OnReceiveResponse(*resource_response_head_);
+  resource_response_head_ = nullptr;
+  client_->OnStartLoadingResponseBody(std::move(consumer_handle_));
+}
+
 void AndroidStreamReaderURLLoader::ReadMore() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!pending_buffer_.get());
@@ -336,6 +356,30 @@
     RequestComplete(net::OK);
     return;
   }
+  if (consumer_handle_.is_valid()) {
+    // We only hit this on for the first buffer read, which we expect to be
+    // enough to determine the MIME type.
+    DCHECK(base::FeatureList::IsEnabled(features::kWebViewSniffMimeType));
+    if (resource_response_head_->mime_type.empty()) {
+      // Limit sniffing to the first net::kMaxBytesToSniff.
+      size_t data_length = result;
+      if (data_length > net::kMaxBytesToSniff)
+        data_length = net::kMaxBytesToSniff;
+
+      std::string new_type;
+      net::SniffMimeType(pending_buffer_->buffer(), data_length,
+                         resource_request_.url, std::string(),
+                         net::ForceSniffFileUrlsForHtml::kDisabled, &new_type);
+      // SniffMimeType() returns false if there is not enough data to
+      // determine the mime type. However, even if it returns false, it
+      // returns a new type that is probably better than the current one.
+      resource_response_head_->mime_type.assign(new_type);
+      resource_response_head_->did_mime_sniff = true;
+    }
+
+    SendResponseToClient();
+  }
+
   producer_handle_ = pending_buffer_->Complete(result);
   pending_buffer_ = nullptr;
 
@@ -357,6 +401,10 @@
 
 void AndroidStreamReaderURLLoader::RequestComplete(int status_code) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  if (consumer_handle_.is_valid()) {
+    // We can hit this before reading any buffers under error conditions.
+    SendResponseToClient();
+  }
 
   client_->OnComplete(network::URLLoaderCompletionStatus(status_code));
   CleanUp();
diff --git a/android_webview/browser/network_service/android_stream_reader_url_loader.h b/android_webview/browser/network_service/android_stream_reader_url_loader.h
index 7796315..1725817 100644
--- a/android_webview/browser/network_service/android_stream_reader_url_loader.h
+++ b/android_webview/browser/network_service/android_stream_reader_url_loader.h
@@ -88,14 +88,26 @@
 
   void OnDataPipeWritable(MojoResult result);
   void CleanUp();
+
+  // Called after trying to read some bytes from the stream. |result| can be a
+  // positive number (the number of bytes read), zero (no bytes were read
+  // because the stream is finished), or negative (error condition).
   void DidRead(int result);
+  // Reads some bytes from the stream. Calls |DidRead| after each read (also, in
+  // the case where it fails to read due to an error).
   void ReadMore();
+  // Send response headers and the data pipe consumer handle (for the body) to
+  // the URLLoaderClient. Requires |consumer_handle_| to be valid, and will make
+  // |consumer_handle_| invalid after running.
+  void SendResponseToClient();
 
   // Expected content size
   int64_t expected_content_size_ = -1;
+  mojo::ScopedDataPipeConsumerHandle consumer_handle_;
 
   net::HttpByteRange byte_range_;
   network::ResourceRequest resource_request_;
+  std::unique_ptr<network::ResourceResponseHead> resource_response_head_;
   network::mojom::URLLoaderClientPtr client_;
   const net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
   std::unique_ptr<ResponseDelegate> response_delegate_;
diff --git a/android_webview/browser/network_service/android_stream_reader_url_loader_unittest.cc b/android_webview/browser/network_service/android_stream_reader_url_loader_unittest.cc
index 07c9c2bd..cdd9a59d 100644
--- a/android_webview/browser/network_service/android_stream_reader_url_loader_unittest.cc
+++ b/android_webview/browser/network_service/android_stream_reader_url_loader_unittest.cc
@@ -89,6 +89,10 @@
   TestResponseDelegate(std::unique_ptr<InputStream> input_stream)
       : input_stream_(std::move(input_stream)) {}
   TestResponseDelegate(std::unique_ptr<InputStream> input_stream,
+                       const std::string custom_mime_type)
+      : input_stream_(std::move(input_stream)),
+        custom_mime_type_(custom_mime_type) {}
+  TestResponseDelegate(std::unique_ptr<InputStream> input_stream,
                        const std::string& custom_status,
                        const std::string& custom_header_name,
                        const std::string& custom_header_value)
@@ -112,6 +116,10 @@
                    const GURL& url,
                    android_webview::InputStream* stream,
                    std::string* mime_type) override {
+    if (!custom_mime_type_.empty()) {
+      *mime_type = custom_mime_type_;
+      return true;
+    }
     return false;
   }
 
@@ -138,6 +146,7 @@
 
  private:
   std::unique_ptr<InputStream> input_stream_;
+  const std::string custom_mime_type_;
   const std::string custom_status_;
   const std::string custom_header_name_;
   const std::string custom_header_value_;
@@ -175,6 +184,19 @@
         std::make_unique<TestResponseDelegate>(std::move(input_stream)));
   }
 
+  // helper method for creating loaders given a stream and MIME type
+  AndroidStreamReaderURLLoader* CreateLoaderWithMimeType(
+      const network::ResourceRequest& request,
+      network::TestURLLoaderClient* client,
+      std::unique_ptr<InputStream> input_stream,
+      const std::string custom_mime_type) {
+    return new AndroidStreamReaderURLLoader(
+        request, client->CreateInterfacePtr(),
+        net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
+        std::make_unique<TestResponseDelegate>(std::move(input_stream),
+                                               custom_mime_type));
+  }
+
   // helper method for creating loaders given a stream and response header
   // values
   AndroidStreamReaderURLLoader* CreateLoaderWithCustomizedResponseHeader(
@@ -335,8 +357,12 @@
   std::string expected_body("test");
   std::unique_ptr<network::TestURLLoaderClient> client =
       std::make_unique<network::TestURLLoaderClient>();
-  AndroidStreamReaderURLLoader* loader = CreateLoader(
-      request, client.get(), std::make_unique<FakeInputStream>(expected_body));
+  // Need a valid MIME type, otherwise we won't get headers until we've already
+  // read the input stream (and we need to interrupt the read in this test).
+  std::string valid_mime_type("text/html");
+  AndroidStreamReaderURLLoader* loader = CreateLoaderWithMimeType(
+      request, client.get(), std::make_unique<FakeInputStream>(expected_body),
+      valid_mime_type);
   loader->Start();
   client->RunUntilResponseBodyArrived();
   EXPECT_TRUE(client->has_received_response());
diff --git a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
index ce4de09d..db361f58 100644
--- a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
+++ b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
@@ -25,9 +25,9 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/global_request_id.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_constants.h"
+#include "content/public/common/resource_type.h"
 #include "content/public/common/url_utils.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_util.h"
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 7bba7cb..4fc6568 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1573,6 +1573,11 @@
   public_deps = [
     ":ash_shell_lib",
   ]
+  data_deps = [
+    "//ash/strings:ash_test_strings",
+    "//ash/resources:ash_test_resources_with_content_100_percent",
+    "//ash/resources:ash_test_resources_200_percent",
+  ]
 }
 
 copy("dbus_service_files") {
@@ -2112,10 +2117,6 @@
     "//content/public/app:both",
     "//device/bluetooth",
   ]
-
-  data_deps = [
-    "//ash/resources:ash_test_resources_with_content_100_percent",
-  ]
 }
 
 static_library("test_support") {
diff --git a/ash/display/display_color_manager.cc b/ash/display/display_color_manager.cc
index 345bee3..35e00ec 100644
--- a/ash/display/display_color_manager.cc
+++ b/ash/display/display_color_manager.cc
@@ -328,7 +328,7 @@
   // TODO(mcasas): correct UMA s/Id/Code/, https://crbug.com/821393.
   UMA_HISTOGRAM_BOOLEAN("Ash.DisplayColorManager.ValidProductId",
                         valid_product_code);
-  if (!valid_product_code)
+  if (!valid_product_code || !quirks::QuirksManager::HasInstance())
     return false;
 
   quirks::QuirksManager::Get()->RequestIccProfilePath(
diff --git a/ash/shell.h b/ash/shell.h
index 684c576..bffe8a5 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -785,7 +785,7 @@
 
   std::unique_ptr<DockedMagnifierControllerImpl> docked_magnifier_controller_;
 
-  // The split view controller for Chrome OS in tablet mode.
+  // The split view controller for Chrome OS.
   std::unique_ptr<SplitViewController> split_view_controller_;
 
   std::unique_ptr<SnapController> snap_controller_;
diff --git a/ash/shell/content/client/shell_browser_main_parts.cc b/ash/shell/content/client/shell_browser_main_parts.cc
index fbcc7ec..7180e26 100644
--- a/ash/shell/content/client/shell_browser_main_parts.cc
+++ b/ash/shell/content/client/shell_browser_main_parts.cc
@@ -144,7 +144,7 @@
                             base::Unretained(browser_context_.get()), nullptr),
         base::BindRepeating(base::IgnoreResult(&EmbeddedBrowser::Create),
                             base::Unretained(browser_context_.get()),
-                            GURL("https://www.google.com")));
+                            GURL("https://www.google.com"), base::nullopt));
   }
 }
 
diff --git a/ash/shell/content/embedded_browser.cc b/ash/shell/content/embedded_browser.cc
index 40ee168..23c23d0 100644
--- a/ash/shell/content/embedded_browser.cc
+++ b/ash/shell/content/embedded_browser.cc
@@ -45,10 +45,11 @@
 }  // namespace
 
 EmbeddedBrowser::EmbeddedBrowser(content::BrowserContext* context,
-                                 const GURL& url)
+                                 const GURL& url,
+                                 const gfx::Rect& bounds)
     : widget_(new views::Widget) {
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
-  params.bounds = gfx::Rect(20, 20, 800, 600);
+  params.bounds = bounds;
   params.delegate = new BrowserWidgetDelegateView(context, url);
   widget_->Init(params);
   WindowState::Get(widget_->GetNativeWindow())->SetWindowPositionManaged(true);
@@ -63,10 +64,14 @@
 
 // static
 aura::Window* EmbeddedBrowser::Create(content::BrowserContext* context,
-                                      const GURL& url) {
+                                      const GURL& url,
+                                      base::Optional<gfx::Rect> bounds) {
+  static const gfx::Rect default_bounds(20, 20, 800, 600);
+
   // EmbeddedBrowser deletes itself when the widget is closed.
   aura::Window* browser_window =
-      (new EmbeddedBrowser(context, url))->GetWindow();
+      (new EmbeddedBrowser(context, url, bounds ? *bounds : default_bounds))
+          ->GetWindow();
   browser_window->SetProperty(aura::client::kAppType,
                               static_cast<int>(ash::AppType::BROWSER));
   return browser_window;
diff --git a/ash/shell/content/embedded_browser.h b/ash/shell/content/embedded_browser.h
index e5cc38df..70ae533 100644
--- a/ash/shell/content/embedded_browser.h
+++ b/ash/shell/content/embedded_browser.h
@@ -8,6 +8,8 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/optional.h"
+#include "ui/gfx/geometry/rect.h"
 
 class GURL;
 
@@ -29,16 +31,19 @@
 // Exercises ServerRemoteViewHost to embed a content::WebContents.
 class EmbeddedBrowser {
  public:
-  EmbeddedBrowser(content::BrowserContext* context, const GURL& url);
-  ~EmbeddedBrowser();
-
   aura::Window* GetWindow();
 
   // Factory.
   static aura::Window* Create(content::BrowserContext* context,
-                              const GURL& url);
+                              const GURL& url,
+                              base::Optional<gfx::Rect> bounds = base::nullopt);
 
  private:
+  EmbeddedBrowser(content::BrowserContext* context,
+                  const GURL& url,
+                  const gfx::Rect& bounds);
+  ~EmbeddedBrowser();
+
   // Callback invoked when the embedding is broken.
   void OnUnembed();
 
diff --git a/ash/shell/content/test/ash_content_test.cc b/ash/shell/content/test/ash_content_test.cc
index 0a214ac..b6089e9 100644
--- a/ash/shell/content/test/ash_content_test.cc
+++ b/ash/shell/content/test/ash_content_test.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "ash/shelf/shelf_constants.h"
 #include "ash/shell.h"
 #include "ash/shell/content/client/shell_browser_main_parts.h"
 #include "ash/shell/content/embedded_browser.h"
@@ -121,7 +122,6 @@
 AshContentTest::~AshContentTest() = default;
 
 void AshContentTest::SetUp() {
-  content::ContentBrowserTest::SetUp();
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   // Add command line arguments that are used by all AshContentTests.
   if (!command_line->HasSwitch(switches::kHostWindowBounds) &&
@@ -132,6 +132,7 @@
     command_line->AppendSwitchASCII(switches::kHostWindowBounds,
                                     "0+0-1280x800");
   }
+  content::ContentBrowserTest::SetUp();
 }
 
 void AshContentTest::SetUpOnMainThread() {
@@ -145,6 +146,10 @@
             "benchmark,cc,viz,input,latency,gpu,rail,toplevel,ui,views,viz"),
         GetUMAHistogramNames());
   }
+  gfx::Size display_size = ash::Shell::GetPrimaryRootWindow()->bounds().size();
+  test_window_size_.set_height((display_size.height() - ash::kShelfSize) *
+                               0.95f);
+  test_window_size_.set_width(display_size.width() * 0.7f);
 }
 
 void AshContentTest::TearDownOnMainThread() {
@@ -164,14 +169,15 @@
 
 aura::Window* AshContentTest::CreateBrowserWindow(const GURL& url) {
   return ash::shell::EmbeddedBrowser::Create(
-      ash::shell::ShellBrowserMainParts::GetBrowserContext(), url);
+      ash::shell::ShellBrowserMainParts::GetBrowserContext(), url,
+      gfx::Rect(test_window_size_));
 }
 
 aura::Window* AshContentTest::CreateTestWindow() {
   views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
       new ash::shell::WindowTypeLauncher(base::NullCallback(),
                                          base::NullCallback()),
-      ash::Shell::GetPrimaryRootWindow(), gfx::Rect(600, 800));
+      ash::Shell::GetPrimaryRootWindow(), gfx::Rect(test_window_size_));
   widget->GetNativeView()->SetName("WindowTypeLauncher");
   widget->Show();
 
diff --git a/ash/shell/content/test/ash_content_test.h b/ash/shell/content/test/ash_content_test.h
index d7dcb9c..19d370bf 100644
--- a/ash/shell/content/test/ash_content_test.h
+++ b/ash/shell/content/test/ash_content_test.h
@@ -33,6 +33,7 @@
  private:
   class Tracer;
 
+  gfx::Size test_window_size_;
   bool enable_trace_;
   std::unique_ptr<Tracer> tracer_;
 
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index b3c943b..fd1a557872c51 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -36,6 +36,7 @@
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/strings/string_split.h"
+#include "base/system/sys_info.h"
 #include "base/token.h"
 #include "chromeos/audio/cras_audio_handler.h"
 #include "chromeos/dbus/audio/cras_audio_client.h"
@@ -84,7 +85,8 @@
   // TODO(jamescook): Can we do this without changing command line?
   // Use the origin (1,1) so that it doesn't over
   // lap with the native mouse cursor.
-  if (!command_line_->GetProcessCommandLine()->HasSwitch(
+  if (!base::SysInfo::IsRunningOnChromeOS() &&
+      !command_line_->GetProcessCommandLine()->HasSwitch(
           ::switches::kHostWindowBounds)) {
     // TODO(oshima): Disable native events instead of adding offset.
     command_line_->GetProcessCommandLine()->AppendSwitchASCII(
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index 4254329..8193e98 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -619,10 +619,11 @@
     SplitViewController::SnapPosition default_snap_position =
         split_view_controller_->default_snap_position();
     // If we're trying to snap to a position that already has a snapped window:
-    const bool re_snap =
-        is_primary == (position < split_view_controller_->divider_position() ==
-                       (default_snap_position == SplitViewController::LEFT));
-    if (re_snap)
+    const bool is_default_snap_position_left_or_top =
+        is_primary == (default_snap_position == SplitViewController::LEFT);
+    const bool is_drag_position_left_or_top =
+        position < split_view_controller_->divider_position();
+    if (is_default_snap_position_left_or_top == is_drag_position_left_or_top)
       return default_snap_position;
   }
 
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 2368ec78..b458070 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -556,7 +556,7 @@
     return (work_area_bounds_in_screen.height() - divider_size.height()) * 0.5f;
 }
 
-bool SplitViewController::IsDividerAnimating() {
+bool SplitViewController::IsDividerAnimating() const {
   return divider_snap_animation_ && divider_snap_animation_->is_animating();
 }
 
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 7f8fad7d..f9a9dcb 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -140,7 +140,7 @@
   int GetDefaultDividerPosition(aura::Window* window) const;
 
   // Returns true during the divider snap animation.
-  bool IsDividerAnimating();
+  bool IsDividerAnimating() const;
 
   void StartResize(const gfx::Point& location_in_screen);
   void Resize(const gfx::Point& location_in_screen);
diff --git a/base/android/jni_generator/BUILD.gn b/base/android/jni_generator/BUILD.gn
index 691e584..dc671366 100644
--- a/base/android/jni_generator/BUILD.gn
+++ b/base/android/jni_generator/BUILD.gn
@@ -91,7 +91,13 @@
 }
 
 java_annotation_processor("jni_processor") {
-  java_files = [ "java/src/org/chromium/jni_generator/JniProcessor.java" ]
+  java_files = [
+    "java/src/org/chromium/jni_generator/JniProcessor.java",
+
+    # Avoids a circular dependency with base:base_java. This is okay because
+    # no target should ever expect to package an annotation processor.
+    "//base/android/java/src/org/chromium/base/annotations/MainDex.java",
+  ]
 
   main_class = "org.chromium.jni_generator.JniProcessor"
 
diff --git a/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java b/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
index f2d27fd..711730e 100644
--- a/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
+++ b/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
@@ -21,6 +21,7 @@
 import com.squareup.javapoet.TypeSpec;
 
 import org.chromium.base.JniStaticTestMocker;
+import org.chromium.base.annotations.MainDex;
 import org.chromium.base.annotations.NativeMethods;
 
 import java.security.MessageDigest;
@@ -60,6 +61,7 @@
 @AutoService(Processor.class)
 public class JniProcessor extends AbstractProcessor {
     private static final Class<NativeMethods> JNI_STATIC_NATIVES_CLASS = NativeMethods.class;
+    private static final Class<MainDex> MAIN_DEX_CLASS = MainDex.class;
 
     private static final String NATIVE_WRAPPER_CLASS_POSTFIX = "Jni";
 
@@ -184,9 +186,13 @@
             // method overridden will be a wrapper that calls its
             // native counterpart in NativeClass.
             boolean isNativesInterfacePublic = type.getModifiers().contains(Modifier.PUBLIC);
+            // If the outerType needs to be in the main dex, then the generated NativeWrapperClass
+            // should also be added to the main dex.
+            boolean addMainDexAnnotation = outerElement.getAnnotation(MAIN_DEX_CLASS) != null;
+
             TypeSpec nativeWrapperClassSpec =
                     createNativeWrapperClassSpec(getNameOfWrapperClass(outerClassName),
-                            isNativesInterfacePublic, type, methodMap);
+                            isNativesInterfacePublic, addMainDexAnnotation, type, methodMap);
 
             // Queue this file for writing.
             // Can't write right now because the wrapper class depends on NativeClass
@@ -318,11 +324,12 @@
      *
      * @param name name of the wrapper class.
      * @param isPublic if true, a public modifier will be added to this native wrapper.
+     * @param isMainDex if true, the @MainDex annotation will be added to this native wrapper.
      * @param nativeInterface the {@link NativeMethods} annotated type that this native wrapper
      *                        will implement.
      * @param methodMap a map from the old method name to the new method spec in NativeClass.
      * */
-    TypeSpec createNativeWrapperClassSpec(String name, boolean isPublic,
+    TypeSpec createNativeWrapperClassSpec(String name, boolean isPublic, boolean isMainDex,
             TypeElement nativeInterface, Map<String, MethodSpec> methodMap) {
         // The wrapper class builder.
         TypeName nativeInterfaceType = TypeName.get(nativeInterface.asType());
@@ -333,6 +340,9 @@
         if (isPublic) {
             builder.addModifiers(Modifier.PUBLIC);
         }
+        if (isMainDex) {
+            builder.addAnnotation(MAIN_DEX_CLASS);
+        }
 
         // Start by adding all the native method wrappers.
         for (Element enclosed : nativeInterface.getEnclosedElements()) {
diff --git a/base/process/memory.h b/base/process/memory.h
index 7f16e12d..1dd2f412 100644
--- a/base/process/memory.h
+++ b/base/process/memory.h
@@ -11,14 +11,6 @@
 #include "base/process/process_handle.h"
 #include "build/build_config.h"
 
-#ifdef PVALLOC_AVAILABLE
-// Build config explicitly tells us whether or not pvalloc is available.
-#elif defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
-#define PVALLOC_AVAILABLE 1
-#else
-#define PVALLOC_AVAILABLE 0
-#endif
-
 namespace base {
 
 // Enables 'terminate on heap corruption' flag. Helps protect against heap
diff --git a/base/process/memory_unittest.cc b/base/process/memory_unittest.cc
index 835cf7e..a2f559cb 100644
--- a/base/process/memory_unittest.cc
+++ b/base/process/memory_unittest.cc
@@ -307,7 +307,6 @@
     }, kOomRegex);
 }
 
-#if PVALLOC_AVAILABLE == 1
 TEST_F(OutOfMemoryDeathTest, Pvalloc) {
   ASSERT_DEATH({
       SetUpInDeathAssert();
@@ -321,7 +320,6 @@
       value_ = pvalloc(insecure_test_size_);
     }, kOomRegex);
 }
-#endif  // PVALLOC_AVAILABLE == 1
 
 TEST_F(OutOfMemoryDeathTest, Memalign) {
   ASSERT_DEATH({
diff --git a/base/values.cc b/base/values.cc
index 7d042cd..02e92b7e 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -320,6 +320,11 @@
   return string_value_;
 }
 
+std::string& Value::GetString() {
+  CHECK(is_string());
+  return string_value_;
+}
+
 const Value::BlobStorage& Value::GetBlob() const {
   CHECK(is_blob());
   return binary_value_;
@@ -386,6 +391,11 @@
   return result ? &result->string_value_ : nullptr;
 }
 
+std::string* Value::FindStringKey(StringPiece key) {
+  Value* result = FindKeyOfType(key, Type::STRING);
+  return result ? &result->string_value_ : nullptr;
+}
+
 const Value::BlobStorage* Value::FindBlobKey(StringPiece key) const {
   const Value* value = FindKeyOfType(key, Type::BINARY);
   return value ? &value->binary_value_ : nullptr;
@@ -526,6 +536,11 @@
   return &cur->string_value_;
 }
 
+std::string* Value::FindStringPath(StringPiece path) {
+  return const_cast<std::string*>(
+      static_cast<const Value*>(this)->FindStringPath(path));
+}
+
 const Value::BlobStorage* Value::FindBlobPath(StringPiece path) const {
   const Value* cur = FindPath(path);
   if (!cur || !cur->is_blob())
diff --git a/base/values.h b/base/values.h
index ef24b19..38e4f37 100644
--- a/base/values.h
+++ b/base/values.h
@@ -172,6 +172,7 @@
   int GetInt() const;
   double GetDouble() const;  // Implicitly converts from int if necessary.
   const std::string& GetString() const;
+  std::string& GetString();
   const BlobStorage& GetBlob() const;
 
   ListStorage& GetList();
@@ -211,6 +212,7 @@
 
   // |FindStringKey| returns |nullptr| if value is not found or not a string.
   const std::string* FindStringKey(StringPiece key) const;
+  std::string* FindStringKey(StringPiece key);
 
   // Returns nullptr is value is not found or not a binary.
   const BlobStorage* FindBlobKey(StringPiece key) const;
@@ -318,6 +320,7 @@
   base::Optional<int> FindIntPath(StringPiece path) const;
   base::Optional<double> FindDoublePath(StringPiece path) const;
   const std::string* FindStringPath(StringPiece path) const;
+  std::string* FindStringPath(StringPiece path);
   const BlobStorage* FindBlobPath(StringPiece path) const;
   Value* FindDictPath(StringPiece path);
   const Value* FindDictPath(StringPiece path) const;
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 884309b..c8be7e5f 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -748,6 +748,20 @@
   EXPECT_EQ(nullptr, dict.FindStringKey("dict"));
 }
 
+TEST(ValuesTest, MutableFindStringKey) {
+  Value::DictStorage storage;
+  storage.emplace("string", std::make_unique<Value>("foo"));
+  Value dict(std::move(storage));
+
+  *(dict.FindStringKey("string")) = "bar";
+
+  Value::DictStorage expected_storage;
+  expected_storage.emplace("string", std::make_unique<Value>("bar"));
+  Value expected_dict(std::move(expected_storage));
+
+  EXPECT_EQ(expected_dict, dict);
+}
+
 TEST(ValuesTest, FindDictKey) {
   Value::DictStorage storage;
   storage.emplace("null", std::make_unique<Value>(Value::Type::NONE));
@@ -2374,4 +2388,22 @@
   EXPECT_EQ(dict_copy, *val);
 }
 
+TEST(ValuesTest, MutableFindStringPath) {
+  Value dict(Value::Type::DICTIONARY);
+  dict.SetStringPath("foo.bar", "value");
+
+  *(dict.FindStringPath("foo.bar")) = "new_value";
+
+  Value expected_dict(Value::Type::DICTIONARY);
+  expected_dict.SetStringPath("foo.bar", "new_value");
+
+  EXPECT_EQ(expected_dict, dict);
+}
+
+TEST(ValuesTest, MutableGetString) {
+  Value value("value");
+  value.GetString() = "new_value";
+  EXPECT_EQ("new_value", value.GetString());
+}
+
 }  // namespace base
diff --git a/build/fuchsia/fidlgen_js/runtime/zircon.cc b/build/fuchsia/fidlgen_js/runtime/zircon.cc
index 55ccb101..7787db0d 100644
--- a/build/fuchsia/fidlgen_js/runtime/zircon.cc
+++ b/build/fuchsia/fidlgen_js/runtime/zircon.cc
@@ -39,7 +39,7 @@
                   zx_handle_t handle,
                   zx_signals_t signals)
       : async_wait_t({ASYNC_STATE_INIT, &WaitPromiseImpl::StaticOnSignaled,
-                      handle, signals}),
+                      handle, signals, 0}),
         isolate_(isolate),
         wait_state_(WaitState::kCreated),
         failed_start_status_(ZX_OK) {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 0c100ed4..45760342 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8906501286599338608
\ No newline at end of file
+8906478680409839408
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index c8f0a09..6ee9f83 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8906527071452361600
\ No newline at end of file
+8906483693919796992
\ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION
index 7a1e32d..81a66e0 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=78
 MINOR=0
-BUILD=3870
+BUILD=3871
 PATCH=0
diff --git a/chrome/android/java/res/drawable/explore_sites_dense_tile_background.xml b/chrome/android/java/res/drawable/explore_sites_dense_tile_background.xml
new file mode 100644
index 0000000..ed7c235a
--- /dev/null
+++ b/chrome/android/java/res/drawable/explore_sites_dense_tile_background.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/modern_secondary_color" />
+    <corners android:radius="@dimen/explore_sites_dense_icon_corner_radius" />
+</shape>
diff --git a/chrome/android/java/res/layout/explore_sites_dense_tile_bottom_view.xml b/chrome/android/java/res/layout/explore_sites_dense_tile_bottom_view.xml
index bcc875a5..d3d535e5 100644
--- a/chrome/android/java/res/layout/explore_sites_dense_tile_bottom_view.xml
+++ b/chrome/android/java/res/layout/explore_sites_dense_tile_bottom_view.xml
@@ -18,7 +18,7 @@
         android:layout_height="@dimen/explore_sites_dense_icon_size"
         android:layout_marginTop="@dimen/explore_sites_dense_title_bottom_icon_margin_top"
         android:layout_gravity="center_horizontal"
-        android:visibility="gone" />
+        android:background="@drawable/explore_sites_dense_tile_background" />
     <!-- The main icon. -->
     <ImageView
         android:id="@+id/tile_view_icon"
diff --git a/chrome/android/java/res/layout/explore_sites_dense_tile_right_view.xml b/chrome/android/java/res/layout/explore_sites_dense_tile_right_view.xml
index 9f2957d6..ef04ca0 100644
--- a/chrome/android/java/res/layout/explore_sites_dense_tile_right_view.xml
+++ b/chrome/android/java/res/layout/explore_sites_dense_tile_right_view.xml
@@ -16,9 +16,9 @@
         android:id="@+id/tile_view_icon_background"
         android:layout_width="@dimen/explore_sites_dense_icon_size"
         android:layout_height="@dimen/explore_sites_dense_icon_size"
-        android:layout_marginTop="@dimen/explore_sites_dense_title_bottom_icon_margin_top"
-        android:layout_gravity="center_horizontal"
-        android:visibility="gone" />
+        android:layout_marginStart="@dimen/explore_sites_dense_title_bottom_icon_margin_top"
+        android:layout_gravity="center_vertical"
+        android:background="@drawable/explore_sites_dense_tile_background"/>
     <!-- The main icon. -->
     <ImageView
         android:id="@+id/tile_view_icon"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index be632d99..c4577f9 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -388,7 +388,7 @@
     <dimen name="explore_sites_dense_category_padding_vertical_bottom">12dp</dimen>
     <dimen name="explore_sites_dense_category_padding_vertical_top">8dp</dimen>
 
-    <dimen name="explore_sites_dense_icon_corner_radius">2dp</dimen>
+    <dimen name="explore_sites_dense_icon_corner_radius">3dp</dimen>
     <dimen name="explore_sites_dense_icon_size">32dp</dimen>
     <dimen name="explore_sites_dense_icon_text_size">16dp</dimen>
     <dimen name="explore_sites_dense_offline_badge_margin_start">26dp</dimen>
@@ -402,7 +402,7 @@
 
     <dimen name="explore_sites_dense_title_bottom_icon_margin_top">4dp</dimen>
     <dimen name="explore_sites_dense_title_bottom_tile_view_height">72dp</dimen>
-    <dimen name="explore_sites_dense_title_bottom_tile_view_width">68dp</dimen>
+    <dimen name="explore_sites_dense_title_bottom_tile_view_width">64dp</dimen>
     <dimen name="explore_sites_dense_title_bottom_title_margin_start">40dp</dimen>
 
     <!-- Recent tabs page -->
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkDelegate.java
index 1ea40bc..eae17775 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkDelegate.java
@@ -106,20 +106,6 @@
     DragStateDelegate getDragStateDelegate();
 
     /**
-     * Move a bookmark to the bottom of its folder.
-     *
-     * @param bookmarkId The bookmark to move.
-     */
-    void moveToBottom(BookmarkId bookmarkId);
-
-    /**
-     * Move a bookmark to the top of its folder.
-     *
-     * @param bookmarkId The bookmark to move.
-     */
-    void moveToTop(BookmarkId bookmarkId);
-
-    /**
      * Move a bookmark one position down within its folder.
      *
      * @param bookmarkId The bookmark to move.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java
index e8de64b..18cd468c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkItemsAdapter.java
@@ -365,16 +365,6 @@
         throw new RuntimeException("Cannot reorder bookmarks when bookmark reordering flag is off");
     }
 
-    @Override
-    public void moveToTop(BookmarkId bookmarkId) {
-        throw new RuntimeException("Cannot reorder bookmarks when bookmark reordering flag is off");
-    }
-
-    @Override
-    public void moveToBottom(BookmarkId bookmarkId) {
-        throw new RuntimeException("Cannot reorder bookmarks when bookmark reordering flag is off");
-    }
-
     private static class ItemViewHolder extends RecyclerView.ViewHolder {
         private ItemViewHolder(View view) {
             super(view);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
index 237a85db..b647e098 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
@@ -88,8 +88,6 @@
 
         void moveUpOne(BookmarkId bookmarkId);
         void moveDownOne(BookmarkId bookmarkId);
-        void moveToTop(BookmarkId bookmarkId);
-        void moveToBottom(BookmarkId bookmarkId);
     }
 
     private final BookmarkModelObserver mBookmarkModelObserver = new BookmarkModelObserver() {
@@ -450,16 +448,6 @@
     }
 
     @Override
-    public void moveToBottom(BookmarkId bookmarkId) {
-        mAdapter.moveToBottom(bookmarkId);
-    }
-
-    @Override
-    public void moveToTop(BookmarkId bookmarkId) {
-        mAdapter.moveToTop(bookmarkId);
-    }
-
-    @Override
     public void moveDownOne(BookmarkId bookmarkId) {
         mAdapter.moveDownOne(bookmarkId);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java
index 830b60d8d..3698da5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java
@@ -42,8 +42,6 @@
     @Location
     private int mLocation;
 
-    private static final String TAG = "BookmarkRow";
-
     @IntDef({Location.TOP, Location.MIDDLE, Location.BOTTOM})
     @Retention(RetentionPolicy.SOURCE)
     public @interface Location {
@@ -161,12 +159,6 @@
             if (mLocation != Location.BOTTOM) {
                 menuItems.add(new Item(getContext(), R.string.menu_item_move_down, true));
             }
-            if (mLocation != Location.TOP) {
-                menuItems.add(new Item(getContext(), R.string.menu_item_move_to_top, true));
-            }
-            if (mLocation != Location.BOTTOM) {
-                menuItems.add(new Item(getContext(), R.string.menu_item_move_to_bottom, true));
-            }
         }
         return menuItems.toArray(new Item[menuItems.size()]);
     }
@@ -197,12 +189,10 @@
 
         } else if (item.getTextId() == R.string.menu_item_move_up) {
             mDelegate.moveUpOne(mBookmarkId);
+            RecordUserAction.record("MobileBookmarkManagerMoveUp");
         } else if (item.getTextId() == R.string.menu_item_move_down) {
             mDelegate.moveDownOne(mBookmarkId);
-        } else if (item.getTextId() == R.string.menu_item_move_to_top) {
-            mDelegate.moveToTop(mBookmarkId);
-        } else if (item.getTextId() == R.string.menu_item_move_to_bottom) {
-            mDelegate.moveToBottom(mBookmarkId);
+            RecordUserAction.record("MobileBookmarkManagerMoveDown");
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReorderBookmarkItemsAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReorderBookmarkItemsAdapter.java
index 348e68cf..aeb001e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReorderBookmarkItemsAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReorderBookmarkItemsAdapter.java
@@ -15,6 +15,8 @@
 import android.view.ViewGroup;
 
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem;
 import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkModelObserver;
@@ -23,6 +25,7 @@
 import org.chromium.chrome.browser.signin.PersonalizedSigninPromoView;
 import org.chromium.chrome.browser.widget.dragreorder.DragReorderableListAdapter;
 import org.chromium.components.bookmarks.BookmarkId;
+import org.chromium.components.bookmarks.BookmarkType;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -61,6 +64,10 @@
     private String mSearchText;
     private BookmarkId mCurrentFolder;
 
+    // For metrics
+    private int mDragReorderCount;
+    private int mMoveButtonCount;
+
     private BookmarkModelObserver mBookmarkModelObserver = new BookmarkModelObserver() {
         @Override
         public void bookmarkNodeChanged(BookmarkItem node) {
@@ -236,6 +243,7 @@
     // BookmarkUIObserver implementations.
     @Override
     public void onDestroy() {
+        recordSessionReorderInfo(); // For metrics
         mDelegate.removeUIObserver(this);
         mDelegate.getModel().removeObserver(mBookmarkModelObserver);
         mDelegate.getSelectionDelegate().removeObserver(this);
@@ -250,6 +258,10 @@
         mSearchText = EMPTY_QUERY;
         mCurrentFolder = folder;
 
+        if (!(folder.equals(mCurrentFolder))) {
+            recordSessionReorderInfo();
+            mCurrentFolder = folder;
+        }
         enableDrag();
 
         if (folder.equals(mDelegate.getModel().getRootFolderId())) {
@@ -261,6 +273,7 @@
 
     @Override
     public void onSearchStateSet() {
+        recordSessionReorderInfo(); // For metrics
         disableDrag();
         // Headers should not appear in Search mode
         // Don't need to notify because we need to redraw everything in the next step
@@ -310,22 +323,18 @@
         setOrder(mElements);
     }
 
-    @Override
-    public void moveToTop(BookmarkId bookmarkId) {
-        int pos = getPositionForBookmark(bookmarkId);
-        mElements.remove(pos);
-        mElements.add(
-                getBookmarkItemStartIndex(), mDelegate.getModel().getBookmarkById(bookmarkId));
-        setOrder(mElements);
-    }
-
-    @Override
-    public void moveToBottom(BookmarkId bookmarkId) {
-        int pos = getPositionForBookmark(bookmarkId);
-        mElements.remove(pos);
-        mElements.add(
-                getBookmarkItemEndIndex() + 1, mDelegate.getModel().getBookmarkById(bookmarkId));
-        setOrder(mElements);
+    private void recordSessionReorderInfo() {
+        // Record metrics when we are exiting a folder (mCurrentFolder must not be null)
+        // Cannot reorder top level folders or partner bookmarks
+        if (mCurrentFolder != null && !mCurrentFolder.equals(mDelegate.getModel().getRootFolderId())
+                && mCurrentFolder.getType() != BookmarkType.PARTNER) {
+            RecordHistogram.recordCount1000Histogram(
+                    "BookmarkManager.NumDraggedInSession", mDragReorderCount);
+            RecordHistogram.recordCount1000Histogram(
+                    "BookmarkManager.NumReorderButtonInSession", mMoveButtonCount);
+            mDragReorderCount = 0;
+            mMoveButtonCount = 0;
+        }
     }
 
     /**
@@ -410,7 +419,10 @@
 
     @Override
     protected void setOrder(List<BookmarkItem> bookmarkItems) {
-        assert mCurrentFolder != mTopLevelFolders : "Cannot reorder top-level folders!";
+        assert !mCurrentFolder.equals(mDelegate.getModel().getRootFolderId())
+            : "Cannot reorder top-level folders!";
+        assert mCurrentFolder.getType()
+                != BookmarkType.PARTNER : "Cannot reorder partner bookmarks!";
         assert mDelegate.getCurrentState()
                 == BookmarkUIState.STATE_FOLDER : "Can only reorder items from folder mode!";
 
@@ -423,6 +435,12 @@
             newOrder[i - startIndex] = bookmarkItems.get(i).getId().getId();
         }
         mDelegate.getModel().reorderBookmarks(mCurrentFolder, newOrder);
+        if (mDragStateDelegate.getDragActive()) {
+            RecordUserAction.record("MobileBookmarkManagerDragReorder");
+            mDragReorderCount++;
+        } else {
+            mMoveButtonCount++;
+        }
     }
 
     private int getBookmarkItemStartIndex() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java
index 185de683..e36890f2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java
@@ -9,10 +9,12 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
+import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
 import android.util.AttributeSet;
+import android.view.View;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.util.ViewUtils;
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
 import org.chromium.chrome.browser.widget.tile.TileWithTextView;
 
@@ -29,9 +31,9 @@
     public ExploreSitesTileView(Context ctx, AttributeSet attrs) {
         super(ctx, attrs);
         TypedArray styleAttrs = ctx.obtainStyledAttributes(attrs, R.styleable.ExploreSitesTileView);
-        mIconCornerRadius =
-                styleAttrs.getDimensionPixelSize(R.styleable.ExploreSitesTileView_iconCornerRadius,
-                        ViewUtils.DEFAULT_FAVICON_CORNER_RADIUS);
+        mIconCornerRadius = styleAttrs.getDimensionPixelSize(
+                R.styleable.ExploreSitesTileView_iconCornerRadius,
+                getResources().getDimensionPixelSize(R.dimen.default_favicon_corner_radius));
         styleAttrs.recycle();
     }
 
@@ -51,6 +53,20 @@
         if (image == null) {
             return new BitmapDrawable(getResources(), mIconGenerator.generateIconForText(text));
         }
-        return ViewUtils.createRoundedBitmapDrawable(image, mIconCornerRadius);
+        // Icon corner radius must be scaled to the current size of the image from the final size,
+        // because an arbitrary sized icon may be passed to the RoundedBitmapDrawableFactory, which
+        // expects the radius to be scaled to the image being passed in, not the final view. This is
+        // why we cannot use ViewUtils.createRoundedBitmapDrawable.
+        float scaledIconCornerRadius;
+        float iconSize = View.MeasureSpec.getSize(mIconView.getLayoutParams().width);
+        if (iconSize == 0) {
+            scaledIconCornerRadius = mIconCornerRadius;
+        } else {
+            scaledIconCornerRadius = image.getWidth() / iconSize * mIconCornerRadius;
+        }
+        RoundedBitmapDrawable roundedIcon =
+                RoundedBitmapDrawableFactory.create(getResources(), image);
+        roundedIcon.setCornerRadius(scaledIconCornerRadius);
+        return roundedIcon;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/OWNERS
new file mode 100644
index 0000000..b3445f9
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/OWNERS
@@ -0,0 +1,5 @@
+jinsukkim@chromium.org
+
+# TEAM: chrome-android-app@chromium.org
+# COMPONENT: UI>Browser>Mobile
+# OS: Android
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/PackageMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/PackageMetrics.java
index 4a04da30..ec1727f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/PackageMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/PackageMetrics.java
@@ -66,7 +66,7 @@
                     pmd.codeSize += storageStats.getAppBytes();
                     pmd.dataSize += (storageStats.getDataBytes() - storageStats.getCacheBytes());
                     pmd.cacheSize += storageStats.getCacheBytes();
-                } catch (IOException | NameNotFoundException ex) {
+                } catch (IOException | NameNotFoundException | SecurityException ex) {
                     Log.e(TAG, "Error calling into queryStatsForPackage", ex);
                 }
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/scheduler/DisplayAgent.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/scheduler/DisplayAgent.java
index e3a202a..1bb5fa8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/scheduler/DisplayAgent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/scheduler/DisplayAgent.java
@@ -48,6 +48,8 @@
             "org.chromium.chrome.browser.notifications.scheduler.EXTRA_GUID";
     private static final String EXTRA_ACTION_BUTTON_TYPE =
             "org.chromium.chrome.browser.notifications.scheduler.EXTRA_ACTION_BUTTON_TYPE";
+    private static final String EXTRA_ACTION_BUTTON_ID =
+            "org.chromium.chrome.browser.notifications.scheduler.EXTRA_ACTION_BUTTON_ID";
     private static final String EXTRA_SCHEDULER_CLIENT_TYPE =
             "org.chromium.chrome.browser.notifications.scheduler.EXTRA_SCHEDULER_CLIENT_TYPE ";
 
@@ -150,16 +152,19 @@
             case NotificationIntentInterceptor.IntentType.UNKNOWN:
                 break;
             case NotificationIntentInterceptor.IntentType.CONTENT_INTENT:
-                nativeOnContentClick(Profile.getLastUsedProfile(), clientType, guid);
+                nativeOnUserAction(Profile.getLastUsedProfile(), clientType, UserActionType.CLICK,
+                        guid, ActionButtonType.UNKNOWN_ACTION, null);
                 break;
             case NotificationIntentInterceptor.IntentType.DELETE_INTENT:
-                nativeOnDismiss(Profile.getLastUsedProfile(), clientType, guid);
+                nativeOnUserAction(Profile.getLastUsedProfile(), clientType, UserActionType.DISMISS,
+                        guid, ActionButtonType.UNKNOWN_ACTION, null);
                 break;
             case NotificationIntentInterceptor.IntentType.ACTION_INTENT:
                 int actionButtonType = IntentUtils.safeGetIntExtra(
                         intent, EXTRA_ACTION_BUTTON_TYPE, ActionButtonType.UNKNOWN_ACTION);
-                nativeOnActionButton(
-                        Profile.getLastUsedProfile(), clientType, guid, actionButtonType);
+                String buttonId = IntentUtils.safeGetStringExtra(intent, EXTRA_ACTION_BUTTON_ID);
+                nativeOnUserAction(Profile.getLastUsedProfile(), clientType,
+                        UserActionType.BUTTON_CLICK, guid, actionButtonType, buttonId);
                 break;
         }
     }
@@ -228,6 +233,7 @@
             Intent actionIntent = buildIntent(
                     context, NotificationIntentInterceptor.IntentType.ACTION_INTENT, systemData);
             actionIntent.putExtra(EXTRA_ACTION_BUTTON_TYPE, button.type);
+            actionIntent.putExtra(EXTRA_ACTION_BUTTON_ID, button.id);
 
             // TODO(xingliu): Support button icon. See https://crbug.com/983354
             builder.addAction(0 /*icon_id*/, button.text,
@@ -257,10 +263,7 @@
 
     private DisplayAgent() {}
 
-    private static native void nativeOnContentClick(
-            Profile profile, @SchedulerClientType int type, String guid);
-    private static native void nativeOnDismiss(
-            Profile profile, @SchedulerClientType int type, String guid);
-    private static native void nativeOnActionButton(Profile profile,
-            @SchedulerClientType int clientType, String guid, @ActionButtonType int type);
+    private static native void nativeOnUserAction(Profile profile,
+            @SchedulerClientType int clientType, @UserActionType int actionType, String guid,
+            @ActionButtonType int type, String buttonId);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
index ab83853..696aa67 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.offlinepages;
 
 import android.app.Activity;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Environment;
@@ -14,6 +15,7 @@
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.Callback;
+import org.chromium.base.ContentUriUtils;
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
@@ -538,6 +540,11 @@
         AsyncTask<Uri> task = new AsyncTask<Uri>() {
             @Override
             protected Uri doInBackground() {
+                // Android Q+: If we already have a content URI for the published page, return that.
+                if (ContentUriUtils.isContentUri(offlinePath)) {
+                    return Uri.parse(offlinePath);
+                }
+
                 // If we have a content or file URI, we will not have a filename, just return the
                 // URI.
                 if (offlinePath.isEmpty()) {
@@ -545,15 +552,32 @@
                     assert(isSchemeContentOrFile(uri));
                     return uri;
                 }
-                return ChromeFileProvider.generateUri(activity, offlinePageFile);
+
+                // TODO(985699): Investigate why we sometimes aren't able to generate URIs for files
+                // in external storage.
+                Uri generatedUri;
+                try {
+                    generatedUri = ChromeFileProvider.generateUri(activity, offlinePageFile);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, "Couldn't generate URI for sharing page: " + e);
+                    generatedUri = Uri.parse(pageUrl);
+                }
+                return generatedUri;
             }
             @Override
             protected void onPostExecute(Uri uri) {
-                ShareParams shareParams = new ShareParams.Builder(activity, pageTitle, pageUrl)
-                                                  .setShareDirectly(false)
-                                                  .setOfflineUri(uri)
-                                                  .build();
-                shareCallback.onResult(shareParams);
+                ShareParams.Builder builder = new ShareParams.Builder(activity, pageTitle, pageUrl)
+                                                      .setShareDirectly(false);
+                // Only try to share the offline page if we have a content URI making the actual
+                // file available.
+                // TODO(985699): Sharing the page's online URL is a temporary fix for crashes when
+                // sharing the archive's content URI. Once the root cause is addressed, the offline
+                // URI should always be set.
+                if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+                    builder = builder.setOfflineUri(uri);
+                }
+
+                shareCallback.onResult(builder.build());
             }
         };
         task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/themes/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/preferences/themes/OWNERS
index 926f19c3..12b79e1c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/themes/OWNERS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/themes/OWNERS
@@ -1,5 +1,4 @@
 twellington@chromium.org
-huayinz@chromium.org
 
 # TEAM: chrome-android-app@chromium.org
 # COMPONENT: UI>Browser>Mobile>Settings
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index e7b25360..10abbec 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -269,9 +269,6 @@
       <message name="IDS_MENU_ITEM_MOVE_TO_TOP" desc="Option in item menu. User can click the 'Move to top' option to move the item up to the top of its list. [CHAR-LIMIT=24]">
         Move to top
       </message>
-      <message name="IDS_MENU_ITEM_MOVE_TO_BOTTOM" desc="Option in item menu. User can click the 'Move to bottom' option to move the item down to the bottom of its list. [CHAR-LIMIT=24]">
-        Move to bottom
-      </message>
 
       <!-- Main Preferences -->
       <message name="IDS_PREFERENCES" desc="Title for Chrome's Settings.">
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_MENU_ITEM_MOVE_TO_BOTTOM.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_MENU_ITEM_MOVE_TO_BOTTOM.png.sha1
deleted file mode 100644
index 31f939e..0000000
--- a/chrome/android/java/strings/android_chrome_strings_grd/IDS_MENU_ITEM_MOVE_TO_BOTTOM.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-026ad1d1f203dccaf9e877daea1ea03b33393124
\ No newline at end of file
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index 1e6ebe1..fcb67c0 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -462,7 +462,7 @@
       "//chromeos/services/multidevice_setup/public/cpp:manifest",
       "//chromeos/services/multidevice_setup/public/mojom",
       "//chromeos/services/network_config/public/mojom",
-      "//media/capture/video/chromeos/mojo:cros_camera",
+      "//media/capture/video/chromeos/mojom:cros_camera",
     ]
 
     if (enable_cros_assistant) {
@@ -612,7 +612,6 @@
   if (is_chromeos) {
     deps += [
       "//ash/public/cpp:manifest",
-      "//chrome/services/cups_ipp_parser/public/cpp:manifest",
       "//chromeos/services/cellular_setup/public/cpp:manifest",
       "//chromeos/services/ime/public/cpp:manifest",
       "//chromeos/services/network_config/public/cpp:manifest",
diff --git a/chrome/app/DEPS b/chrome/app/DEPS
index 9294552..7ae6470 100644
--- a/chrome/app/DEPS
+++ b/chrome/app/DEPS
@@ -62,7 +62,7 @@
     "+components/translate/content/common",
     "+extensions/buildflags",
     "+extensions/common",
-    "+media/capture/video/chromeos/mojo",
+    "+media/capture/video/chromeos/mojom",
     "+services/identity",
     "+services/image_annotation/public",
     "+services/resource_coordinator/public",
@@ -82,7 +82,6 @@
     "+third_party/blink/public/mojom",
   ],
   "builtin_service_manifests\.cc": [
-    "+chrome/services/cups_ipp_parser/public",
     "+chrome/services/file_util/public",
     "+chrome/services/isolated_xr_device/manifest.h",
     "+chrome/services/media_gallery_util/public",
diff --git a/chrome/app/builtin_service_manifests.cc b/chrome/app/builtin_service_manifests.cc
index 1b2ebe7..fbc31424 100644
--- a/chrome/app/builtin_service_manifests.cc
+++ b/chrome/app/builtin_service_manifests.cc
@@ -20,7 +20,6 @@
 
 #if defined(OS_CHROMEOS)
 #include "ash/public/cpp/manifest.h"
-#include "chrome/services/cups_ipp_parser/public/cpp/manifest.h"  // nogncheck
 #include "chromeos/services/cellular_setup/public/cpp/manifest.h"
 #include "chromeos/services/ime/public/cpp/manifest.h"
 #include "chromeos/services/network_config/public/cpp/manifest.h"
@@ -137,7 +136,6 @@
       chromeos::ime::GetManifest(),
       chromeos::network_config::GetManifest(),
       chromeos::secure_channel::GetManifest(),
-      GetCupsIppParserManifest(),
 #endif
   }};
   return *manifests;
diff --git a/chrome/app/chrome_content_browser_overlay_manifest.cc b/chrome/app/chrome_content_browser_overlay_manifest.cc
index ea98854..df6bad12 100644
--- a/chrome/app/chrome_content_browser_overlay_manifest.cc
+++ b/chrome/app/chrome_content_browser_overlay_manifest.cc
@@ -60,7 +60,7 @@
 #include "chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
 #include "chromeos/services/network_config/public/mojom/constants.mojom.h"  // nogncheck
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"  // nogncheck
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #if BUILDFLAG(ENABLE_CROS_ASSISTANT)
 #include "chromeos/services/assistant/public/cpp/manifest.h"  // nogncheck
 #endif
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 86a9fc8..75fc5c9 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -12,7 +12,6 @@
   "+chrome/installer/util",
   "+chrome/notification_helper/notification_helper_constants.h",
   "+chrome/services/app_service/public/mojom",
-  "+chrome/services/cups_ipp_parser/public",
   "+chrome/services/cups_proxy",
   "+chrome/services/diagnosticsd/public",
   "+chrome/services/file_util/public",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 817af2b1..3c99d42 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -782,8 +782,12 @@
     {OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "5"}};
 const FeatureEntry::FeatureParam kOmniboxUIMaxAutocompleteMatches6[] = {
     {OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "6"}};
+const FeatureEntry::FeatureParam kOmniboxUIMaxAutocompleteMatches7[] = {
+    {OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "7"}};
 const FeatureEntry::FeatureParam kOmniboxUIMaxAutocompleteMatches8[] = {
     {OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "8"}};
+const FeatureEntry::FeatureParam kOmniboxUIMaxAutocompleteMatches9[] = {
+    {OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "9"}};
 const FeatureEntry::FeatureParam kOmniboxUIMaxAutocompleteMatches10[] = {
     {OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam, "10"}};
 const FeatureEntry::FeatureParam kOmniboxUIMaxAutocompleteMatches12[] = {
@@ -799,8 +803,12 @@
          base::size(kOmniboxUIMaxAutocompleteMatches5), nullptr},
         {"6 matches", kOmniboxUIMaxAutocompleteMatches6,
          base::size(kOmniboxUIMaxAutocompleteMatches6), nullptr},
+        {"7 matches", kOmniboxUIMaxAutocompleteMatches7,
+         base::size(kOmniboxUIMaxAutocompleteMatches7), nullptr},
         {"8 matches", kOmniboxUIMaxAutocompleteMatches8,
          base::size(kOmniboxUIMaxAutocompleteMatches8), nullptr},
+        {"9 matches", kOmniboxUIMaxAutocompleteMatches9,
+         base::size(kOmniboxUIMaxAutocompleteMatches9), nullptr},
         {"10 matches", kOmniboxUIMaxAutocompleteMatches10,
          base::size(kOmniboxUIMaxAutocompleteMatches10), nullptr},
         {"12 matches", kOmniboxUIMaxAutocompleteMatches12,
@@ -2743,7 +2751,7 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(
          omnibox::kUIExperimentMaxAutocompleteMatches,
          kOmniboxUIMaxAutocompleteMatchesVariations,
-         "OmniboxUIMaxAutocompleteVariations")},
+         "OmniboxBundledExperimentV1")},
 
     {"omnibox-max-url-matches", flag_descriptions::kOmniboxMaxURLMatchesName,
      flag_descriptions::kOmniboxMaxURLMatchesDescription, kOsAll,
@@ -2789,6 +2797,11 @@
      kOsDesktop,
      FEATURE_VALUE_TYPE(omnibox::kOmniboxMaterialDesignWeatherIcons)},
 
+    {"omnibox-disable-instant-extended-limit",
+     flag_descriptions::kOmniboxDisableInstantExtendedLimitName,
+     flag_descriptions::kOmniboxDisableInstantExtendedLimitDescription, kOsAll,
+     FEATURE_VALUE_TYPE(omnibox::kOmniboxDisableInstantExtendedLimit)},
+
     {"use-new-accept-language-header",
      flag_descriptions::kUseNewAcceptLanguageHeaderName,
      flag_descriptions::kUseNewAcceptLanguageHeaderDescription, kOsAll,
diff --git a/chrome/browser/android/download/download_controller.cc b/chrome/browser/android/download/download_controller.cc
index f9a58d1..042aa84 100644
--- a/chrome/browser/android/download/download_controller.cc
+++ b/chrome/browser/android/download/download_controller.cc
@@ -66,12 +66,11 @@
 // Guards download_controller_
 base::LazyInstance<base::Lock>::DestructorAtExit g_download_controller_lock_;
 
-void CreateContextMenuDownload(
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-    const content::ContextMenuParams& params,
-    bool is_link,
-    const std::string& extra_headers,
-    bool granted) {
+void CreateContextMenuDownload(const content::WebContents::Getter& wc_getter,
+                               const content::ContextMenuParams& params,
+                               bool is_link,
+                               const std::string& extra_headers,
+                               bool granted) {
   content::WebContents* web_contents = wc_getter.Run();
   if (!granted)
     return;
@@ -151,7 +150,7 @@
 }
 
 void OnRequestFileAccessResult(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const content::WebContents::Getter& web_contents_getter,
     DownloadControllerBase::AcquireFileAccessPermissionCallback cb,
     bool granted,
     const std::string& permission_to_update) {
@@ -251,7 +250,7 @@
 DownloadController::~DownloadController() = default;
 
 void DownloadController::AcquireFileAccessPermission(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const content::WebContents::Getter& web_contents_getter,
     DownloadControllerBase::AcquireFileAccessPermissionCallback cb) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -285,7 +284,7 @@
 }
 
 void DownloadController::CreateAndroidDownload(
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const DownloadInfo& info) {
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::UI},
@@ -315,7 +314,7 @@
 }
 
 void DownloadController::StartAndroidDownload(
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const DownloadInfo& info) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -325,8 +324,9 @@
 }
 
 void DownloadController::StartAndroidDownloadInternal(
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-    const DownloadInfo& info, bool allowed) {
+    const content::WebContents::Getter& wc_getter,
+    const DownloadInfo& info,
+    bool allowed) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!allowed)
     return;
@@ -476,7 +476,7 @@
   int process_id = web_contents->GetRenderViewHost()->GetProcess()->GetID();
   int routing_id = web_contents->GetRenderViewHost()->GetRoutingID();
 
-  const content::ResourceRequestInfo::WebContentsGetter& wc_getter(
+  const content::WebContents::Getter& wc_getter(
       base::Bind(&GetWebContents, process_id, routing_id));
 
   AcquireFileAccessPermission(
diff --git a/chrome/browser/android/download/download_controller.h b/chrome/browser/android/download/download_controller.h
index 24159ce..0b71533 100644
--- a/chrome/browser/android/download/download_controller.h
+++ b/chrome/browser/android/download/download_controller.h
@@ -27,21 +27,16 @@
 #include "base/memory/singleton.h"
 #include "chrome/browser/android/download/download_controller_base.h"
 
-namespace content {
-class WebContents;
-}
-
 class DownloadController : public DownloadControllerBase {
  public:
   static DownloadController* GetInstance();
 
   // DownloadControllerBase implementation.
   void AcquireFileAccessPermission(
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       AcquireFileAccessPermissionCallback callback) override;
-  void CreateAndroidDownload(
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const DownloadInfo& info) override;
+  void CreateAndroidDownload(const content::WebContents::Getter& wc_getter,
+                             const DownloadInfo& info) override;
   void AboutToResumeDownload(download::DownloadItem* download_item) override;
 
   // UMA histogram enum for download cancellation reasons. Keep this
@@ -102,12 +97,12 @@
   void OnDangerousDownload(download::DownloadItem* item);
 
   // Helper methods to start android download on UI thread.
-  void StartAndroidDownload(
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const DownloadInfo& info);
+  void StartAndroidDownload(const content::WebContents::Getter& wc_getter,
+                            const DownloadInfo& info);
   void StartAndroidDownloadInternal(
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const DownloadInfo& info, bool allowed);
+      const content::WebContents::Getter& wc_getter,
+      const DownloadInfo& info,
+      bool allowed);
 
   // Check if an interrupted download item can be auto resumed.
   bool IsInterruptedDownloadAutoResumable(
diff --git a/chrome/browser/android/download/download_controller_base.cc b/chrome/browser/android/download/download_controller_base.cc
index 3b2b105..047ea34 100644
--- a/chrome/browser/android/download/download_controller_base.cc
+++ b/chrome/browser/android/download/download_controller_base.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/android/download/download_controller_base.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "content/public/browser/render_view_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 #include "net/url_request/url_request.h"
 
@@ -28,8 +27,6 @@
 // static
 DownloadControllerBase* DownloadControllerBase::download_controller_ = nullptr;
 
-using content::ResourceRequestInfo;
-
 DownloadInfo::DownloadInfo(const GURL& url,
                            const GURL& original_url,
                            const std::string& content_disposition,
diff --git a/chrome/browser/android/download/download_controller_base.h b/chrome/browser/android/download/download_controller_base.h
index db811f9..110d9e7 100644
--- a/chrome/browser/android/download/download_controller_base.h
+++ b/chrome/browser/android/download/download_controller_base.h
@@ -10,7 +10,7 @@
 #include "base/callback.h"
 #include "components/download/public/common/download_item.h"
 #include "components/download/public/common/download_start_observer.h"
-#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/context_menu_params.h"
 #include "net/http/http_content_disposition.h"
 #include "net/http/http_request_headers.h"
@@ -77,7 +77,7 @@
   // Called to prompt the user for file access permission. When finished,
   // |callback| will be executed.
   virtual void AcquireFileAccessPermission(
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       AcquireFileAccessPermissionCallback callback) = 0;
 
   // Called by unit test to approve or disapprove file access request.
@@ -86,7 +86,7 @@
   // Starts a new download request with Android DownloadManager. Can be called
   // on any thread.
   virtual void CreateAndroidDownload(
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const DownloadInfo& info) = 0;
 
   // Called before resuming a download.
diff --git a/chrome/browser/android/download/mock_download_controller.cc b/chrome/browser/android/download/mock_download_controller.cc
index abae54c..d87f38b 100644
--- a/chrome/browser/android/download/mock_download_controller.cc
+++ b/chrome/browser/android/download/mock_download_controller.cc
@@ -29,7 +29,7 @@
 }
 
 void MockDownloadController::AcquireFileAccessPermission(
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     DownloadControllerBase::AcquireFileAccessPermissionCallback cb) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::BindOnce(std::move(cb), approve_file_access_request_));
@@ -41,7 +41,7 @@
 }
 
 void MockDownloadController::CreateAndroidDownload(
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const DownloadInfo& info) {}
 
 void MockDownloadController::AboutToResumeDownload(
diff --git a/chrome/browser/android/download/mock_download_controller.h b/chrome/browser/android/download/mock_download_controller.h
index 0a85328..346c3425 100644
--- a/chrome/browser/android/download/mock_download_controller.h
+++ b/chrome/browser/android/download/mock_download_controller.h
@@ -12,14 +12,6 @@
 #include "base/memory/singleton.h"
 #include "chrome/browser/android/download/download_controller_base.h"
 
-namespace content {
-class WebContents;
-}  // namespace content
-
-namespace download {
-class DownloadItem;
-}
-
 namespace chrome {
 namespace android {
 
@@ -36,12 +28,11 @@
       content::WebContents* web_contents,
       bool is_link, const std::string& extra_headers) override;
   void AcquireFileAccessPermission(
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       AcquireFileAccessPermissionCallback callback) override;
   void SetApproveFileAccessRequestForTesting(bool approve) override;
-  void CreateAndroidDownload(
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const DownloadInfo& info) override;
+  void CreateAndroidDownload(const content::WebContents::Getter& wc_getter,
+                             const DownloadInfo& info) override;
   void AboutToResumeDownload(download::DownloadItem* download_item) override;
 
  private:
diff --git a/chrome/browser/apps/app_service/app_icon_source.cc b/chrome/browser/apps/app_service/app_icon_source.cc
index d8d517e..1b9c873 100644
--- a/chrome/browser/apps/app_service/app_icon_source.cc
+++ b/chrome/browser/apps/app_service/app_icon_source.cc
@@ -58,7 +58,7 @@
 
 void AppIconSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   std::string path_lower = base::ToLowerASCII(path);
   std::vector<std::string> path_parts = base::SplitString(
diff --git a/chrome/browser/apps/app_service/app_icon_source.h b/chrome/browser/apps/app_service/app_icon_source.h
index 345a33a..7db8b0ca0 100644
--- a/chrome/browser/apps/app_service/app_icon_source.h
+++ b/chrome/browser/apps/app_service/app_icon_source.h
@@ -38,7 +38,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string&) override;
   bool AllowCaching() override;
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index 9357921..fad5615 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -251,7 +251,7 @@
 
 void BackgroundFetchDelegateImpl::GetPermissionForOrigin(
     const url::Origin& origin,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     GetPermissionForOriginCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.h b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
index 2ba849e..c117967 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.h
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
@@ -54,10 +54,9 @@
 
   // BackgroundFetchDelegate implementation:
   void GetIconDisplaySize(GetIconDisplaySizeCallback callback) override;
-  void GetPermissionForOrigin(
-      const url::Origin& origin,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      GetPermissionForOriginCallback callback) override;
+  void GetPermissionForOrigin(const url::Origin& origin,
+                              const content::WebContents::Getter& wc_getter,
+                              GetPermissionForOriginCallback callback) override;
   void CreateDownloadJob(base::WeakPtr<Client> client,
                          std::unique_ptr<content::BackgroundFetchDescription>
                              fetch_description) override;
diff --git a/chrome/browser/banners/app_banner_manager_desktop.cc b/chrome/browser/banners/app_banner_manager_desktop.cc
index affc058..9172901 100644
--- a/chrome/browser/banners/app_banner_manager_desktop.cc
+++ b/chrome/browser/banners/app_banner_manager_desktop.cc
@@ -128,7 +128,6 @@
 void AppBannerManagerDesktop::ShowBannerUi(WebappInstallSource install_source) {
   RecordDidShowBanner("AppBanner.WebApp.Shown");
   TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_CREATED);
-  TrackUserResponse(USER_RESPONSE_WEB_APP_ACCEPTED);
   ReportStatus(SHOWING_APP_INSTALLATION_DIALOG);
   CreateWebApp(install_source);
 }
@@ -187,25 +186,19 @@
   if (!contents)
     return;
 
-  // BookmarkAppInstallManager returns kFailedUnknownReason for any error.
-  // We can't distinguish kUserInstallDeclined case so far.
-  // If kFailedUnknownReason, we assume that the confirmation dialog was
-  // cancelled. Alternatively, the web app installation may have failed, but
-  // we can't tell the difference here.
-  // TODO(crbug.com/789381): plumb through enough information to be able to
-  // distinguish between extension install failures and user-cancellations of
-  // the app install dialog.
-  if (code != web_app::InstallResultCode::kSuccess) {
+  // Catch only kSuccess and kUserInstallDeclined. Report nothing on all other
+  // errors.
+  if (code == web_app::InstallResultCode::kSuccess) {
+    SendBannerAccepted();
+    TrackUserResponse(USER_RESPONSE_WEB_APP_ACCEPTED);
+    AppBannerSettingsHelper::RecordBannerInstallEvent(
+        contents, GetAppIdentifier(), AppBannerSettingsHelper::WEB);
+  } else if (code == web_app::InstallResultCode::kUserInstallDeclined) {
     SendBannerDismissed();
     TrackUserResponse(USER_RESPONSE_WEB_APP_DISMISSED);
     AppBannerSettingsHelper::RecordBannerDismissEvent(
         contents, GetAppIdentifier(), AppBannerSettingsHelper::WEB);
-    return;
   }
-
-  SendBannerAccepted();
-  AppBannerSettingsHelper::RecordBannerInstallEvent(
-      contents, GetAppIdentifier(), AppBannerSettingsHelper::WEB);
 }
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(AppBannerManagerDesktop)
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index fa58465..dbae0a5c 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -612,11 +612,6 @@
 #include "chrome/browser/supervised_user/supervised_user_navigation_throttle.h"
 #endif
 
-#if BUILDFLAG(ENABLE_PRINTING) && defined(OS_CHROMEOS)
-// TODO(crbug.com/948800): Doesn't match BUILD.gn of use_cups && is_chromeos.
-#include "chrome/services/cups_ipp_parser/public/mojom/constants.mojom.h"
-#endif
-
 #if BUILDFLAG(FULL_SAFE_BROWSING)
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
 #endif
@@ -1014,11 +1009,10 @@
   return prerender::PrerenderContents::FromWebContents(web_contents);
 }
 
-void LaunchURL(
-    const GURL& url,
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
-    ui::PageTransition page_transition,
-    bool has_user_gesture) {
+void LaunchURL(const GURL& url,
+               const content::WebContents::Getter& web_contents_getter,
+               ui::PageTransition page_transition,
+               bool has_user_gesture) {
   // If there is no longer a WebContents, the request may have raced with tab
   // closing. Don't fire the external request. (It may have been a prerender.)
   content::WebContents* web_contents = web_contents_getter.Run();
@@ -5228,7 +5222,7 @@
 
 bool ChromeContentBrowserClient::HandleExternalProtocol(
     const GURL& url,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    content::WebContents::Getter web_contents_getter,
     int child_id,
     content::NavigationUIData* navigation_data,
     bool is_main_frame,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index c3fe3087..b1337c1 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -534,7 +534,7 @@
       LoginAuthRequiredCallback auth_required_callback) override;
   bool HandleExternalProtocol(
       const GURL& url,
-      content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+      content::WebContents::Getter web_contents_getter,
       int child_id,
       content::NavigationUIData* navigation_data,
       bool is_main_frame,
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
index b2c8ebd..5571690 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -721,10 +721,9 @@
 
   // content::URLDataSource:
   std::string GetSource() override { return source_; }
-  void StartDataRequest(
-      const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const GotDataCallback& callback) override {
+  void StartDataRequest(const std::string& path,
+                        const content::WebContents::Getter& wc_getter,
+                        const GotDataCallback& callback) override {
     std::string data(content_);
     callback.Run(base::RefCountedString::TakeString(&data));
   }
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.cc b/chrome/browser/chromeos/input_method/input_method_engine.cc
index 9d3b895..171777b 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine.cc
@@ -281,32 +281,22 @@
 
 void InputMethodEngine::CommitTextToInputContext(int context_id,
                                                  const std::string& text) {
-  bool committed = false;
   ui::IMEInputContextHandlerInterface* input_context =
       ui::IMEBridge::Get()->GetInputContextHandler();
-  if (input_context) {
-    input_context->CommitText(text);
-    committed = true;
-  }
+  if (!input_context)
+    return;
 
-  if (committed && !composition_text_->text.empty()) {
-    // Records histograms for committed characters.
+  const bool had_composition_text = input_context->HasCompositionText();
+  input_context->CommitText(text);
+
+  if (had_composition_text) {
+    // Records histograms for committed characters with composition text.
     base::string16 wtext = base::UTF8ToUTF16(text);
     UMA_HISTOGRAM_CUSTOM_COUNTS("InputMethod.CommitLength", wtext.length(), 1,
                                 25, 25);
-    composition_text_.reset(new ui::CompositionText());
   }
 }
 
-void InputMethodEngine::DeleteSurroundingTextToInputContext(
-    int offset,
-    size_t number_of_chars) {
-  ui::IMEInputContextHandlerInterface* input_context =
-      ui::IMEBridge::Get()->GetInputContextHandler();
-  if (input_context)
-    input_context->DeleteSurroundingText(offset, number_of_chars);
-}
-
 bool InputMethodEngine::SendKeyEvent(ui::KeyEvent* event,
                                      const std::string& code) {
   DCHECK(event);
@@ -330,15 +320,6 @@
   return false;
 }
 
-void InputMethodEngine::ConfirmCompositionText() {
-  ui::IMEInputContextHandlerInterface* input_context =
-      ui::IMEBridge::Get()->GetInputContextHandler();
-  if (input_context) {
-    input_context->ConfirmCompositionText();
-    composition_text_.reset(new ui::CompositionText());
-  }
-}
-
 void InputMethodEngine::EnableInputView() {
   input_method::InputMethodManager::Get()
       ->GetActiveIMEState()
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.h b/chrome/browser/chromeos/input_method/input_method_engine.h
index 8465090..eb2195c 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.h
+++ b/chrome/browser/chromeos/input_method/input_method_engine.h
@@ -139,10 +139,7 @@
       const std::vector<ui::ImeTextSpan>& text_spans) override;
   void CommitTextToInputContext(int context_id,
                                 const std::string& text) override;
-  void DeleteSurroundingTextToInputContext(int offset,
-                                           size_t number_of_chars) override;
   bool SendKeyEvent(ui::KeyEvent* event, const std::string& code) override;
-  void ConfirmCompositionText() override;
 
   // Enables overriding input view page to Virtual Keyboard window.
   void EnableInputView();
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc b/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc
index 8f5c73f5..bd805559 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_browsertests.cc
@@ -1039,17 +1039,19 @@
 
     InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
         kIdentityIMEID, false /* show_message */);
+    EXPECT_EQ(1, mock_input_context->commit_text_call_count());
     EXPECT_EQ("us", mock_input_context->last_commit_text());
 
+    // Should not call CommitText anymore.
     InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
         extension_ime_util::GetInputMethodIDByEngineID("zh-t-i0-pinyin"),
         false /* show_message */);
-    EXPECT_EQ("", mock_input_context->last_commit_text());
+    EXPECT_EQ(1, mock_input_context->commit_text_call_count());
 
     InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod(
         extension_ime_util::GetInputMethodIDByEngineID("xkb:us::eng"),
         false /* show_message */);
-    EXPECT_EQ("", mock_input_context->last_commit_text());
+    EXPECT_EQ(1, mock_input_context->commit_text_call_count());
   }
 
   ui::IMEBridge::Get()->SetInputContextHandler(nullptr);
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc b/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
index 4adf824b..691aa45 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_unittest.cc
@@ -318,10 +318,13 @@
                       &error);
   engine_->SetComposition(context, "test", 0, 0, 0, segments, nullptr);
   engine_->CommitText(context, "input\xE5\x85\xA5\xE5\x8A\x9B", &error);
-  histograms.ExpectTotalCount("InputMethod.CommitLength", 3);
+  // This one shouldn't be counted because there was no composition.
+  engine_->CommitText(context, "abc", &error);
+  histograms.ExpectTotalCount("InputMethod.CommitLength", 4);
   histograms.ExpectBucketCount("InputMethod.CommitLength", 5, 1);
   histograms.ExpectBucketCount("InputMethod.CommitLength", 2, 1);
   histograms.ExpectBucketCount("InputMethod.CommitLength", 7, 1);
+  histograms.ExpectBucketCount("InputMethod.CommitLength", 3, 1);
 }
 
 TEST_F(InputMethodEngineTest, TestCompositionBoundsChanged) {
diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_manager.h b/chrome/browser/chromeos/login/signin/oauth2_login_manager.h
index 8782cc0..b4720b9 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_login_manager.h
+++ b/chrome/browser/chromeos/login/signin/oauth2_login_manager.h
@@ -196,8 +196,6 @@
   static void RecordCookiesCheckOutcome(bool is_pre_merge,
                                         MergeVerificationOutcome outcome);
 
-  // Keeps the track if we have already reported OAuth2 token being loaded
-  // by OAuth2TokenService.
   Profile* user_profile_;
   SessionRestoreStrategy restore_strategy_;
   SessionRestoreState state_;
diff --git a/chrome/browser/chromeos/policy/android_management_client.h b/chrome/browser/chromeos/policy/android_management_client.h
index 3d1b8b55..2f65138 100644
--- a/chrome/browser/chromeos/policy/android_management_client.h
+++ b/chrome/browser/chromeos/policy/android_management_client.h
@@ -35,7 +35,7 @@
 namespace policy {
 
 // Interacts with the device management service and determines whether Android
-// management is enabled for the user or not. Uses the OAuth2TokenService to
+// management is enabled for the user or not. Uses the IdentityManager to
 // acquire access tokens for the device management.
 class AndroidManagementClient {
  public:
diff --git a/chrome/browser/chromeos/policy/upload_job.h b/chrome/browser/chromeos/policy/upload_job.h
index 991db37..cab5682 100644
--- a/chrome/browser/chromeos/policy/upload_job.h
+++ b/chrome/browser/chromeos/policy/upload_job.h
@@ -18,12 +18,12 @@
 
 // UploadJob can be used to upload screenshots and logfiles to the cloud.
 // Data is uploaded via a POST request of type "multipart/form-data". The class
-// relies on OAuth2TokenService to acquire an access token with a sufficient
-// scope. Data segments can be added to the upload queue using AddDataSegment()
-// and the upload is started by calling Start(). Calls to AddDataSegment() are
-// only allowed prior to the first call to Start().
-// An Upload instance may be destroyed at any point in time, the pending
-// operations are guaranteed to be canceled and the Delegate::OnSuccess() and
+// relies on OAuth2AccessTokenManager to acquire an access token with a
+// sufficient scope. Data segments can be added to the upload queue using
+// AddDataSegment() and the upload is started by calling Start(). Calls to
+// AddDataSegment() are only allowed prior to the first call to Start(). An
+// Upload instance may be destroyed at any point in time, the pending operations
+// are guaranteed to be canceled and the Delegate::OnSuccess() and
 // Delegate::OnFailure() methods will not be invoked.
 class UploadJob {
  public:
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
index 9a45d9819..3b78efd 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
@@ -1040,8 +1040,8 @@
 class UserCloudPolicyManagerChromeOSChildTest
     : public UserCloudPolicyManagerChromeOSTest {
  public:
-  // Issues OAuthToken for device management scopes using OAuth2TokenService.
-  void IssueOAuthTokenWithTokenService(base::TimeDelta token_lifetime) {
+  // Issues OAuthToken for device management scopes.
+  void IssueOAuth2AccessToken(base::TimeDelta token_lifetime) {
     identity::ScopeSet scopes;
     scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
     scopes.insert(GaiaConstants::kOAuthWrapBridgeUserInfoScope);
@@ -1100,7 +1100,7 @@
   LoadStoreWithCachedData();
   EXPECT_FALSE(manager_->core()->refresh_scheduler());
 
-  IssueOAuthTokenWithTokenService(base::TimeDelta::FromSeconds(3600));
+  IssueOAuth2AccessToken(base::TimeDelta::FromSeconds(3600));
 
   EXPECT_TRUE(manager_->core()->refresh_scheduler());
 }
@@ -1113,7 +1113,7 @@
 
   // This starts refresh scheduler.
   const base::TimeDelta token_lifetime = base::TimeDelta::FromMinutes(50);
-  IssueOAuthTokenWithTokenService(token_lifetime);
+  IssueOAuth2AccessToken(token_lifetime);
 
   // First refresh is scheduled with delay of 0s - let it execute.
   FetchPolicy(
@@ -1133,7 +1133,7 @@
   for (int i = 0; i < iterations; ++i) {
     task_runner_->FastForwardBy(token_lifetime);
     refresh_delay -= token_lifetime;
-    IssueOAuthTokenWithTokenService(token_lifetime);
+    IssueOAuth2AccessToken(token_lifetime);
   }
 
   // Advance the clock by the remaining time to get scheduled policy refresh.
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
index af54fae..53bf416 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
@@ -366,7 +366,8 @@
       // This shouldn't happen: GetRefreshToken() is only called for actual
       // token minting operations. In above states, requests are either queued
       // or short-circuited to signal error immediately, so no actual token
-      // minting via OAuth2TokenService::FetchOAuth2Token should be triggered.
+      // minting via OAuth2AccessTokenManager::FetchOAuth2Token should be
+      // triggered.
       NOTREACHED();
       return std::string();
     case STATE_VALIDATION_PENDING:
diff --git a/chrome/browser/client_hints/client_hints_browsertest.cc b/chrome/browser/client_hints/client_hints_browsertest.cc
index bdabb5f35..c2380048 100644
--- a/chrome/browser/client_hints/client_hints_browsertest.cc
+++ b/chrome/browser/client_hints/client_hints_browsertest.cc
@@ -28,8 +28,10 @@
 #include "components/content_settings/core/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/web_preferences.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "content/public/test/url_loader_interceptor.h"
@@ -293,6 +295,16 @@
     expected_ect = effective_connection_type;
   }
 
+  void SetJsEnabledForActiveView(bool enabled) {
+    content::RenderViewHost* view = browser()
+                                        ->tab_strip_model()
+                                        ->GetActiveWebContents()
+                                        ->GetRenderViewHost();
+    content::WebPreferences prefs = view->GetWebkitPreferences();
+    prefs.javascript_enabled = enabled;
+    view->UpdateWebkitPreferences(prefs);
+  }
+
   const GURL& accept_ch_with_lifetime_http_local_url() const {
     return accept_ch_with_lifetime_http_local_url_;
   }
@@ -1440,7 +1452,21 @@
                               &host_settings);
   EXPECT_EQ(1u, host_settings.size());
 
-  // Block the Javascript: Client hints should not be attached.
+  // Block JavaScript via WebPreferences: Client hints should not be attached.
+  SetJsEnabledForActiveView(false);
+
+  SetClientHintExpectationsOnMainFrame(false);
+  SetClientHintExpectationsOnSubresources(false);
+  ui_test_utils::NavigateToURL(browser(),
+                               without_accept_ch_without_lifetime_url());
+
+  EXPECT_EQ(0u, count_client_hints_headers_seen());
+  VerifyContentSettingsNotNotified();
+  EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
+
+  SetJsEnabledForActiveView(true);
+
+  // Block JavaScript via ContentSetting: Client hints should not be attached.
   HostContentSettingsMapFactory::GetForProfile(browser()->profile())
       ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
                                       GURL(), CONTENT_SETTINGS_TYPE_JAVASCRIPT,
@@ -1451,7 +1477,7 @@
   VerifyContentSettingsNotNotified();
   EXPECT_EQ(1u, count_user_agent_hint_headers_seen());
 
-  // Allow the Javascript: Client hints should now be attached.
+  // Allow JavaScript: Client hints should now be attached.
   HostContentSettingsMapFactory::GetForProfile(browser()->profile())
       ->SetContentSettingDefaultScope(without_accept_ch_without_lifetime_url(),
                                       GURL(), CONTENT_SETTINGS_TYPE_JAVASCRIPT,
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 2124c5f..46f81c3e 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -2118,10 +2118,9 @@
 
   // content::URLDataSource:
   std::string GetSource() override { return source_; }
-  void StartDataRequest(
-      const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const GotDataCallback& callback) override {
+  void StartDataRequest(const std::string& path,
+                        const content::WebContents::Getter& wc_getter,
+                        const GotDataCallback& callback) override {
     std::string data(content_);
     callback.Run(base::RefCountedString::TakeString(&data));
   }
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index b91ace4..ce30a64 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -237,12 +237,11 @@
     base::OnceCallback<void(bool /* storage permission granted */,
                             bool /*allow*/)>;
 
-void CheckCanDownload(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
-    const GURL& url,
-    const std::string& request_method,
-    base::Optional<url::Origin> request_initiator,
-    CanDownloadCallback can_download_cb) {
+void CheckCanDownload(const content::WebContents::Getter& web_contents_getter,
+                      const GURL& url,
+                      const std::string& request_method,
+                      base::Optional<url::Origin> request_initiator,
+                      CanDownloadCallback can_download_cb) {
   DownloadRequestLimiter* limiter =
       g_browser_process->download_request_limiter();
   if (limiter) {
@@ -256,7 +255,7 @@
 // TODO(qinmin): reuse the similar function defined in
 // DownloadResourceThrottle.
 void OnDownloadAcquireFileAccessPermissionDone(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const content::WebContents::Getter& web_contents_getter,
     const GURL& url,
     const std::string& request_method,
     base::Optional<url::Origin> request_initiator,
@@ -1388,7 +1387,7 @@
 }
 
 void ChromeDownloadManagerDelegate::CheckDownloadAllowed(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const content::WebContents::Getter& web_contents_getter,
     const GURL& url,
     const std::string& request_method,
     base::Optional<url::Origin> request_initiator,
diff --git a/chrome/browser/download/chrome_download_manager_delegate.h b/chrome/browser/download/chrome_download_manager_delegate.h
index 35097f9f..c5b7b53 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.h
+++ b/chrome/browser/download/chrome_download_manager_delegate.h
@@ -120,8 +120,7 @@
       content::CheckForFileExistenceCallback callback) override;
   std::string ApplicationClientIdForFileScanning() override;
   void CheckDownloadAllowed(
-      const content::ResourceRequestInfo::WebContentsGetter&
-          web_contents_getter,
+      const content::WebContents::Getter& web_contents_getter,
       const GURL& url,
       const std::string& request_method,
       base::Optional<url::Origin> request_initiator,
diff --git a/chrome/browser/download/download_request_limiter.cc b/chrome/browser/download/download_request_limiter.cc
index 120964e..77ac016 100644
--- a/chrome/browser/download/download_request_limiter.cc
+++ b/chrome/browser/download/download_request_limiter.cc
@@ -509,7 +509,7 @@
 }
 
 void DownloadRequestLimiter::CanDownload(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const content::WebContents::Getter& web_contents_getter,
     const GURL& url,
     const std::string& request_method,
     base::Optional<url::Origin> request_initiator,
@@ -541,7 +541,7 @@
 }
 
 void DownloadRequestLimiter::OnCanDownloadDecided(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const content::WebContents::Getter& web_contents_getter,
     const std::string& request_method,
     base::Optional<url::Origin> request_initiator,
     Callback orig_callback,
diff --git a/chrome/browser/download/download_request_limiter.h b/chrome/browser/download/download_request_limiter.h
index ffbb4c6..e37acbb 100644
--- a/chrome/browser/download/download_request_limiter.h
+++ b/chrome/browser/download/download_request_limiter.h
@@ -20,7 +20,7 @@
 #include "base/scoped_observer.h"
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/common/content_settings.h"
-#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 
 class HostContentSettingsMap;
@@ -240,8 +240,7 @@
   GURL GetDownloadOrigin(content::WebContents* web_contents);
 
   // Check if download can proceed and notifies the callback on UI thread.
-  void CanDownload(const content::ResourceRequestInfo::WebContentsGetter&
-                       web_contents_getter,
+  void CanDownload(const content::WebContents::Getter& web_contents_getter,
                    const GURL& url,
                    const std::string& request_method,
                    base::Optional<url::Origin> request_initiator,
@@ -284,8 +283,7 @@
 
   // Invoked when decision to download has been made.
   void OnCanDownloadDecided(
-      const content::ResourceRequestInfo::WebContentsGetter&
-          web_contents_getter,
+      const content::WebContents::Getter& web_contents_getter,
       const std::string& request_method,
       base::Optional<url::Origin> request_initiator,
       Callback orig_callback,
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 3b6e53c..c9e1491f 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -996,7 +996,7 @@
       "//components/drive",
       "//components/user_manager",
       "//media/capture:capture_lib",
-      "//media/capture/video/chromeos/mojo:cros_camera",
+      "//media/capture/video/chromeos/mojom:cros_camera",
       "//remoting/base",
       "//remoting/host",
       "//remoting/host/it2me:chrome_os_host",
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index c303798e..5c4ad9c 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -51,7 +51,6 @@
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/content_switches.h"
 #include "extensions/browser/core_extensions_browser_api_provider.h"
 #include "extensions/browser/extension_prefs.h"
diff --git a/chrome/browser/extensions/chrome_extensions_interface_registration.cc b/chrome/browser/extensions/chrome_extensions_interface_registration.cc
index 6efb513..fd15825 100644
--- a/chrome/browser/extensions/chrome_extensions_interface_registration.cc
+++ b/chrome/browser/extensions/chrome_extensions_interface_registration.cc
@@ -35,7 +35,7 @@
 #include "content/public/browser/media_device_id.h"
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/api/media_perception_private/media_perception_api_delegate.h"
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #include "media/capture/video/chromeos/renderer_facing_cros_image_capture.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
diff --git a/chrome/browser/extensions/chrome_url_request_util.cc b/chrome/browser/extensions/chrome_url_request_util.cc
index 4a62cd53..5aafcd12 100644
--- a/chrome/browser/extensions/chrome_url_request_util.cc
+++ b/chrome/browser/extensions/chrome_url_request_util.cc
@@ -17,7 +17,6 @@
 #include "base/task/post_task.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/chrome_manifest_url_handlers.h"
-#include "content/public/browser/resource_request_info.h"
 #include "extensions/browser/component_extension_resource_manager.h"
 #include "extensions/browser/extension_protocols.h"
 #include "extensions/browser/extensions_browser_client.h"
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index a9f9571..f267299 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -26,7 +26,6 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/crx_file/id_util.h"
 #include "content/public/browser/render_process_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_renderer_host.h"
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 68a093d..f11376fd 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2520,6 +2520,11 @@
     "expiry_milestone": 80
   },
   {
+    "name": "omnibox-disable-instant-extended-limit",
+    "owners": [ "pnoland", "chrome-omnibox-team@google.com" ],
+    "expiry_milestone": 80
+  },
+  {
     "name": "omnibox-display-title-for-current-url",
     "owners": [ "chrome-omnibox-team@google.com" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 4727217a..6464a90 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1319,6 +1319,11 @@
     "the current page is provided as the first suggestion without a title. "
     "Enabling this flag causes the title to be displayed.";
 
+const char kOmniboxDisableInstantExtendedLimitName[] =
+    "Disable the 'instant extended' limit on search suggestions";
+const char kOmniboxDisableInstantExtendedLimitDescription[] =
+    "Effectively doubles the max number of Google-provided search suggestions "
+    "on Android by disabling the 'Instant Extended' check.";
 const char kOmniboxGroupSuggestionsBySearchVsUrlName[] =
     "Omnibox Group Suggestions By Search vs URL";
 const char kOmniboxGroupSuggestionsBySearchVsUrlDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 649fa49..7f7e1bb 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -797,6 +797,9 @@
 extern const char kOmniboxAlternateMatchDescriptionSeparatorName[];
 extern const char kOmniboxAlternateMatchDescriptionSeparatorDescription[];
 
+extern const char kOmniboxDisableInstantExtendedLimitName[];
+extern const char kOmniboxDisableInstantExtendedLimitDescription[];
+
 extern const char kOmniboxDisplayTitleForCurrentUrlName[];
 extern const char kOmniboxDisplayTitleForCurrentUrlDescription[];
 
diff --git a/chrome/browser/lookalikes/lookalike_url_interstitial_page.cc b/chrome/browser/lookalikes/lookalike_url_interstitial_page.cc
index bf4cad2f..72fa5cf 100644
--- a/chrome/browser/lookalikes/lookalike_url_interstitial_page.cc
+++ b/chrome/browser/lookalikes/lookalike_url_interstitial_page.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "base/metrics/field_trial_params.h"
+#include "chrome/common/chrome_features.h"
 #include "components/grit/components_resources.h"
 #include "components/security_interstitials/content/security_interstitial_controller_client.h"
 #include "components/security_interstitials/core/common_string_util.h"
@@ -21,6 +23,13 @@
 
 using security_interstitials::MetricsHelper;
 
+namespace {
+
+const base::FeatureParam<bool> kEnableAdvancedSection{
+    &features::kLookalikeUrlNavigationSuggestionsUI, "show_advanced", false};
+
+}  // namespace
+
 // static
 const content::InterstitialPageDelegate::TypeID
     LookalikeUrlInterstitialPage::kTypeForTesting =
@@ -87,6 +96,10 @@
   security_interstitials::common_string_util::PopulateDarkModeDisplaySetting(
       load_time_data);
 
+  auto formatted_hostname =
+      security_interstitials::common_string_util::GetFormattedHostName(
+          request_url());
+
   load_time_data->SetString(
       "tabTitle",
       l10n_util::GetStringFUTF16(
@@ -94,19 +107,50 @@
           security_interstitials::common_string_util::GetFormattedHostName(
               request_url())));
   load_time_data->SetString(
-      "heading",
-      l10n_util::GetStringFUTF16(
-          IDS_LOOKALIKE_URL_HEADING,
-          security_interstitials::common_string_util::GetFormattedHostName(
-              request_url())));
-  load_time_data->SetString(
-      "primaryParagraph",
-      l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH));
+      "heading", l10n_util::GetStringFUTF16(IDS_LOOKALIKE_URL_HEADING,
+                                            formatted_hostname));
   load_time_data->SetString(
       "proceedButtonText", l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_IGNORE));
   load_time_data->SetString(
       "primaryButtonText",
       l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_CONTINUE));
+  load_time_data->SetString(
+      "openDetails", l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_SHOW_DETAILS));
+  load_time_data->SetString(
+      "closeDetails",
+      l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_HIDE_DETAILS));
+  load_time_data->SetString(
+      "finalParagraph",
+      l10n_util::GetStringFUTF16(IDS_LOOKALIKE_URL_FINAL_PARAGRAPH,
+                                 formatted_hostname));
+
+  switch (match_type_) {
+    case MatchType::kNone:  // kNone used by chrome://interstitials
+    case MatchType::kTopSite:
+      load_time_data->SetString(
+          "primaryParagraph",
+          l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_TOP));
+      load_time_data->SetString(
+          "explanationParagraph",
+          l10n_util::GetStringFUTF16(IDS_LOOKALIKE_URL_EXPLANATION_TOP,
+                                     formatted_hostname));
+      break;
+    case MatchType::kSiteEngagement:
+      load_time_data->SetString(
+          "primaryParagraph",
+          l10n_util::GetStringUTF16(
+              IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_ENGAGEMENT));
+      load_time_data->SetString(
+          "explanationParagraph",
+          l10n_util::GetStringFUTF16(IDS_LOOKALIKE_URL_EXPLANATION_ENGAGEMENT,
+                                     formatted_hostname));
+      break;
+    case MatchType::kEditDistance:
+    case MatchType::kEditDistanceSiteEngagement:
+      NOTREACHED();
+  }
+
+  load_time_data->SetBoolean("show_advanced", kEnableAdvancedSection.Get());
 }
 
 void LookalikeUrlInterstitialPage::OnInterstitialClosing() {
@@ -142,9 +186,12 @@
       ReportUkmIfNeeded(UserAction::kClickThrough);
       controller()->Proceed();
       break;
+    case security_interstitials::CMD_SHOW_MORE_SECTION:
+      controller()->metrics_helper()->RecordUserInteraction(
+          MetricsHelper::SHOW_ADVANCED);
+      break;
     case security_interstitials::CMD_DO_REPORT:
     case security_interstitials::CMD_DONT_REPORT:
-    case security_interstitials::CMD_SHOW_MORE_SECTION:
     case security_interstitials::CMD_OPEN_DATE_SETTINGS:
     case security_interstitials::CMD_OPEN_REPORTING_PRIVACY:
     case security_interstitials::CMD_OPEN_WHITEPAPER:
@@ -176,7 +223,6 @@
   load_time_data->SetBoolean("show_recurrent_error_paragraph", false);
 
   load_time_data->SetString("recurrentErrorParagraph", "");
-  load_time_data->SetString("openDetails", "");
   load_time_data->SetString("explanationParagraph", "");
   load_time_data->SetString("finalParagraph", "");
 
diff --git a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
index 9131843..9053b9a 100644
--- a/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
+++ b/chrome/browser/lookalikes/lookalike_url_navigation_throttle_browsertest.cc
@@ -1051,3 +1051,20 @@
   TestInterstitialNotShown(browser(),
                            embedded_test_server()->GetURL("example.net", "/"));
 }
+
+// Verify that displaying the advanced section records UMA.
+IN_PROC_BROWSER_TEST_F(LookalikeUrlInterstitialPageBrowserTest,
+                       MetricsRecordedOnAdvancedShown) {
+  base::HistogramTester histograms;
+  LoadAndCheckInterstitialAt(browser(), GetURL("googlé.com"));
+  SendInterstitialCommand(browser()->tab_strip_model()->GetActiveWebContents(),
+                          SecurityInterstitialCommand::CMD_SHOW_MORE_SECTION);
+  SendInterstitialCommandSync(browser(),
+                              SecurityInterstitialCommand::CMD_PROCEED);
+
+  histograms.ExpectTotalCount(kInterstitialInteractionMetric, 2);
+  histograms.ExpectBucketCount(kInterstitialInteractionMetric,
+                               MetricsHelper::TOTAL_VISITS, 1);
+  histograms.ExpectBucketCount(kInterstitialInteractionMetric,
+                               MetricsHelper::SHOW_ADVANCED, 1);
+}
diff --git a/chrome/browser/media/router/providers/cast/activity_record.cc b/chrome/browser/media/router/providers/cast/activity_record.cc
index 2bc69b1..421dae76 100644
--- a/chrome/browser/media/router/providers/cast/activity_record.cc
+++ b/chrome/browser/media/router/providers/cast/activity_record.cc
@@ -42,14 +42,14 @@
            << session_id_.value_or("<missing>")
            << ", new session_id = " << session.session_id();
   route_.set_description(session.GetRouteDescription());
+  sink_ = sink;
   if (session_id_) {
     DCHECK_EQ(*session_id_, session.session_id());
   } else {
     session_id_ = session.session_id();
-    OnSessionSet();
+    if (on_session_set_)
+      std::move(on_session_set_).Run();
   }
 }
 
-void ActivityRecord::OnSessionSet() {}
-
 }  // namespace media_router
diff --git a/chrome/browser/media/router/providers/cast/activity_record.h b/chrome/browser/media/router/providers/cast/activity_record.h
index f7ff4dd3..cb8031c7 100644
--- a/chrome/browser/media/router/providers/cast/activity_record.h
+++ b/chrome/browser/media/router/providers/cast/activity_record.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/media/router/providers/cast/cast_internal_message_util.h"
 #include "chrome/browser/media/router/providers/cast/cast_session_client.h"
 #include "chrome/browser/media/router/providers/cast/cast_session_tracker.h"
+#include "chrome/common/media_router/discovery/media_sink_internal.h"
 #include "chrome/common/media_router/media_route.h"
 #include "chrome/common/media_router/mojo/media_router.mojom.h"
 #include "chrome/common/media_router/providers/cast/cast_media_source.h"
@@ -47,6 +48,8 @@
   const MediaRoute& route() const { return route_; }
   const std::string& app_id() const { return app_id_; }
   const base::Optional<std::string>& session_id() const { return session_id_; }
+  base::Optional<int> mirroring_tab_id() const { return mirroring_tab_id_; }
+  const MediaSinkInternal sink() const { return sink_; }
 
   // On the first call, saves the ID of |session|.  On subsequent calls,
   // notifies all connected clients that the session has been updated.  In both
@@ -138,15 +141,16 @@
   virtual void TerminatePresentationConnections() = 0;
 
  protected:
-  // Function called the first time session_id_ has been set.
-  virtual void OnSessionSet();
-
   CastSession* GetSession() const;
 
   MediaRoute route_;
   std::string app_id_;
+  base::Optional<int> mirroring_tab_id_;
   ClientMap connected_clients_;
 
+  // Called when a session is initially set from SetOrUpdateSession().
+  base::OnceCallback<void()> on_session_set_;
+
   // TODO(https://crbug.com/809249): Consider wrapping CastMessageHandler with
   // known parameters (sink, client ID, session transport ID) and passing them
   // to objects that need to send messages to the receiver.
@@ -157,6 +161,8 @@
 
   // Set by CastActivityManager after the session is launched successfully.
   base::Optional<std::string> session_id_;
+
+  MediaSinkInternal sink_;
 };
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
index 84bdccc..efd6469 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
@@ -89,6 +89,8 @@
   MediaRoute route(route_id, source, sink_id, /* description */ std::string(),
                    /* is_local */ true, /* for_display */ true);
   route.set_incognito(incognito);
+  DVLOG(1) << "LaunchSession: source_id=" << cast_source.source_id()
+           << ", route_id: " << route_id << ", sink_id=" << sink_id;
   DoLaunchSessionParams params(route, cast_source, sink, origin, tab_id,
                                std::move(callback));
   // If there is currently a session on the sink, it must be terminated before
@@ -261,9 +263,12 @@
     activity = FindActivityForAutoJoin(cast_source, origin, tab_id);
     if (!activity && cast_source.default_action_policy() !=
                          DefaultActionPolicy::kCastThisTab) {
-      // TODO(crbug.com/951057): Try to convert a mirroring route matching the
-      // tab to a Cast route.
-      DLOG(ERROR) << "Conversion to a Cast route is not implemented.";
+      auto sink = ConvertMirrorToCast(tab_id);
+      if (sink) {
+        LaunchSession(cast_source, *sink, presentation_id, origin, tab_id,
+                      incognito, std::move(callback));
+        return;
+      }
     }
   } else {
     activity = FindActivityForSessionJoin(cast_source, presentation_id);
@@ -668,7 +673,7 @@
 void CastActivityManager::SendFailedToCastIssue(
     const MediaSink::Id& sink_id,
     const MediaRoute::Id& route_id) {
-  // TODO(imcheng): i18n-ize the title string.
+  // TODO(crbug.com/989237): i18n-ize the title string.
   IssueInfo info("Failed to cast. Please try again.",
                  IssueInfo::Action::DISMISS, IssueInfo::Severity::WARNING);
   info.sink_id = sink_id;
@@ -676,6 +681,17 @@
   media_router_->OnIssue(info);
 }
 
+base::Optional<MediaSinkInternal> CastActivityManager::ConvertMirrorToCast(
+    int tab_id) {
+  for (const auto& pair : activities_) {
+    if (pair.second->mirroring_tab_id() == tab_id) {
+      return pair.second->sink();
+    }
+  }
+
+  return base::nullopt;
+}
+
 CastActivityManager::DoLaunchSessionParams::DoLaunchSessionParams(
     const MediaRoute& route,
     const CastMediaSource& cast_source,
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.h b/chrome/browser/media/router/providers/cast/cast_activity_manager.h
index 5c8ccef..230d23b 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager.h
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.h
@@ -240,6 +240,10 @@
       int tab_id,
       const CastSinkExtraData& cast_data);
 
+  // Returns a sink used to convert a mirroring activity to a cast activity.  If
+  // no conversion should occur, returns base::nullopt.
+  base::Optional<MediaSinkInternal> ConvertMirrorToCast(int tab_id);
+
   static CastActivityRecordFactoryForTest* activity_record_factory_;
 
   base::flat_set<MediaSource::Id> route_queries_;
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity_record.cc b/chrome/browser/media/router/providers/cast/mirroring_activity_record.cc
index 79cbb8c..e96d74e 100644
--- a/chrome/browser/media/router/providers/cast/mirroring_activity_record.cc
+++ b/chrome/browser/media/router/providers/cast/mirroring_activity_record.cc
@@ -65,6 +65,8 @@
       on_stop_(std::move(callback)) {
   // TODO(jrw): Detect and report errors.
 
+  mirroring_tab_id_ = target_tab_id;
+
   // Get a reference to the mirroring service host.
   media_router->GetMirroringServiceHostForTab(target_tab_id,
                                               mojo::MakeRequest(&host_));
@@ -250,10 +252,6 @@
   channel_to_service_->Send(std::move(ptr));
 }
 
-void MirroringActivityRecord::OnSessionSet() {
-  std::move(on_session_set_).Run();
-}
-
 void MirroringActivityRecord::StopMirroring() {
   // Running the callback will cause this object to be deleted.
   if (on_stop_)
diff --git a/chrome/browser/media/router/providers/cast/mirroring_activity_record.h b/chrome/browser/media/router/providers/cast/mirroring_activity_record.h
index 19d5369..6f560c29 100644
--- a/chrome/browser/media/router/providers/cast/mirroring_activity_record.h
+++ b/chrome/browser/media/router/providers/cast/mirroring_activity_record.h
@@ -76,9 +76,6 @@
   void OnAppMessage(const cast_channel::CastMessage& message) override;
   void OnInternalMessage(const cast_channel::InternalMessage& message) override;
 
- protected:
-  void OnSessionSet() override;
-
  private:
   enum class MirroringType {
     kTab,           // Mirror a single tab.
@@ -103,7 +100,6 @@
   const int channel_id_;
   const MirroringType mirroring_type_;
   OnStopCallback on_stop_;
-  base::OnceCallback<void()> on_session_set_;
   base::WeakPtrFactory<MirroringActivityRecord> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc b/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
index 3a33cae..861ee79f 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
@@ -66,7 +66,7 @@
                          base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
 
 void OnPreferencesInit(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const content::WebContents::Getter& web_contents_getter,
     const extensions::Extension* extension,
     MediaGalleryPrefId pref_id,
     base::OnceCallback<void(base::File::Error result)> callback) {
@@ -84,7 +84,7 @@
 }
 
 void AttemptAutoMountOnUIThread(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const content::WebContents::Getter& web_contents_getter,
     const std::string& storage_domain,
     const std::string& mount_point,
     base::OnceCallback<void(base::File::Error result)> callback) {
@@ -205,7 +205,7 @@
                         base::CompareCase::SENSITIVE))
     return false;
 
-  content::ResourceRequestInfo::WebContentsGetter web_contents_getter;
+  content::WebContents::Getter web_contents_getter;
   if (request_info.content_id) {
     web_contents_getter = base::BindRepeating(
         &GetWebContentsFromFrameTreeNodeID, request_info.content_id);
diff --git a/chrome/browser/notifications/scheduler/display_agent_android.cc b/chrome/browser/notifications/scheduler/display_agent_android.cc
index f996b579..2a3cd3e 100644
--- a/chrome/browser/notifications/scheduler/display_agent_android.cc
+++ b/chrome/browser/notifications/scheduler/display_agent_android.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/notifications/scheduler/display_agent_android.h"
 
+#include <string>
+#include <utility>
+
 #include "base/android/jni_string.h"
 #include "base/logging.h"
 #include "chrome/android/chrome_jni_headers/DisplayAgent_jni.h"
@@ -15,6 +18,7 @@
 
 using base::android::ConvertUTF16ToJavaString;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
 namespace {
@@ -30,38 +34,30 @@
 }  // namespace
 
 // static
-void JNI_DisplayAgent_OnContentClick(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& j_profile,
-    jint j_client_type,
-    const base::android::JavaParamRef<jstring>& j_guid) {
-  GetUserActionHandler(j_profile)->OnClick(
+void JNI_DisplayAgent_OnUserAction(JNIEnv* env,
+                                   const JavaParamRef<jobject>& j_profile,
+                                   jint j_client_type,
+                                   jint j_action_type,
+                                   const JavaParamRef<jstring>& j_guid,
+                                   jint j_button_type,
+                                   const JavaParamRef<jstring>& j_button_id) {
+  auto user_action_type =
+      static_cast<notifications::UserActionType>(j_action_type);
+  notifications::UserActionData action_data(
       static_cast<notifications::SchedulerClientType>(j_client_type),
-      ConvertJavaStringToUTF8(env, j_guid));
-}
+      user_action_type, ConvertJavaStringToUTF8(env, j_guid));
 
-// static
-void JNI_DisplayAgent_OnDismiss(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& j_profile,
-    jint j_client_type,
-    const base::android::JavaParamRef<jstring>& j_guid) {
-  GetUserActionHandler(j_profile)->OnDismiss(
-      static_cast<notifications::SchedulerClientType>(j_client_type),
-      ConvertJavaStringToUTF8(env, j_guid));
-}
+  // Attach button click data.
+  if (user_action_type == notifications::UserActionType::kButtonClick) {
+    notifications::ButtonClickInfo button_click_info;
+    button_click_info.button_id = ConvertJavaStringToUTF8(env, j_button_id);
+    button_click_info.type =
+        static_cast<notifications::ActionButtonType>(j_button_type);
+    action_data.button_click_info =
+        base::make_optional(std::move(button_click_info));
+  }
 
-// static
-void JNI_DisplayAgent_OnActionButton(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& j_profile,
-    jint j_client_type,
-    const base::android::JavaParamRef<jstring>& j_guid,
-    jint type) {
-  GetUserActionHandler(j_profile)->OnActionClick(
-      static_cast<notifications::SchedulerClientType>(j_client_type),
-      ConvertJavaStringToUTF8(env, j_guid),
-      static_cast<notifications::ActionButtonType>(type));
+  GetUserActionHandler(j_profile)->OnUserAction(action_data);
 }
 
 DisplayAgentAndroid::DisplayAgentAndroid() = default;
diff --git a/chrome/browser/notifications/scheduler/internal/impression_history_tracker.cc b/chrome/browser/notifications/scheduler/internal/impression_history_tracker.cc
index d06abd1..976641fc 100644
--- a/chrome/browser/notifications/scheduler/internal/impression_history_tracker.cc
+++ b/chrome/browser/notifications/scheduler/internal/impression_history_tracker.cc
@@ -109,20 +109,22 @@
   std::move(callback).Run(std::move(detail));
 }
 
-void ImpressionHistoryTrackerImpl::OnClick(SchedulerClientType type,
-                                           const std::string& guid) {
-  OnClickInternal(guid, true /*update_db*/);
-}
-
-void ImpressionHistoryTrackerImpl::OnActionClick(SchedulerClientType type,
-                                                 const std::string& guid,
-                                                 ActionButtonType button_type) {
-  OnButtonClickInternal(guid, button_type, true /*update_db*/);
-}
-
-void ImpressionHistoryTrackerImpl::OnDismiss(SchedulerClientType type,
-                                             const std::string& guid) {
-  OnDismissInternal(guid, true /*update_db*/);
+void ImpressionHistoryTrackerImpl::OnUserAction(
+    const UserActionData& action_data) {
+  auto button_type = action_data.button_click_info.has_value()
+                         ? action_data.button_click_info->type
+                         : ActionButtonType::kUnknownAction;
+  switch (action_data.action_type) {
+    case UserActionType::kClick:
+      OnClickInternal(action_data.guid, true /*update_db*/);
+      break;
+    case UserActionType::kButtonClick:
+      OnButtonClickInternal(action_data.guid, button_type, true /*update_db*/);
+      break;
+    case UserActionType::kDismiss:
+      OnDismissInternal(action_data.guid, true /*update_db*/);
+      break;
+  }
 }
 
 void ImpressionHistoryTrackerImpl::OnStoreInitialized(
diff --git a/chrome/browser/notifications/scheduler/internal/impression_history_tracker.h b/chrome/browser/notifications/scheduler/internal/impression_history_tracker.h
index 32c45da1..0ea2916 100644
--- a/chrome/browser/notifications/scheduler/internal/impression_history_tracker.h
+++ b/chrome/browser/notifications/scheduler/internal/impression_history_tracker.h
@@ -95,11 +95,7 @@
   void GetImpressionDetail(
       SchedulerClientType type,
       ImpressionDetail::ImpressionDetailCallback callback) override;
-  void OnClick(SchedulerClientType type, const std::string& guid) override;
-  void OnActionClick(SchedulerClientType type,
-                     const std::string& guid,
-                     ActionButtonType button_type) override;
-  void OnDismiss(SchedulerClientType type, const std::string& guid) override;
+  void OnUserAction(const UserActionData& action_data) override;
 
   // Called after |store_| is initialized.
   void OnStoreInitialized(InitCallback callback,
diff --git a/chrome/browser/notifications/scheduler/internal/impression_history_tracker_unittest.cc b/chrome/browser/notifications/scheduler/internal/impression_history_tracker_unittest.cc
index fbfcc15..d78bb4a4 100644
--- a/chrome/browser/notifications/scheduler/internal/impression_history_tracker_unittest.cc
+++ b/chrome/browser/notifications/scheduler/internal/impression_history_tracker_unittest.cc
@@ -24,6 +24,7 @@
 namespace {
 
 const char kGuid1[] = "guid1";
+const char kButtonId[] = "button_id_1";
 const char kTimeStr[] = "04/25/20 01:00:00 AM";
 
 struct TestCase {
@@ -252,7 +253,9 @@
   InitTrackerWithData(test_case);
   EXPECT_CALL(*store(), Update(_, _, _)).Times(0);
   EXPECT_CALL(*delegate(), OnImpressionUpdated()).Times(0);
-  tracker()->OnClick(SchedulerClientType::kTest1, kGuid1);
+  UserActionData action_data(SchedulerClientType::kTest1,
+                             UserActionType::kClick, kGuid1);
+  tracker()->OnUserAction(action_data);
   VerifyClientStates(test_case);
 }
 
@@ -331,12 +334,22 @@
 
   // Trigger user action.
   if (GetParam().user_feedback == UserFeedback::kClick) {
-    tracker()->OnClick(SchedulerClientType::kTest1, kGuid1);
+    UserActionData action_data(SchedulerClientType::kTest1,
+                               UserActionType::kClick, kGuid1);
+    tracker()->OnUserAction(action_data);
   } else if (GetParam().button_type.has_value()) {
-    tracker()->OnActionClick(SchedulerClientType::kTest1, kGuid1,
-                             GetParam().button_type.value());
+    ButtonClickInfo button_click_info;
+    button_click_info.button_id = kButtonId;
+    button_click_info.type = GetParam().button_type.value();
+    UserActionData action_data(SchedulerClientType::kTest1,
+                               UserActionType::kButtonClick, kGuid1);
+    action_data.button_click_info =
+        base::make_optional(std::move(button_click_info));
+    tracker()->OnUserAction(action_data);
   } else if (GetParam().user_feedback == UserFeedback::kDismiss) {
-    tracker()->OnDismiss(SchedulerClientType::kTest1, kGuid1);
+    UserActionData action_data(SchedulerClientType::kTest1,
+                               UserActionType::kDismiss, kGuid1);
+    tracker()->OnUserAction(action_data);
   }
 
   VerifyClientStates(test_case);
diff --git a/chrome/browser/notifications/scheduler/internal/init_aware_scheduler.cc b/chrome/browser/notifications/scheduler/internal/init_aware_scheduler.cc
index ca7c03ac..a5b64f1 100644
--- a/chrome/browser/notifications/scheduler/internal/init_aware_scheduler.cc
+++ b/chrome/browser/notifications/scheduler/internal/init_aware_scheduler.cc
@@ -79,39 +79,15 @@
                                    weak_ptr_factory_.GetWeakPtr(), task_time));
 }
 
-void InitAwareNotificationScheduler::OnClick(SchedulerClientType type,
-                                             const std::string& guid) {
+void InitAwareNotificationScheduler::OnUserAction(
+    const UserActionData& action_data) {
   if (IsReady()) {
-    impl_->OnClick(type, guid);
+    impl_->OnUserAction(action_data);
     return;
   }
-  MaybeCacheClosure(base::BindOnce(&InitAwareNotificationScheduler::OnClick,
-                                   weak_ptr_factory_.GetWeakPtr(), type, guid));
-}
-
-void InitAwareNotificationScheduler::OnActionClick(
-    SchedulerClientType type,
-    const std::string& guid,
-    ActionButtonType button_type) {
-  if (IsReady()) {
-    impl_->OnActionClick(type, guid, button_type);
-    return;
-  }
-
   MaybeCacheClosure(
-      base::BindOnce(&InitAwareNotificationScheduler::OnActionClick,
-                     weak_ptr_factory_.GetWeakPtr(), type, guid, button_type));
-}
-
-void InitAwareNotificationScheduler::OnDismiss(SchedulerClientType type,
-                                               const std::string& guid) {
-  if (IsReady()) {
-    impl_->OnDismiss(type, guid);
-    return;
-  }
-
-  MaybeCacheClosure(base::BindOnce(&InitAwareNotificationScheduler::OnDismiss,
-                                   weak_ptr_factory_.GetWeakPtr(), type, guid));
+      base::BindOnce(&InitAwareNotificationScheduler::OnUserAction,
+                     weak_ptr_factory_.GetWeakPtr(), action_data));
 }
 
 void InitAwareNotificationScheduler::OnInitialized(InitCallback init_callback,
diff --git a/chrome/browser/notifications/scheduler/internal/init_aware_scheduler.h b/chrome/browser/notifications/scheduler/internal/init_aware_scheduler.h
index f50298fd..daf67299 100644
--- a/chrome/browser/notifications/scheduler/internal/init_aware_scheduler.h
+++ b/chrome/browser/notifications/scheduler/internal/init_aware_scheduler.h
@@ -41,11 +41,7 @@
   void OnStartTask(SchedulerTaskTime task_time,
                    TaskFinishedCallback callback) override;
   void OnStopTask(SchedulerTaskTime task_time) override;
-  void OnClick(SchedulerClientType type, const std::string& guid) override;
-  void OnActionClick(SchedulerClientType type,
-                     const std::string& guid,
-                     ActionButtonType button_type) override;
-  void OnDismiss(SchedulerClientType type, const std::string& guid) override;
+  void OnUserAction(const UserActionData& action_data) override;
 
   // Called after initialization is done.
   void OnInitialized(InitCallback init_callback, bool success);
diff --git a/chrome/browser/notifications/scheduler/internal/init_aware_scheduler_unittest.cc b/chrome/browser/notifications/scheduler/internal/init_aware_scheduler_unittest.cc
index 52eebe8..6fb72f3c 100644
--- a/chrome/browser/notifications/scheduler/internal/init_aware_scheduler_unittest.cc
+++ b/chrome/browser/notifications/scheduler/internal/init_aware_scheduler_unittest.cc
@@ -33,10 +33,7 @@
                     ImpressionDetail::ImpressionDetailCallback callback));
   MOCK_METHOD2(OnStartTask, void(SchedulerTaskTime, TaskFinishedCallback));
   MOCK_METHOD1(OnStopTask, void(SchedulerTaskTime));
-  MOCK_METHOD2(OnClick, void(SchedulerClientType, const std::string&));
-  MOCK_METHOD3(OnActionClick,
-               void(SchedulerClientType, const std::string&, ActionButtonType));
-  MOCK_METHOD2(OnDismiss, void(SchedulerClientType, const std::string&));
+  MOCK_METHOD1(OnUserAction, void(const UserActionData&));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockNotificationScheduler);
diff --git a/chrome/browser/notifications/scheduler/internal/noop_notification_schedule_service.cc b/chrome/browser/notifications/scheduler/internal/noop_notification_schedule_service.cc
index 6b74245..efb9066 100644
--- a/chrome/browser/notifications/scheduler/internal/noop_notification_schedule_service.cc
+++ b/chrome/browser/notifications/scheduler/internal/noop_notification_schedule_service.cc
@@ -37,15 +37,7 @@
 
 void NoopNotificationScheduleService::OnStopTask(SchedulerTaskTime task_time) {}
 
-void NoopNotificationScheduleService::OnClick(SchedulerClientType type,
-                                              const std::string& guid) {}
-
-void NoopNotificationScheduleService::OnActionClick(
-    SchedulerClientType type,
-    const std::string& guid,
-    ActionButtonType button_type) {}
-
-void NoopNotificationScheduleService::OnDismiss(SchedulerClientType type,
-                                                const std::string& guid) {}
+void NoopNotificationScheduleService::OnUserAction(
+    const UserActionData& action_data) {}
 
 }  // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/internal/noop_notification_schedule_service.h b/chrome/browser/notifications/scheduler/internal/noop_notification_schedule_service.h
index 25630e8..b17acef2 100644
--- a/chrome/browser/notifications/scheduler/internal/noop_notification_schedule_service.h
+++ b/chrome/browser/notifications/scheduler/internal/noop_notification_schedule_service.h
@@ -39,11 +39,7 @@
   void OnStopTask(SchedulerTaskTime task_time) override;
 
   // UserActionHandler implementation.
-  void OnClick(SchedulerClientType type, const std::string& guid) override;
-  void OnActionClick(SchedulerClientType type,
-                     const std::string& guid,
-                     ActionButtonType button_type) override;
-  void OnDismiss(SchedulerClientType type, const std::string& guid) override;
+  void OnUserAction(const UserActionData& action_data) override;
 
   DISALLOW_COPY_AND_ASSIGN(NoopNotificationScheduleService);
 };
diff --git a/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.cc b/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.cc
index 01feb35..6a917e6 100644
--- a/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.cc
+++ b/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.cc
@@ -58,21 +58,9 @@
   scheduler_->OnStopTask(task_time);
 }
 
-void NotificationScheduleServiceImpl::OnClick(SchedulerClientType type,
-                                              const std::string& guid) {
-  scheduler_->OnClick(type, guid);
-}
-
-void NotificationScheduleServiceImpl::OnActionClick(
-    SchedulerClientType type,
-    const std::string& guid,
-    ActionButtonType button_type) {
-  scheduler_->OnActionClick(type, guid, button_type);
-}
-
-void NotificationScheduleServiceImpl::OnDismiss(SchedulerClientType type,
-                                                const std::string& guid) {
-  scheduler_->OnDismiss(type, guid);
+void NotificationScheduleServiceImpl::OnUserAction(
+    const UserActionData& action_data) {
+  scheduler_->OnUserAction(action_data);
 }
 
 void NotificationScheduleServiceImpl::OnInitialized(bool success) {
diff --git a/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.h b/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.h
index 46ffba6..6ced042 100644
--- a/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.h
+++ b/chrome/browser/notifications/scheduler/internal/notification_schedule_service_impl.h
@@ -45,11 +45,7 @@
   void OnStopTask(SchedulerTaskTime task_time) override;
 
   // UserActionHandler implementation.
-  void OnClick(SchedulerClientType type, const std::string& guid) override;
-  void OnActionClick(SchedulerClientType type,
-                     const std::string& guid,
-                     ActionButtonType button_type) override;
-  void OnDismiss(SchedulerClientType type, const std::string& guid) override;
+  void OnUserAction(const UserActionData& action_data) override;
 
   // Called after initialization is done.
   void OnInitialized(bool success);
diff --git a/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc b/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc
index 55d4e572..17cc27d6 100644
--- a/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc
+++ b/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc
@@ -267,52 +267,22 @@
         std::move(notifications), std::move(client_states), task_start_time_);
   }
 
-  void OnClick(SchedulerClientType type, const std::string& guid) override {
-    context_->impression_tracker()->OnClick(type, guid);
+  void OnUserAction(const UserActionData& action_data) override {
+    context_->impression_tracker()->OnUserAction(action_data);
 
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(&NotificationSchedulerImpl::NotifyClientAfterUserAction,
-                       weak_ptr_factory_.GetWeakPtr(), UserActionType::kClick,
-                       type, base::nullopt));
+                       weak_ptr_factory_.GetWeakPtr(), action_data));
   }
 
-  void OnActionClick(SchedulerClientType type,
-                     const std::string& guid,
-                     ActionButtonType button_type) override {
-    context_->impression_tracker()->OnActionClick(type, guid, button_type);
-
-    ButtonClickInfo button_info;
-    // TODO(xingliu): Plumb the button id from platform.
-    button_info.button_id = std::string();
-    button_info.type = button_type;
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(&NotificationSchedulerImpl::NotifyClientAfterUserAction,
-                       weak_ptr_factory_.GetWeakPtr(),
-                       UserActionType::kButtonClick, type,
-                       std::move(button_info)));
-  }
-
-  void OnDismiss(SchedulerClientType type, const std::string& guid) override {
-    context_->impression_tracker()->OnDismiss(type, guid);
-
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(&NotificationSchedulerImpl::NotifyClientAfterUserAction,
-                       weak_ptr_factory_.GetWeakPtr(), UserActionType::kDismiss,
-                       type, base::nullopt));
-  }
-
-  void NotifyClientAfterUserAction(
-      UserActionType action_type,
-      SchedulerClientType client_type,
-      base::Optional<ButtonClickInfo> button_info) {
-    auto* client = context_->client_registrar()->GetClient(client_type);
+  void NotifyClientAfterUserAction(const UserActionData& action_data) {
+    auto* client =
+        context_->client_registrar()->GetClient(action_data.client_type);
     if (!client)
       return;
 
-    client->OnUserAction(action_type, std::move(button_info));
+    client->OnUserAction(action_data);
   }
 
   std::unique_ptr<NotificationSchedulerContext> context_;
diff --git a/chrome/browser/notifications/scheduler/internal/webui_client.cc b/chrome/browser/notifications/scheduler/internal/webui_client.cc
index 28e5b36..b5df64f8 100644
--- a/chrome/browser/notifications/scheduler/internal/webui_client.cc
+++ b/chrome/browser/notifications/scheduler/internal/webui_client.cc
@@ -25,8 +25,7 @@
   NOTIMPLEMENTED();
 }
 
-void WebUIClient::OnUserAction(UserActionType action_type,
-                               base::Optional<ButtonClickInfo> button_info) {
+void WebUIClient::OnUserAction(const UserActionData& action_data) {
   NOTIMPLEMENTED();
 }
 
diff --git a/chrome/browser/notifications/scheduler/internal/webui_client.h b/chrome/browser/notifications/scheduler/internal/webui_client.h
index 75a698e1..ce63a082f 100644
--- a/chrome/browser/notifications/scheduler/internal/webui_client.h
+++ b/chrome/browser/notifications/scheduler/internal/webui_client.h
@@ -26,8 +26,7 @@
       NotificationDataCallback callback) override;
   void OnSchedulerInitialized(bool success,
                               std::set<std::string> guids) override;
-  void OnUserAction(UserActionType action_type,
-                    base::Optional<ButtonClickInfo> button_info) override;
+  void OnUserAction(const UserActionData& action_data) override;
 
   DISALLOW_COPY_AND_ASSIGN(WebUIClient);
 };
diff --git a/chrome/browser/notifications/scheduler/public/BUILD.gn b/chrome/browser/notifications/scheduler/public/BUILD.gn
index 23e87ae..0c98008 100644
--- a/chrome/browser/notifications/scheduler/public/BUILD.gn
+++ b/chrome/browser/notifications/scheduler/public/BUILD.gn
@@ -23,6 +23,7 @@
     "notification_scheduler_client.h",
     "notification_scheduler_client_registrar.cc",
     "notification_scheduler_client_registrar.h",
+    "notification_scheduler_types.cc",
     "notification_scheduler_types.h",
     "schedule_params.cc",
     "schedule_params.h",
diff --git a/chrome/browser/notifications/scheduler/public/notification_scheduler_client.h b/chrome/browser/notifications/scheduler/public/notification_scheduler_client.h
index 4da1fd8..193ea0f 100644
--- a/chrome/browser/notifications/scheduler/public/notification_scheduler_client.h
+++ b/chrome/browser/notifications/scheduler/public/notification_scheduler_client.h
@@ -41,8 +41,7 @@
                                       std::set<std::string> guids) = 0;
 
   // Called when the user interacts with the notification.
-  virtual void OnUserAction(UserActionType action_type,
-                            base::Optional<ButtonClickInfo> button_info) = 0;
+  virtual void OnUserAction(const UserActionData& action_data) = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(NotificationSchedulerClient);
diff --git a/chrome/browser/notifications/scheduler/public/notification_scheduler_types.cc b/chrome/browser/notifications/scheduler/public/notification_scheduler_types.cc
new file mode 100644
index 0000000..bec6e9f
--- /dev/null
+++ b/chrome/browser/notifications/scheduler/public/notification_scheduler_types.cc
@@ -0,0 +1,18 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/notifications/scheduler/public/notification_scheduler_types.h"
+
+namespace notifications {
+
+UserActionData::UserActionData(SchedulerClientType client_type,
+                               UserActionType action_type,
+                               const std::string& guid)
+    : client_type(client_type), action_type(action_type), guid(guid) {}
+
+UserActionData::UserActionData(const UserActionData& other) = default;
+
+UserActionData::~UserActionData() = default;
+
+}  // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/public/notification_scheduler_types.h b/chrome/browser/notifications/scheduler/public/notification_scheduler_types.h
index 5cf07e6..b19aa08 100644
--- a/chrome/browser/notifications/scheduler/public/notification_scheduler_types.h
+++ b/chrome/browser/notifications/scheduler/public/notification_scheduler_types.h
@@ -5,8 +5,11 @@
 #ifndef CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_PUBLIC_NOTIFICATION_SCHEDULER_TYPES_H_
 #define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_PUBLIC_NOTIFICATION_SCHEDULER_TYPES_H_
 
+#include <map>
 #include <string>
 
+#include "base/optional.h"
+
 namespace notifications {
 
 // Enum to describe the time to process scheduled notification data.
@@ -73,6 +76,9 @@
 };
 
 // Defines user actions type.
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: (
+//   org.chromium.chrome.browser.notifications.scheduler)
 enum class UserActionType {
   // The user clicks on the notification body.
   kClick = 0,
@@ -107,6 +113,30 @@
   ActionButtonType type = ActionButtonType::kUnknownAction;
 };
 
+// Contains data associated with user actions.
+struct UserActionData {
+  UserActionData(SchedulerClientType client_type,
+                 UserActionType action_type,
+                 const std::string& guid);
+  UserActionData(const UserActionData& other);
+  ~UserActionData();
+
+  // The type of the client that sent the notification.
+  const SchedulerClientType client_type;
+
+  // The user action type.
+  const UserActionType action_type;
+
+  // The guid of the notification.
+  const std::string guid;
+
+  // The client defined custom data.
+  std::map<std::string, std::string> custom_data;
+
+  // The button click info, only available when the user clicked a button.
+  base::Optional<ButtonClickInfo> button_click_info;
+};
+
 }  // namespace notifications
 
 #endif  // CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_PUBLIC_NOTIFICATION_SCHEDULER_TYPES_H_
diff --git a/chrome/browser/notifications/scheduler/public/user_action_handler.h b/chrome/browser/notifications/scheduler/public/user_action_handler.h
index d5da8ee..e364d65 100644
--- a/chrome/browser/notifications/scheduler/public/user_action_handler.h
+++ b/chrome/browser/notifications/scheduler/public/user_action_handler.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_PUBLIC_USER_ACTION_HANDLER_H_
 #define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_PUBLIC_USER_ACTION_HANDLER_H_
 
-#include <string>
 
 #include "base/macros.h"
 #include "chrome/browser/notifications/scheduler/public/notification_scheduler_types.h"
@@ -13,20 +12,10 @@
 namespace notifications {
 
 // An interface to plumb user actions events to notification scheduling system.
-// Each event needs to provide an unique id of the notification shown.
 class UserActionHandler {
  public:
-  // Called when the user clicks on the notification. |guid| is the internal id
-  // to track the notification persist to disk.
-  virtual void OnClick(SchedulerClientType type, const std::string& guid) = 0;
-
-  // Called when the user clicks on a button on the notification.
-  virtual void OnActionClick(SchedulerClientType type,
-                             const std::string& guid,
-                             ActionButtonType button_type) = 0;
-
-  // Called when the user cancels or dismiss the notification.
-  virtual void OnDismiss(SchedulerClientType type, const std::string& guid) = 0;
+  // Called when the user interacts with the notification.
+  virtual void OnUserAction(const UserActionData& action_data) = 0;
 
   ~UserActionHandler() = default;
 
diff --git a/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc b/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
index d1d5f9d..befb4bd 100644
--- a/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
+++ b/chrome/browser/offline_pages/android/downloads/offline_page_download_bridge.cc
@@ -255,7 +255,7 @@
   return content::WebContents::FromRenderFrameHost(render_frame_host);
 }
 
-content::ResourceRequestInfo::WebContentsGetter GetWebContentsGetter(
+content::WebContents::Getter GetWebContentsGetter(
     content::WebContents* web_contents) {
   // PlzNavigate: The FrameTreeNode ID should be used to access the WebContents.
   int frame_tree_node_id = web_contents->GetMainFrame()->GetFrameTreeNodeId();
@@ -295,7 +295,7 @@
 }
 
 void OnOfflinePageAcquireFileAccessPermissionDone(
-    const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const content::WebContents::Getter& web_contents_getter,
     const ScopedJavaGlobalRef<jobject>& j_tab_ref,
     const std::string& origin,
     bool granted) {
@@ -387,7 +387,7 @@
 
   // Ensure that the storage permission is granted since the target file
   // is going to be placed in the public directory.
-  content::ResourceRequestInfo::WebContentsGetter web_contents_getter =
+  content::WebContents::Getter web_contents_getter =
       GetWebContentsGetter(web_contents);
   DownloadControllerBase::Get()->AcquireFileAccessPermission(
       web_contents_getter,
diff --git a/chrome/browser/offline_pages/offline_page_request_handler.cc b/chrome/browser/offline_pages/offline_page_request_handler.cc
index 3ce6e01..4b41389 100644
--- a/chrome/browser/offline_pages/offline_page_request_handler.cc
+++ b/chrome/browser/offline_pages/offline_page_request_handler.cc
@@ -30,7 +30,6 @@
 #include "components/previews/core/previews_experiments.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/resource_type.h"
@@ -254,7 +253,7 @@
 }
 
 OfflinePageModel* GetOfflinePageModel(
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter) {
+    content::WebContents::Getter web_contents_getter) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   content::WebContents* web_contents = web_contents_getter.Run();
@@ -309,7 +308,7 @@
     const OfflinePageHeader& offline_header,
     OfflinePageRequestHandler::NetworkState network_state,
     base::WeakPtr<OfflinePageRequestHandler> job,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    content::WebContents::Getter web_contents_getter,
     const std::vector<OfflinePageItem>& offline_pages) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
@@ -345,7 +344,7 @@
     const GURL& url,
     const OfflinePageHeader& offline_header,
     OfflinePageRequestHandler::NetworkState network_state,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    content::WebContents::Getter web_contents_getter,
     base::WeakPtr<OfflinePageRequestHandler> job,
     const OfflinePageItem* offline_page) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -368,7 +367,7 @@
     const GURL& url,
     const OfflinePageHeader& offline_header,
     OfflinePageRequestHandler::NetworkState network_state,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    content::WebContents::Getter web_contents_getter,
     OfflinePageRequestHandler::Delegate::TabIdGetter tab_id_getter,
     base::WeakPtr<OfflinePageRequestHandler> job) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -418,7 +417,7 @@
 void VisitTrustedOfflinePageOnUI(
     const OfflinePageHeader& offline_header,
     OfflinePageRequestHandler::NetworkState network_state,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    content::WebContents::Getter web_contents_getter,
     const OfflinePageItem& offline_page,
     bool archive_is_in_internal_dir) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -452,8 +451,7 @@
           OfflinePageRequestHandler::NetworkState::PROHIBITIVELY_SLOW_NETWORK);
 }
 
-void ClearOfflinePageData(
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter) {
+void ClearOfflinePageData(content::WebContents::Getter web_contents_getter) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // |web_contents_getter| is passed from IO thread. We need to check if
diff --git a/chrome/browser/offline_pages/offline_page_request_handler.h b/chrome/browser/offline_pages/offline_page_request_handler.h
index adea439..836f06af 100644
--- a/chrome/browser/offline_pages/offline_page_request_handler.h
+++ b/chrome/browser/offline_pages/offline_page_request_handler.h
@@ -15,7 +15,6 @@
 #include "components/offline_pages/core/archive_validator.h"
 #include "components/offline_pages/core/offline_page_item.h"
 #include "components/offline_pages/core/request_header/offline_page_header.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/resource_type.h"
 
 namespace base {
@@ -23,6 +22,10 @@
 class TaskRunner;
 }
 
+namespace content {
+class WebContents;
+}
+
 namespace net {
 class FileStream;
 class HttpRequestHeaders;
diff --git a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
index 7ddcb82..48ab504a 100644
--- a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
+++ b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
@@ -39,7 +39,6 @@
 #include "components/offline_pages/core/request_header/offline_page_navigation_ui_data.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/previews_state.h"
diff --git a/chrome/browser/offline_pages/offline_page_utils.cc b/chrome/browser/offline_pages/offline_page_utils.cc
index c12fe77..29742f0f 100644
--- a/chrome/browser/offline_pages/offline_page_utils.cc
+++ b/chrome/browser/offline_pages/offline_page_utils.cc
@@ -128,7 +128,7 @@
   return content::WebContents::FromRenderFrameHost(render_frame_host);
 }
 
-content::ResourceRequestInfo::WebContentsGetter GetWebContentsGetter(
+content::WebContents::Getter GetWebContentsGetter(
     content::WebContents* web_contents) {
   // PlzNavigate: The FrameTreeNode ID should be used to access the WebContents.
   int frame_tree_node_id = web_contents->GetMainFrame()->GetFrameTreeNodeId();
@@ -387,7 +387,7 @@
     content::WebContents* web_contents,
     base::OnceCallback<void(bool)> callback) {
 #if defined(OS_ANDROID)
-  content::ResourceRequestInfo::WebContentsGetter web_contents_getter =
+  content::WebContents::Getter web_contents_getter =
       GetWebContentsGetter(web_contents);
   DownloadControllerBase::Get()->AcquireFileAccessPermission(
       web_contents_getter, std::move(callback));
diff --git a/chrome/browser/predictors/loading_data_collector.cc b/chrome/browser/predictors/loading_data_collector.cc
index c2ac8a6b..c9f40ac 100644
--- a/chrome/browser/predictors/loading_data_collector.cc
+++ b/chrome/browser/predictors/loading_data_collector.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/history/core/browser/history_service.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/resource_type.h"
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_request.h"
diff --git a/chrome/browser/predictors/loading_test_util.cc b/chrome/browser/predictors/loading_test_util.cc
index 4cb41ef..326def7 100644
--- a/chrome/browser/predictors/loading_test_util.cc
+++ b/chrome/browser/predictors/loading_test_util.cc
@@ -8,7 +8,6 @@
 #include <memory>
 #include <utility>
 
-#include "content/public/browser/resource_request_info.h"
 #include "net/http/http_response_headers.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/url_request_test_util.h"
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc
index 47716f95..8d1c505 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -23,7 +23,6 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/url_utils.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 
 using content::BrowserThread;
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index 312dec20..00a20a6 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -305,3 +305,17 @@
     output_dir = "$root_gen_dir/chrome"
   }
 }
+
+if (enable_webui_tab_strip) {
+  grit("tab_strip_resources") {
+    source = "tab_strip/tab_strip_resources.grd"
+    defines = chrome_grit_defines
+    outputs = [
+      "grit/tab_strip_resources.h",
+      "grit/tab_strip_resources_map.cc",
+      "grit/tab_strip_resources_map.h",
+      "tab_strip_resources.pak",
+    ]
+    output_dir = "$root_gen_dir/chrome"
+  }
+}
diff --git a/chrome/browser/resources/chromeos/BUILD.gn b/chrome/browser/resources/chromeos/BUILD.gn
index 72b6c86..6d5a6073 100644
--- a/chrome/browser/resources/chromeos/BUILD.gn
+++ b/chrome/browser/resources/chromeos/BUILD.gn
@@ -47,7 +47,7 @@
   output_dir = "$root_gen_dir/chrome"
 
   deps = [
-    "//media/capture/video/chromeos/mojo:cros_camera_js",
+    "//media/capture/video/chromeos/mojom:cros_camera_js",
   ]
 
   # The .grd contains references to generated files.
diff --git a/chrome/browser/resources/chromeos/camera/BUILD.gn b/chrome/browser/resources/chromeos/camera/BUILD.gn
index 813d058f..0804b35 100644
--- a/chrome/browser/resources/chromeos/camera/BUILD.gn
+++ b/chrome/browser/resources/chromeos/camera/BUILD.gn
@@ -232,16 +232,16 @@
 copy("chrome_camera_app_mojo_generated") {
   sources = [
     "$root_gen_dir/media/capture/mojom/image_capture.mojom-lite.js",
-    "$root_gen_dir/media/capture/video/chromeos/mojo/camera_common.mojom-lite.js",
-    "$root_gen_dir/media/capture/video/chromeos/mojo/camera_metadata.mojom-lite.js",
-    "$root_gen_dir/media/capture/video/chromeos/mojo/camera_metadata_tags.mojom-lite.js",
-    "$root_gen_dir/media/capture/video/chromeos/mojo/cros_image_capture.mojom-lite.js",
+    "$root_gen_dir/media/capture/video/chromeos/mojom/camera_common.mojom-lite.js",
+    "$root_gen_dir/media/capture/video/chromeos/mojom/camera_metadata.mojom-lite.js",
+    "$root_gen_dir/media/capture/video/chromeos/mojom/camera_metadata_tags.mojom-lite.js",
+    "$root_gen_dir/media/capture/video/chromeos/mojom/cros_image_capture.mojom-lite.js",
     "$root_gen_dir/mojo/public/js/mojo_bindings_lite.js",
   ]
 
   deps = [
     "//media/capture/mojom:image_capture_js",
-    "//media/capture/video/chromeos/mojo:cros_camera_js",
+    "//media/capture/video/chromeos/mojom:cros_camera_js",
     "//mojo/public/js:bindings_lite",
   ]
 
diff --git a/chrome/browser/resources/chromeos/camera/camera_resources.grd b/chrome/browser/resources/chromeos/camera/camera_resources.grd
index 0f24c24..f4da463 100644
--- a/chrome/browser/resources/chromeos/camera/camera_resources.grd
+++ b/chrome/browser/resources/chromeos/camera/camera_resources.grd
@@ -57,19 +57,19 @@
           use_base_dir="false"
           type="BINDATA"/>
       <include name="IDR_CAMERA_CAMERA_COMMON_MOJOM_LITE_JS"
-          file="${root_gen_dir}/media/capture/video/chromeos/mojo/camera_common.mojom-lite.js"
+          file="${root_gen_dir}/media/capture/video/chromeos/mojom/camera_common.mojom-lite.js"
           use_base_dir="false"
           type="BINDATA"/>
       <include name="IDR_CAMERA_CAMERA_METADATA_MOJOM_LITE_JS"
-          file="${root_gen_dir}/media/capture/video/chromeos/mojo/camera_metadata.mojom-lite.js"
+          file="${root_gen_dir}/media/capture/video/chromeos/mojom/camera_metadata.mojom-lite.js"
           use_base_dir="false"
           type="BINDATA"/>
       <include name="IDR_CAMERA_CAMERA_METADATA_TAGS_MOJOM_LITE_JS"
-          file="${root_gen_dir}/media/capture/video/chromeos/mojo/camera_metadata_tags.mojom-lite.js"
+          file="${root_gen_dir}/media/capture/video/chromeos/mojom/camera_metadata_tags.mojom-lite.js"
           use_base_dir="false"
           type="BINDATA"/>
       <include name="IDR_CAMERA_CROS_IMAGE_CAPTURE_MOJOM_LITE_JS"
-          file="${root_gen_dir}/media/capture/video/chromeos/mojo/cros_image_capture.mojom-lite.js"
+          file="${root_gen_dir}/media/capture/video/chromeos/mojom/cros_image_capture.mojom-lite.js"
           use_base_dir="false"
           type="BINDATA"/>
 
diff --git a/chrome/browser/resources/chromeos/camera/src/css/main.css b/chrome/browser/resources/chromeos/camera/src/css/main.css
index ee74beb6..e0335ab 100644
--- a/chrome/browser/resources/chromeos/camera/src/css/main.css
+++ b/chrome/browser/resources/chromeos/camera/src/css/main.css
@@ -460,7 +460,8 @@
   background-image: url(../images/camera_button_mic_off.svg);
 }
 
-#toggle-fps {
+body:not(.multi-fps) #toggle-fps,
+body:not(.video-mode) #toggle-fps {
   display: none;
 }
 
diff --git a/chrome/browser/resources/chromeos/camera/src/js/mojo/BUILD.gn b/chrome/browser/resources/chromeos/camera/src/js/mojo/BUILD.gn
index 9d131abf..2de793e 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/mojo/BUILD.gn
+++ b/chrome/browser/resources/chromeos/camera/src/js/mojo/BUILD.gn
@@ -13,7 +13,7 @@
 js_library("imagecapture") {
   deps = [
     "//media/capture/mojom:image_capture_js_library_for_compile",
-    "//media/capture/video/chromeos/mojo:cros_camera_js_library_for_compile",
+    "//media/capture/video/chromeos/mojom:cros_camera_js_library_for_compile",
   ]
   externs_list = [ "$externs_path/pending.js" ]
 }
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js
index de3b7a76..d576d99 100644
--- a/chrome/browser/resources/local_ntp/customize.js
+++ b/chrome/browser/resources/local_ntp/customize.js
@@ -1896,7 +1896,7 @@
   };
 
   const richerPicker = $(customize.IDS.CUSTOMIZATION_MENU);
-  richerPicker.onclick = function(event) {
+  richerPicker.onmousedown = function(event) {
     richerPicker.classList.add(customize.CLASSES.MOUSE_NAV);
   };
   richerPicker.onkeydown = function(event) {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index aa472e49..917a39c 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -200,6 +200,7 @@
   text-align: initial;
   text-overflow: ellipsis;
   top: 0;
+  user-select: none;
   vertical-align: middle;
   visibility: inherit;
   white-space: nowrap;
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
index b83551d..8920265 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
+++ b/chrome/browser/resources/settings/chromeos/os_settings_menu/os_settings_menu.html
@@ -44,12 +44,15 @@
       /* The "item" draws the icon, text, and rounded background. */
       a > .item {
         align-items: center;
-        border: 1px solid transparent;
+        /* Always apply border so item doesn't shift when focused. */
+        border-color: transparent;
         border-radius: 0 20px 20px 0;
+        border-style: solid;
+        border-width: 1px 1px 1px 0;
         color: var(--menu-text-color);
         display: flex;
         font-weight: 500;
-        margin-inline-end: 2px;  /* Margin so selected outline is visible. */
+        margin-inline-end: 2px;
         min-height: 32px;
         padding-inline-start: 24px;
         pointer-events: none;
diff --git a/chrome/browser/resources/tab_strip/tab_strip.html b/chrome/browser/resources/tab_strip/tab_strip.html
new file mode 100644
index 0000000..8ddf6a3
--- /dev/null
+++ b/chrome/browser/resources/tab_strip/tab_strip.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+  <head>
+    <meta charset="utf-8">
+  </head>
+  <body>
+  </body>
+</html>
diff --git a/chrome/browser/resources/tab_strip/tab_strip_resources.grd b/chrome/browser/resources/tab_strip/tab_strip_resources.grd
new file mode 100644
index 0000000..e9805a9
--- /dev/null
+++ b/chrome/browser/resources/tab_strip/tab_strip_resources.grd
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+  <outputs>
+    <output filename="grit/tab_strip_resources.h" type="rc_header">
+      <emit emit_type='prepend'></emit>
+    </output>
+    <output filename="grit/tab_strip_resources_map.cc"
+            type="resource_file_map_source" />
+    <output filename="grit/tab_strip_resources_map.h"
+            type="resource_map_header" />
+    <output filename="tab_strip_resources.pak" type="data_package" />
+  </outputs>
+  <release seq="1">
+    <structures>
+      <structure
+          name="IDR_TAB_STRIP_HTML"
+          file="tab_strip.html"
+          type="chrome_html"
+          compress="gzip"/>
+    </structures>
+  </release>
+</grit>
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index 1d13ab6c..7cbdbbea 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -48,7 +48,6 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
-#include "content/public/browser/resource_request_info.h"
 #include "services/network/public/cpp/cross_thread_shared_url_loader_factory_info.h"
 #include "services/network/public/cpp/features.h"
 #include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index 7264e4b..4b6a3ef 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -820,7 +820,7 @@
 
 void LocalNtpSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
diff --git a/chrome/browser/search/local_ntp_source.h b/chrome/browser/search/local_ntp_source.h
index fcf2afc..27d422ca 100644
--- a/chrome/browser/search/local_ntp_source.h
+++ b/chrome/browser/search/local_ntp_source.h
@@ -73,7 +73,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string& path) override;
   bool AllowCaching() override;
diff --git a/chrome/browser/search/most_visited_iframe_source.cc b/chrome/browser/search/most_visited_iframe_source.cc
index 3b414d0..39932db 100644
--- a/chrome/browser/search/most_visited_iframe_source.cc
+++ b/chrome/browser/search/most_visited_iframe_source.cc
@@ -60,7 +60,7 @@
 
 void MostVisitedIframeSource::StartDataRequest(
     const std::string& path_and_query,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   GURL url(chrome::kChromeSearchMostVisitedUrl + path_and_query);
   std::string path(url.path());
@@ -170,7 +170,7 @@
 
 void MostVisitedIframeSource::SendJSWithOrigin(
     int resource_id,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   std::string origin;
   if (!GetOrigin(wc_getter, &origin)) {
@@ -186,7 +186,7 @@
 }
 
 bool MostVisitedIframeSource::GetOrigin(
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     std::string* origin) const {
   if (wc_getter.is_null())
     return false;
diff --git a/chrome/browser/search/most_visited_iframe_source.h b/chrome/browser/search/most_visited_iframe_source.h
index e3a7db40..1af6aec 100644
--- a/chrome/browser/search/most_visited_iframe_source.h
+++ b/chrome/browser/search/most_visited_iframe_source.h
@@ -25,7 +25,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path_and_query,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string& path_and_query) override;
   bool AllowCaching() override;
@@ -46,16 +46,15 @@
   // Sends Javascript with an expected postMessage origin interpolated.
   void SendJSWithOrigin(
       int resource_id,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback);
 
   // This is exposed for testing and should not be overridden.
   // Sets |origin| to the URL of the WebContents identified by |wc_getter|.
   // Returns true if successful and false if not, for example if the WebContents
   // does not exist
-  virtual bool GetOrigin(
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      std::string* origin) const;
+  virtual bool GetOrigin(const content::WebContents::Getter& wc_getter,
+                         std::string* origin) const;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MostVisitedIframeSource);
diff --git a/chrome/browser/search/most_visited_iframe_source_unittest.cc b/chrome/browser/search/most_visited_iframe_source_unittest.cc
index ac23d5c4..ddd87b7 100644
--- a/chrome/browser/search/most_visited_iframe_source_unittest.cc
+++ b/chrome/browser/search/most_visited_iframe_source_unittest.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/search/instant_io_context.h"
 #include "chrome/grit/local_ntp_resources.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/test/mock_resource_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -48,14 +47,13 @@
 
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override {}
 
   // RenderFrameHost is hard to mock in concert with everything else, so stub
   // this method out for testing.
-  bool GetOrigin(
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      std::string* origin) const override {
+  bool GetOrigin(const content::WebContents::Getter& wc_getter,
+                 std::string* origin) const override {
     if (origin_.empty())
       return false;
     *origin = origin_;
@@ -91,9 +89,8 @@
   }
 
   void SendJSWithOrigin(int resource_id) {
-    source()->SendJSWithOrigin(
-        resource_id, content::ResourceRequestInfo::WebContentsGetter(),
-        callback_);
+    source()->SendJSWithOrigin(resource_id, content::WebContents::Getter(),
+                               callback_);
   }
 
   bool ShouldService(const std::string& path, int process_id) {
diff --git a/chrome/browser/search/ntp_icon_source.cc b/chrome/browser/search/ntp_icon_source.cc
index c8d0cc1..a7a1f9e7 100644
--- a/chrome/browser/search/ntp_icon_source.cc
+++ b/chrome/browser/search/ntp_icon_source.cc
@@ -280,7 +280,7 @@
 
 void NtpIconSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   favicon::FaviconService* favicon_service =
       FaviconServiceFactory::GetForProfile(profile_,
diff --git a/chrome/browser/search/ntp_icon_source.h b/chrome/browser/search/ntp_icon_source.h
index 9aef5709..3148d2f 100644
--- a/chrome/browser/search/ntp_icon_source.h
+++ b/chrome/browser/search/ntp_icon_source.h
@@ -38,7 +38,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string& path) override;
   bool ShouldServiceRequest(const GURL& url,
diff --git a/chrome/browser/search/search_suggest/search_suggest_service.cc b/chrome/browser/search/search_suggest/search_suggest_service.cc
index 4891190f..cb93ea92 100644
--- a/chrome/browser/search/search_suggest/search_suggest_service.cc
+++ b/chrome/browser/search/search_suggest/search_suggest_service.cc
@@ -24,7 +24,10 @@
 constexpr char kSuggestionHashRegex[] = "[a-z0-9]{4}";
 
 bool ValidateHash(const uint8_t hash[4], std::string& result) {
-  const std::string hash_string(reinterpret_cast<const char*>(hash), 4);
+  if (!hash)
+    return false;
+
+  const std::string hash_string(reinterpret_cast<const char*>(hash), 0, 4);
   result = hash_string;
 
   return re2::RE2::FullMatch(hash_string, kSuggestionHashRegex);
diff --git a/chrome/browser/search/suggestions/suggestions_ui.cc b/chrome/browser/search/suggestions/suggestions_ui.cc
index 39d39f1..a038da4c 100644
--- a/chrome/browser/search/suggestions/suggestions_ui.cc
+++ b/chrome/browser/search/suggestions/suggestions_ui.cc
@@ -28,7 +28,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string& path) override;
 
@@ -51,7 +51,7 @@
 
 void SuggestionsSourceWrapper::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   suggestions_source_.StartDataRequest(path, callback);
 }
diff --git a/chrome/browser/signin/chrome_signin_helper.cc b/chrome/browser/signin/chrome_signin_helper.cc
index 515b7a3..aa29f94 100644
--- a/chrome/browser/signin/chrome_signin_helper.cc
+++ b/chrome/browser/signin/chrome_signin_helper.cc
@@ -39,7 +39,6 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_request_info.h"
-#include "content/public/browser/web_contents.h"
 #include "content/public/common/resource_type.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "net/http/http_response_headers.h"
@@ -91,8 +90,7 @@
 
   // Creates the account reconcilor lock on the UI thread. The lock will be
   // deleted on the UI thread when this wrapper is deleted.
-  void CreateLockOnUI(const content::ResourceRequestInfo::WebContentsGetter&
-                          web_contents_getter) {
+  void CreateLockOnUI(const content::WebContents::Getter& web_contents_getter) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     content::WebContents* web_contents = web_contents_getter.Run();
     if (!web_contents)
@@ -172,8 +170,7 @@
 // opens an incognito window/tab.
 void ProcessMirrorHeaderUIThread(
     ManageAccountsParams manage_accounts_params,
-    const content::ResourceRequestInfo::WebContentsGetter&
-        web_contents_getter) {
+    const content::WebContents::Getter& web_contents_getter) {
 #if defined(OS_CHROMEOS) || defined(OS_ANDROID)
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
@@ -292,8 +289,7 @@
 
 void ProcessDiceHeaderUIThread(
     const DiceResponseParams& dice_params,
-    const content::ResourceRequestInfo::WebContentsGetter&
-        web_contents_getter) {
+    const content::WebContents::Getter& web_contents_getter) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   content::WebContents* web_contents = web_contents_getter.Run();
@@ -442,8 +438,8 @@
 
 ChromeRequestAdapter::~ChromeRequestAdapter() = default;
 
-content::ResourceRequestInfo::WebContentsGetter
-ChromeRequestAdapter::GetWebContentsGetter() const {
+content::WebContents::Getter ChromeRequestAdapter::GetWebContentsGetter()
+    const {
   auto* info = content::ResourceRequestInfo::ForRequest(request_);
   return info->GetWebContentsGetterForRequest();
 }
@@ -471,8 +467,7 @@
 
 ResponseAdapter::~ResponseAdapter() = default;
 
-content::ResourceRequestInfo::WebContentsGetter
-ResponseAdapter::GetWebContentsGetter() const {
+content::WebContents::Getter ResponseAdapter::GetWebContentsGetter() const {
   auto* info = content::ResourceRequestInfo::ForRequest(request_);
   return info->GetWebContentsGetterForRequest();
 }
diff --git a/chrome/browser/signin/chrome_signin_helper.h b/chrome/browser/signin/chrome_signin_helper.h
index 23c8cc63..a008f5b 100644
--- a/chrome/browser/signin/chrome_signin_helper.h
+++ b/chrome/browser/signin/chrome_signin_helper.h
@@ -12,7 +12,8 @@
 #include "base/supports_user_data.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "components/signin/core/browser/signin_header_helper.h"
-#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/resource_type.h"
 
 namespace content_settings {
 class CookieSettings;
@@ -40,8 +41,7 @@
   explicit ChromeRequestAdapter(net::URLRequest* request);
   ~ChromeRequestAdapter() override;
 
-  virtual content::ResourceRequestInfo::WebContentsGetter GetWebContentsGetter()
-      const;
+  virtual content::WebContents::Getter GetWebContentsGetter() const;
   virtual content::ResourceType GetResourceType() const;
   virtual GURL GetReferrerOrigin() const;
 
@@ -59,8 +59,7 @@
   explicit ResponseAdapter(net::URLRequest* request);
   virtual ~ResponseAdapter();
 
-  virtual content::ResourceRequestInfo::WebContentsGetter GetWebContentsGetter()
-      const;
+  virtual content::WebContents::Getter GetWebContentsGetter() const;
   virtual bool IsMainFrame() const;
   virtual GURL GetOrigin() const;
   virtual const net::HttpResponseHeaders* GetHeaders() const;
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
index c9f4f5ca..b8774958 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
@@ -19,7 +19,6 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/resource_context.h"
-#include "content/public/browser/web_contents.h"
 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
 #include "extensions/buildflags/buildflags.h"
 #include "google_apis/gaia/gaia_auth_util.h"
@@ -41,7 +40,7 @@
 
   static void StartProxying(
       content::ResourceContext* resource_context,
-      content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+      content::WebContents::Getter web_contents_getter,
       network::mojom::URLLoaderFactoryRequest request,
       network::mojom::URLLoaderFactoryPtrInfo target_factory) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@@ -203,8 +202,7 @@
 
   ~ProxyRequestAdapter() override = default;
 
-  content::ResourceRequestInfo::WebContentsGetter GetWebContentsGetter()
-      const override {
+  content::WebContents::Getter GetWebContentsGetter() const override {
     return in_progress_request_->factory_->web_contents_getter_;
   }
 
@@ -269,8 +267,7 @@
   ~ProxyResponseAdapter() override = default;
 
   // signin::ResponseAdapter
-  content::ResourceRequestInfo::WebContentsGetter GetWebContentsGetter()
-      const override {
+  content::WebContents::Getter GetWebContentsGetter() const override {
     return in_progress_request_->factory_->web_contents_getter_;
   }
 
@@ -409,7 +406,7 @@
 
 ProxyingURLLoaderFactory::ProxyingURLLoaderFactory(
     std::unique_ptr<HeaderModificationDelegate> delegate,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    content::WebContents::Getter web_contents_getter,
     network::mojom::URLLoaderFactoryRequest loader_request,
     network::mojom::URLLoaderFactoryPtrInfo target_factory,
     DisconnectCallback on_disconnect) {
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.h b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.h
index d9837eb..7d3c6d3e 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.h
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.h
@@ -9,7 +9,7 @@
 #include "base/containers/unique_ptr_adapters.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted_delete_on_sequence.h"
-#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 
@@ -37,7 +37,7 @@
   // by calling MaybeProxyRequest().
   ProxyingURLLoaderFactory(
       std::unique_ptr<HeaderModificationDelegate> delegate,
-      content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+      content::WebContents::Getter web_contents_getter,
       network::mojom::URLLoaderFactoryRequest request,
       network::mojom::URLLoaderFactoryPtrInfo target_factory,
       DisconnectCallback on_disconnect);
@@ -78,12 +78,12 @@
   void RemoveRequest(InProgressRequest* request);
   void MaybeDestroySelf();
 
-  const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter() {
+  const content::WebContents::Getter& web_contents_getter() {
     return web_contents_getter_;
   }
 
   std::unique_ptr<HeaderModificationDelegate> delegate_;
-  content::ResourceRequestInfo::WebContentsGetter web_contents_getter_;
+  content::WebContents::Getter web_contents_getter_;
 
   mojo::BindingSet<network::mojom::URLLoaderFactory> proxy_bindings_;
   std::set<std::unique_ptr<InProgressRequest>, base::UniquePtrComparator>
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
index 53f91cf..f9fa315b 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
@@ -52,7 +52,7 @@
   DISALLOW_COPY_AND_ASSIGN(MockDelegate);
 };
 
-content::ResourceRequestInfo::WebContentsGetter NullWebContentsGetter() {
+content::WebContents::Getter NullWebContentsGetter() {
   return base::BindRepeating([]() -> content::WebContents* { return nullptr; });
 }
 
diff --git a/chrome/browser/signin/chrome_signin_url_loader_throttle.cc b/chrome/browser/signin/chrome_signin_url_loader_throttle.cc
index 35c9e3f7..177c7fd 100644
--- a/chrome/browser/signin/chrome_signin_url_loader_throttle.cc
+++ b/chrome/browser/signin/chrome_signin_url_loader_throttle.cc
@@ -25,8 +25,7 @@
   ~ThrottleRequestAdapter() override = default;
 
   // ChromeRequestAdapter
-  content::ResourceRequestInfo::WebContentsGetter GetWebContentsGetter()
-      const override {
+  content::WebContents::Getter GetWebContentsGetter() const override {
     return throttle_->web_contents_getter_;
   }
 
@@ -85,8 +84,7 @@
   ~ThrottleResponseAdapter() override = default;
 
   // ResponseAdapter
-  content::ResourceRequestInfo::WebContentsGetter GetWebContentsGetter()
-      const override {
+  content::WebContents::Getter GetWebContentsGetter() const override {
     return throttle_->web_contents_getter_;
   }
 
@@ -128,7 +126,7 @@
 std::unique_ptr<URLLoaderThrottle> URLLoaderThrottle::MaybeCreate(
     std::unique_ptr<HeaderModificationDelegate> delegate,
     content::NavigationUIData* navigation_ui_data,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter) {
+    content::WebContents::Getter web_contents_getter) {
   if (!delegate->ShouldInterceptNavigation(navigation_ui_data))
     return nullptr;
 
@@ -200,7 +198,7 @@
 
 URLLoaderThrottle::URLLoaderThrottle(
     std::unique_ptr<HeaderModificationDelegate> delegate,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter)
+    content::WebContents::Getter web_contents_getter)
     : delegate_(std::move(delegate)),
       web_contents_getter_(std::move(web_contents_getter)) {}
 
diff --git a/chrome/browser/signin/chrome_signin_url_loader_throttle.h b/chrome/browser/signin/chrome_signin_url_loader_throttle.h
index 27704f0..6b4ebbbf 100644
--- a/chrome/browser/signin/chrome_signin_url_loader_throttle.h
+++ b/chrome/browser/signin/chrome_signin_url_loader_throttle.h
@@ -7,7 +7,8 @@
 
 #include "base/macros.h"
 #include "base/supports_user_data.h"
-#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/resource_type.h"
 #include "third_party/blink/public/common/loader/url_loader_throttle.h"
 
 namespace content {
@@ -28,7 +29,7 @@
   static std::unique_ptr<URLLoaderThrottle> MaybeCreate(
       std::unique_ptr<HeaderModificationDelegate> delegate,
       content::NavigationUIData* navigation_ui_data,
-      content::ResourceRequestInfo::WebContentsGetter web_contents_getter);
+      content::WebContents::Getter web_contents_getter);
 
   ~URLLoaderThrottle() override;
 
@@ -48,12 +49,11 @@
   class ThrottleRequestAdapter;
   class ThrottleResponseAdapter;
 
-  URLLoaderThrottle(
-      std::unique_ptr<HeaderModificationDelegate> delegate,
-      content::ResourceRequestInfo::WebContentsGetter web_contents_getter);
+  URLLoaderThrottle(std::unique_ptr<HeaderModificationDelegate> delegate,
+                    content::WebContents::Getter web_contents_getter);
 
   const std::unique_ptr<HeaderModificationDelegate> delegate_;
-  const content::ResourceRequestInfo::WebContentsGetter web_contents_getter_;
+  const content::WebContents::Getter web_contents_getter_;
 
   // Information about the current request.
   GURL request_url_;
diff --git a/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc b/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc
index 68f284e..25356cb 100644
--- a/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc
@@ -39,7 +39,7 @@
   DISALLOW_COPY_AND_ASSIGN(MockDelegate);
 };
 
-content::ResourceRequestInfo::WebContentsGetter NullWebContentsGetter() {
+content::WebContents::Getter NullWebContentsGetter() {
   return base::BindRepeating([]() -> content::WebContents* { return nullptr; });
 }
 
diff --git a/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc b/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc
index a0876eb..fa02f694 100644
--- a/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_app_list_sync_test.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/ui/app_list/page_break_constants.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_user_settings.h"
-#include "extensions/browser/extension_system.h"
 
 namespace {
 
@@ -183,8 +182,7 @@
   SyncAppListHelper::GetInstance()->MoveAppToFolder(profile, app_ids[3],
                                                     "folder2");
 
-  app_list::AppListSyncableService compare_service(
-      profile, extensions::ExtensionSystem::Get(profile));
+  app_list::AppListSyncableService compare_service(profile);
 
   // Make sure that that on start, when sync has not been started yet, model
   // content is filled from local prefs and it matches latest state.
diff --git a/chrome/browser/sync/test/integration/sync_auth_test.cc b/chrome/browser/sync/test/integration/sync_auth_test.cc
index e71f7d34..288ec32 100644
--- a/chrome/browser/sync/test/integration/sync_auth_test.cc
+++ b/chrome/browser/sync/test/integration/sync_auth_test.cc
@@ -121,12 +121,12 @@
 
   void DisableTokenFetchRetries() {
     // If ProfileSyncService observes a transient error like SERVICE_UNAVAILABLE
-    // or CONNECTION_FAILED, this means the OAuth2TokenService has given up
-    // trying to reach Gaia. In practice, OA2TS retries a fixed number of times,
-    // but the count is transparent to PSS.
+    // or CONNECTION_FAILED, this means the access token fetcher has given
+    // up trying to reach Gaia. In practice, the access token fetching code
+    // retries a fixed number of times, but the count is transparent to PSS.
     // Disable retries so that we instantly trigger the case where
-    // ProfileSyncService must pick up where OAuth2TokenService left off (in
-    // terms of retries).
+    // ProfileSyncService must pick up where the access token fetcher left off
+    // (in terms of retries).
     signin::DisableAccessTokenFetchRetries(
         IdentityManagerFactory::GetForProfile(GetProfile(0)));
   }
@@ -153,7 +153,7 @@
 }
 
 // Verify that ProfileSyncService continues trying to fetch access tokens
-// when OAuth2TokenService has encountered more than a fixed number of
+// when the access token fetcher has encountered more than a fixed number of
 // HTTP_INTERNAL_SERVER_ERROR (500) errors.
 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryOnInternalServerError500) {
   ASSERT_TRUE(SetupSync());
@@ -168,7 +168,7 @@
 }
 
 // Verify that ProfileSyncService continues trying to fetch access tokens
-// when OAuth2TokenService has encountered more than a fixed number of
+// when the access token fetcher has encountered more than a fixed number of
 // HTTP_FORBIDDEN (403) errors.
 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryOnHttpForbidden403) {
   ASSERT_TRUE(SetupSync());
@@ -183,7 +183,7 @@
 }
 
 // Verify that ProfileSyncService continues trying to fetch access tokens
-// when OAuth2TokenService has encountered a URLRequestStatus of FAILED.
+// when the access token fetcher has encountered a URLRequestStatus of FAILED.
 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryOnRequestFailed) {
   ASSERT_TRUE(SetupSync());
   ASSERT_FALSE(AttemptToTriggerAuthError());
@@ -197,7 +197,7 @@
 }
 
 // Verify that ProfileSyncService continues trying to fetch access tokens
-// when OAuth2TokenService receives a malformed token.
+// when the access token fetcher receives a malformed token.
 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryOnMalformedToken) {
   ASSERT_TRUE(SetupSync());
   ASSERT_FALSE(AttemptToTriggerAuthError());
@@ -211,8 +211,8 @@
 }
 
 // Verify that ProfileSyncService ends up with an INVALID_GAIA_CREDENTIALS auth
-// error when an invalid_grant error is returned by OAuth2TokenService with an
-// HTTP_BAD_REQUEST (400) response code.
+// error when an invalid_grant error is returned by the access token fetcher
+// with an HTTP_BAD_REQUEST (400) response code.
 IN_PROC_BROWSER_TEST_F(SyncAuthTest, InvalidGrant) {
   ASSERT_TRUE(SetupSync());
   ASSERT_FALSE(AttemptToTriggerAuthError());
@@ -227,7 +227,7 @@
 }
 
 // Verify that ProfileSyncService retries after SERVICE_ERROR auth error when
-// an invalid_client error is returned by OAuth2TokenService with an
+// an invalid_client error is returned by the access token fetcher with an
 // HTTP_BAD_REQUEST (400) response code.
 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryInvalidClient) {
   ASSERT_TRUE(SetupSync());
@@ -242,7 +242,8 @@
 }
 
 // Verify that ProfileSyncService retries after REQUEST_CANCELED auth error
-// when OAuth2TokenService has encountered a URLRequestStatus of CANCELED.
+// when the access token fetcher has encountered a URLRequestStatus of
+// CANCELED.
 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryRequestCanceled) {
   ASSERT_TRUE(SetupSync());
   ASSERT_FALSE(AttemptToTriggerAuthError());
@@ -257,7 +258,7 @@
 
 // Verify that ProfileSyncService fails initial sync setup during backend
 // initialization and ends up with an INVALID_GAIA_CREDENTIALS auth error when
-// an invalid_grant error is returned by OAuth2TokenService with an
+// an invalid_grant error is returned by the access token fetcher with an
 // HTTP_BAD_REQUEST (400) response code.
 IN_PROC_BROWSER_TEST_F(SyncAuthTest, FailInitialSetupWithPersistentError) {
   ASSERT_TRUE(SetupClients());
@@ -274,8 +275,8 @@
 
 // Verify that ProfileSyncService fails initial sync setup during backend
 // initialization, but continues trying to fetch access tokens when
-// OAuth2TokenService receives an HTTP_INTERNAL_SERVER_ERROR (500) response
-// code.
+// the access token fetcher receives an HTTP_INTERNAL_SERVER_ERROR (500)
+// response code.
 IN_PROC_BROWSER_TEST_F(SyncAuthTest, RetryInitialSetupWithTransientError) {
   ASSERT_TRUE(SetupClients());
   GetFakeServer()->SetHttpError(net::HTTP_UNAUTHORIZED);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 9eac25dc..a62040c 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3873,6 +3873,15 @@
       "//components/offline_pages/core/prefetch",
     ]
   }
+
+  if (enable_webui_tab_strip) {
+    deps += [ "//chrome/browser/resources:tab_strip_resources" ]
+
+    sources += [
+      "webui/tab_strip/tab_strip_ui.cc",
+      "webui/tab_strip/tab_strip_ui.h",
+    ]
+  }
 }
 
 # In GYP this is part of test_support_common.
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc
index 05808f9c..42b66b0 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -127,11 +127,6 @@
       .OnApps(std::move(deltas));
 }
 
-bool AppIsDefaultForExtensionService(extensions::ExtensionService* service,
-                                     const std::string& id) {
-  return service && AppIsDefault(service->profile(), id);
-}
-
 bool IsUnRemovableDefaultApp(const std::string& id) {
   return id == extension_misc::kChromeAppId ||
          id == extensions::kWebStoreAppId ||
@@ -316,11 +311,9 @@
   app_list::SetAppIsDefaultForTest(profile, id);
 }
 
-AppListSyncableService::AppListSyncableService(
-    Profile* profile,
-    extensions::ExtensionSystem* extension_system)
+AppListSyncableService::AppListSyncableService(Profile* profile)
     : profile_(profile),
-      extension_system_(extension_system),
+      extension_system_(extensions::ExtensionSystem::Get(profile)),
       initial_sync_data_processed_(false),
       first_app_list_sync_(true),
       is_app_service_enabled_(
@@ -345,7 +338,7 @@
   else
     model_updater_ = std::make_unique<ChromeAppListModelUpdater>(profile);
 
-  if (!extension_system) {
+  if (!extension_system_) {
     LOG(ERROR) << "AppListSyncableService created with no ExtensionSystem";
     return;
   }
@@ -695,8 +688,7 @@
   // If there is an existing REMOVE_DEFAULT_APP entry, and the app is
   // installed as a Default app, uninstall the app instead of adding it.
   if (sync_item->item_type == sync_pb::AppListSpecifics::TYPE_APP &&
-      AppIsDefaultForExtensionService(extension_system_->extension_service(),
-                                      item->id())) {
+      AppIsDefault(profile_, item->id())) {
     VLOG(2) << this
             << ": HandleDefaultApp: Uninstall: " << sync_item->ToString();
     UninstallExtension(extension_system_->extension_service(), item->id());
@@ -712,8 +704,7 @@
 
 bool AppListSyncableService::InterceptDeleteDefaultApp(SyncItem* sync_item) {
   if (sync_item->item_type != sync_pb::AppListSpecifics::TYPE_APP ||
-      !AppIsDefaultForExtensionService(extension_system_->extension_service(),
-                                       sync_item->item_id)) {
+      !AppIsDefault(profile_, sync_item->item_id)) {
     return false;
   }
 
@@ -926,8 +917,7 @@
       ++updated_items;
     if (specifics.item_type() != sync_pb::AppListSpecifics::TYPE_FOLDER &&
         !IsUnRemovableDefaultApp(item_id) && !AppIsOem(item_id) &&
-        !AppIsDefaultForExtensionService(extension_system_->extension_service(),
-                                         item_id)) {
+        !AppIsDefault(profile_, item_id)) {
       VLOG(2) << "Syncing non-default item: " << item_id;
       first_app_list_sync_ = false;
     }
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.h b/chrome/browser/ui/app_list/app_list_syncable_service.h
index ab0b352..e0f6b6c 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.h
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.h
@@ -94,9 +94,8 @@
 
   using SyncItemMap = std::map<std::string, std::unique_ptr<SyncItem>>;
 
-  // Populates the model when |extension_system| is ready.
-  AppListSyncableService(Profile* profile,
-                         extensions::ExtensionSystem* extension_system);
+  // Populates the model when |profile|'s extension system is ready.
+  explicit AppListSyncableService(Profile* profile);
 
   ~AppListSyncableService() override;
 
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
index fb0b66c..c5043db 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_factory.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/prefs/pref_service.h"
-#include "extensions/browser/extension_system.h"
 #include "extensions/browser/extension_system_provider.h"
 #include "extensions/browser/extensions_browser_client.h"
 
@@ -47,8 +46,7 @@
   }
   VLOG(1) << "BuildInstanceFor: " << profile->GetDebugName()
           << " (" << profile << ")";
-  return std::make_unique<AppListSyncableService>(
-      profile, extensions::ExtensionSystem::Get(profile));
+  return std::make_unique<AppListSyncableService>(profile);
 }
 
 // static
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
index 3a3175d..cd54a33 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
@@ -25,7 +25,6 @@
 #include "components/sync/model/sync_error_factory.h"
 #include "components/sync/model/sync_error_factory_mock.h"
 #include "components/sync/protocol/sync.pb.h"
-#include "extensions/browser/extension_system.h"
 #include "extensions/common/constants.h"
 
 using crx_file::id_util::GenerateId;
@@ -214,10 +213,6 @@
     TestingBrowserProcess::GetGlobal()->SetProfileManager(
         new ProfileManagerWithoutInit(temp_dir_.GetPath()));
 
-    extensions::ExtensionSystem* extension_system =
-        extensions::ExtensionSystem::Get(profile_.get());
-    DCHECK(extension_system);
-
     model_updater_factory_scope_ = std::make_unique<
         app_list::AppListSyncableService::ScopedModelUpdaterFactoryForTest>(
         base::Bind([]() -> std::unique_ptr<AppListModelUpdater> {
@@ -225,8 +220,7 @@
         }));
 
     app_list_syncable_service_ =
-        std::make_unique<app_list::AppListSyncableService>(profile_.get(),
-                                                           extension_system);
+        std::make_unique<app_list::AppListSyncableService>(profile_.get());
     content::RunAllTasksUntilIdle();
 
     model_updater_test_api_ =
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc
index f128d81a..a37efe8 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc
@@ -21,7 +21,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "extensions/browser/extension_system.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -117,8 +116,8 @@
             },
             profile()));
     // The AppListSyncableService creates the CrostiniAppModelBuilder.
-    sync_service_ = std::make_unique<app_list::AppListSyncableService>(
-        profile_.get(), extensions::ExtensionSystem::Get(profile_.get()));
+    sync_service_ =
+        std::make_unique<app_list::AppListSyncableService>(profile_.get());
     RemoveNonCrostiniApps(sync_service_.get());
   }
 
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc
index 3c1f11e2..58552dd 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 #include <cstring>
+#include <map>
 #include <set>
 #include <string>
 #include <unordered_set>
@@ -82,14 +83,6 @@
 // is somewhat arbitrary, but is roughly equivalent to the 'ter' in 'terminal'.
 constexpr double kCrostiniTerminalRelevanceThreshold = 0.8;
 
-// When ranking with the |QueryBasedAppsRanker| is enabled, this boost is
-// added to all apps that the ranker knows about.
-constexpr float kDefaultRankerScoreBoost = 0.0f;
-
-// When ranking with the |QueryBasedAppsRanker| is enabled, its scores are
-// multiplied by this amount.
-constexpr float kDefaultRankerScoreCoefficient = 0.1f;
-
 // Adds |app_result| to |results| only in case no duplicate apps were already
 // added. Duplicate means the same app but for different domain, Chrome and
 // Android.
@@ -133,20 +126,6 @@
   return min + score * (max - min);
 }
 
-// Normalizes app IDs by removing any scheme prefix and trailing slash:
-// "arc://[id]/" to "[id]". This is necessary because apps launched from
-// different parts of the launcher have differently formatted IDs.
-std::string NormalizeID(const std::string& id) {
-  std::string app_id(id);
-  // No existing scheme names include the delimiter string "://".
-  std::size_t delimiter_index = app_id.find("://");
-  if (delimiter_index != std::string::npos)
-    app_id.erase(0, delimiter_index + 3);
-  if (!app_id.empty() && app_id.back() == '/')
-    app_id.pop_back();
-  return app_id;
-}
-
 }  // namespace
 
 namespace app_list {
@@ -266,8 +245,7 @@
 class AppSearchProvider::DataSource {
  public:
   DataSource(Profile* profile, AppSearchProvider* owner)
-      : profile_(profile),
-        owner_(owner) {}
+      : profile_(profile), owner_(owner) {}
   virtual ~DataSource() {}
 
   virtual void AddApps(Apps* apps) = 0;
@@ -432,8 +410,8 @@
  private:
   void AddApps(AppSearchProvider::Apps* apps,
                const extensions::ExtensionSet& extensions) {
-    extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(
-        profile());
+    extensions::ExtensionPrefs* prefs =
+        extensions::ExtensionPrefs::Get(profile());
     for (const auto& it : extensions) {
       const extensions::Extension* extension = it.get();
 
@@ -826,13 +804,11 @@
 AppSearchProvider::AppSearchProvider(Profile* profile,
                                      AppListControllerDelegate* list_controller,
                                      base::Clock* clock,
-                                     AppListModelUpdater* model_updater,
-                                     AppSearchResultRanker* ranker)
+                                     AppListModelUpdater* model_updater)
     : profile_(profile),
       list_controller_(list_controller),
       model_updater_(model_updater),
       clock_(clock),
-      ranker_(ranker),
       refresh_apps_factory_(this),
       update_results_factory_(this) {
   bool app_service_enabled =
@@ -878,11 +854,6 @@
     data_source->ViewClosing();
 }
 
-void AppSearchProvider::Train(const std::string& id, RankingItemType type) {
-  if (type == RankingItemType::kApp)
-    ranker_->Train(NormalizeID(id));
-}
-
 void AppSearchProvider::RefreshAppsAndUpdateResults() {
   // Clear any pending requests if any.
   refresh_apps_factory_.InvalidateWeakPtrs();
@@ -910,7 +881,6 @@
   std::set<std::string> seen_or_filtered_apps;
   const uint16_t apps_size = apps_.size();
   new_results.reserve(apps_size);
-  const auto& ranker_scores = ranker_->Rank();
 
   for (auto& app : apps_) {
     // Skip apps which cannot be shown as a suggested app.
@@ -936,26 +906,23 @@
         app->data_source()->CreateResult(app->id(), list_controller_, true);
     result->SetTitle(title);
 
-    // Set app->relevance based on the following criteria.
-    const auto find_in_ranker = ranker_scores.find(app->id());
     const auto find_in_app_list = id_to_app_list_index.find(app->id());
     const base::Time time = app->GetLastActivityTime();
 
-    if (find_in_ranker != ranker_scores.end()) {
-      // Case 1: if it's recommended by |ranker_|, set relevance as a score
-      // in [0.67, 1.0].
-      result->set_relevance(ReRange(find_in_ranker->second, 0.67, 1.0));
-    } else if (!time.is_null()) {
-      // Case 2: if it has last activity time or install time, set the relevance
+    // Set app->relevance based on the following criteria. Scores are set within
+    // the range [0, 0.66], allowing the SearchResultRanker some headroom to set
+    // higher rankings without having to re-range these scores.
+    if (!time.is_null()) {
+      // Case 1: if it has last activity time or install time, set the relevance
       // in [0.34, 0.66] based on the time.
       result->UpdateFromLastLaunchedOrInstalledTime(clock_->Now(), time);
       result->set_relevance(ReRange(result->relevance(), 0.34, 0.66));
     } else if (find_in_app_list != id_to_app_list_index.end()) {
-      // Case 3: if it's in the app_list_index, set the relevance in [0.1, 0.33]
+      // Case 2: if it's in the app_list_index, set the relevance in [0.1, 0.33]
       result->set_relevance(
           ReRange(1.0f / (1.0f + find_in_app_list->second), 0.1, 0.33));
     } else {
-      // Case 4: otherwise set the relevance as 0.0f;
+      // Case 3: otherwise set the relevance as 0.0f;
       result->set_relevance(0.0f);
     }
 
@@ -970,26 +937,6 @@
   const size_t apps_size = apps_.size();
   new_results.reserve(apps_size);
 
-  const bool should_rerank =
-      app_list_features::IsQueryBasedAppsRankerEnabled() &&
-      base::GetFieldTrialParamByFeatureAsBool(
-          app_list_features::kEnableQueryBasedAppsRanker,
-          "rank_app_query_results", false) &&
-      ranker_ != nullptr;
-  // Maps app IDs to their score according to |ranker_|.
-  base::flat_map<std::string, float> ranker_scores;
-  float ranker_score_coefficient = kDefaultRankerScoreCoefficient;
-  float ranker_score_boost = kDefaultRankerScoreBoost;
-  if (should_rerank) {
-    ranker_scores = ranker_->Rank();
-    ranker_score_coefficient = base::GetFieldTrialParamByFeatureAsDouble(
-        app_list_features::kEnableQueryBasedAppsRanker, "app_query_coefficient",
-        ranker_score_coefficient);
-    ranker_score_boost = base::GetFieldTrialParamByFeatureAsDouble(
-        app_list_features::kEnableQueryBasedAppsRanker, "app_query_boost",
-        ranker_score_boost);
-  }
-
   const TokenizedString query_terms(query_);
   for (auto& app : apps_) {
     if (!app->searchable())
@@ -1013,15 +960,6 @@
     std::unique_ptr<AppResult> result =
         app->data_source()->CreateResult(app->id(), list_controller_, false);
     result->UpdateFromMatch(*indexed_name, match);
-    if (should_rerank) {
-      const auto find_in_ranker = ranker_scores.find(app->id());
-      if (find_in_ranker != ranker_scores.end()) {
-        result->set_relevance(result->relevance() +
-                              ranker_score_coefficient *
-                                  find_in_ranker->second +
-                              ranker_score_boost);
-      }
-    }
     MaybeAddResult(&new_results, std::move(result), &seen_or_filtered_apps);
   }
   PublishQueriedResultsOrRecommendation(true, &new_results);
@@ -1072,8 +1010,4 @@
   }
 }
 
-std::string AppSearchProvider::NormalizeIDForTest(const std::string& id) {
-  return NormalizeID(id);
-}
-
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.h b/chrome/browser/ui/app_list/search/app_search_provider.h
index b9bc1a7..dea66b2 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.h
+++ b/chrome/browser/ui/app_list/search/app_search_provider.h
@@ -29,8 +29,6 @@
 
 namespace app_list {
 
-class AppSearchResultRanker;
-
 class AppSearchProvider : public SearchProvider {
  public:
   class App;
@@ -44,14 +42,12 @@
   AppSearchProvider(Profile* profile,
                     AppListControllerDelegate* list_controller,
                     base::Clock* clock,
-                    AppListModelUpdater* model_updater,
-                    AppSearchResultRanker* ranker);
+                    AppListModelUpdater* model_updater);
   ~AppSearchProvider() override;
 
   // SearchProvider overrides:
   void Start(const base::string16& query) override;
   void ViewClosing() override;
-  void Train(const std::string& id, RankingItemType type) override;
 
   // Refreshes apps and updates results inline
   void RefreshAppsAndUpdateResults();
@@ -69,8 +65,6 @@
     return open_tabs_ui_delegate_for_testing_;
   }
 
-  static std::string NormalizeIDForTest(const std::string& id);
-
  private:
   void UpdateResults();
   void UpdateRecommendedResults(
@@ -97,7 +91,6 @@
   AppListModelUpdater* const model_updater_;
   base::Clock* clock_;
   std::vector<std::unique_ptr<DataSource>> data_sources_;
-  AppSearchResultRanker* ranker_;
   sync_sessions::OpenTabsUIDelegate* open_tabs_ui_delegate_for_testing_ =
       nullptr;
   base::WeakPtrFactory<AppSearchProvider> refresh_apps_factory_;
diff --git a/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.cc b/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.cc
index a6905c6..2030760 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.cc
@@ -8,55 +8,23 @@
 #include <string>
 #include <utility>
 
-#include "ash/public/cpp/app_list/app_list_features.h"
 #include "base/bind.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/app_list/search/arc/arc_app_shortcut_search_result.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/session/arc_bridge_service.h"
 
-namespace {
-
-// When ranking with the |QueryBasedAppsRanker| is enabled, this boost is
-// added to all shortcuts that the ranker knows about.
-constexpr float kDefaultRankerScoreBoost = 0.0f;
-
-// When ranking with the |QueryBasedAppsRanker| is enabled, its scores are
-// multiplied by this amount.
-constexpr float kDefaultRankerScoreCoefficient = 0.1f;
-
-// Linearly maps |score| to the range [min, max].
-// |score| is assumed to be within [0.0, 1.0]; if it's greater than 1.0
-// then max is returned; if it's less than 0.0, then min is returned.
-// |min| and |max| are assumed to be within [0.0, 1.0].
-float ReRange(const float score, const float min, const float max) {
-  DCHECK_LT(min, max);
-  if (score >= 1.0f)
-    return max;
-  if (score <= 0.0f)
-    return min;
-
-  return min + score * (max - min);
-}
-
-}  // namespace
-
 namespace app_list {
 
 ArcAppShortcutsSearchProvider::ArcAppShortcutsSearchProvider(
     int max_results,
     Profile* profile,
-    AppListControllerDelegate* list_controller,
-    AppSearchResultRanker* ranker)
+    AppListControllerDelegate* list_controller)
     : max_results_(max_results),
       profile_(profile),
       list_controller_(list_controller),
-      ranker_(ranker),
       weak_ptr_factory_(this) {}
 
 ArcAppShortcutsSearchProvider::~ArcAppShortcutsSearchProvider() = default;
@@ -69,68 +37,36 @@
                 GetAppShortcutGlobalQueryItems)
           : nullptr;
 
-  if (!app_instance) {
+  // TODO(931149): Currently we early-exit if the query is empty because we
+  // don't show zero-state arc shortcuts. If this changes in future, remove this
+  // early exit.
+  if (!app_instance || query.empty()) {
     ClearResults();
     return;
   }
 
-  // Invalidate the weak ptr to prevent previous callback run.
-  weak_ptr_factory_.InvalidateWeakPtrs();
-  int max_items = max_results_;
   if (query.empty()) {
-    if (ShouldRerankZeroState()) {
-      max_items = base::GetFieldTrialParamByFeatureAsInt(
-          app_list_features::kEnableZeroStateAppsRanker, "max_items_to_get",
-          10);
-      app_instance->GetAppShortcutGlobalQueryItems(
-          base::UTF16ToUTF8(query), max_items,
-          base::BindOnce(
-              &ArcAppShortcutsSearchProvider::UpdateRecomendedResults,
-              weak_ptr_factory_.GetWeakPtr()));
-    }
-  } else {
-    if (ShouldReRankQueryBased()) {
-      max_items = base::GetFieldTrialParamByFeatureAsInt(
-          app_list_features::kEnableQueryBasedAppsRanker, "max_items_to_get",
-          10);
-    }
     app_instance->GetAppShortcutGlobalQueryItems(
-        base::UTF16ToUTF8(query), max_items,
+        base::UTF16ToUTF8(query), max_results_,
+        base::BindOnce(&ArcAppShortcutsSearchProvider::UpdateRecommendedResults,
+                       weak_ptr_factory_.GetWeakPtr()));
+  } else {
+    // Invalidate the weak ptr to prevent previous callback run.
+    weak_ptr_factory_.InvalidateWeakPtrs();
+    app_instance->GetAppShortcutGlobalQueryItems(
+        base::UTF16ToUTF8(query), max_results_,
         base::BindOnce(
             &ArcAppShortcutsSearchProvider::OnGetAppShortcutGlobalQueryItems,
             weak_ptr_factory_.GetWeakPtr()));
   }
 }
 
-void ArcAppShortcutsSearchProvider::Train(const std::string& id,
-                                          RankingItemType type) {
-  if (type == RankingItemType::kArcAppShortcut && ranker_ != nullptr)
-    ranker_->Train(id);
-}
-
-bool ArcAppShortcutsSearchProvider::ShouldRerankZeroState() const {
-  return app_list_features::IsZeroStateAppsRankerEnabled() &&
-         base::GetFieldTrialParamByFeatureAsBool(
-             app_list_features::kEnableZeroStateAppsRanker,
-             "rank_arc_app_shortcuts", false) &&
-         ranker_ != nullptr;
-}
-
-bool ArcAppShortcutsSearchProvider::ShouldReRankQueryBased() const {
-  return app_list_features::IsQueryBasedAppsRankerEnabled() &&
-         base::GetFieldTrialParamByFeatureAsBool(
-             app_list_features::kEnableQueryBasedAppsRanker,
-             "rank_arc_app_shortcuts", false) &&
-         ranker_ != nullptr;
-}
-
-void ArcAppShortcutsSearchProvider::UpdateRecomendedResults(
+void ArcAppShortcutsSearchProvider::UpdateRecommendedResults(
     std::vector<arc::mojom::AppShortcutItemPtr> shortcut_items) {
   const ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile_);
   DCHECK(arc_prefs);
 
   // Maps app IDs to their score according to |ranker_|
-  base::flat_map<std::string, float> ranker_scores;
   SearchProvider::Results search_results;
   for (auto& item : shortcut_items) {
     const std::string app_id =
@@ -143,23 +79,14 @@
     auto result = std::make_unique<ArcAppShortcutSearchResult>(
         std::move(item), profile_, list_controller_,
         true /*is_recommendation*/);
-    DCHECK(ShouldRerankZeroState());
-    ranker_scores = ranker_->Rank();
-    const auto find_in_ranker = ranker_scores.find(result->id());
-    // TODO(crbug.com/931149): This logic mimics the logic of
-    // AppSearchProvider::UpdateRecommendedResults. Need update to a
-    // logic that fits ArcAppShortcut.
-    if (find_in_ranker != ranker_scores.end()) {
-      // Case 1: If it is recommended by |ranker_|, set the relevance as
-      // a score in a range [0.67, 1.0].
-      result->set_relevance(ReRange(find_in_ranker->second, 0.67, 1.0));
-    } else if (!app_info->install_time.is_null() ||
-               !app_info->last_launch_time.is_null()) {
-      // Case 2: It it has |install_time| or |last_launch_time|, set the
+
+    if (!app_info->install_time.is_null() ||
+        !app_info->last_launch_time.is_null()) {
+      // Case 1: It it has |install_time| or |last_launch_time|, set the
       // relevance to 0.5.
       result->set_relevance(0.5);
     } else {
-      // Case 3: otherwise set relevance to 0.0.
+      // Case 2: otherwise set relevance to 0.0.
       result->set_relevance(0);
     }
     search_results.emplace_back(std::move(result));
@@ -171,20 +98,6 @@
     std::vector<arc::mojom::AppShortcutItemPtr> shortcut_items) {
   const ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile_);
   DCHECK(arc_prefs);
-  // Maps app IDs to their score according to |ranker_|.
-  base::flat_map<std::string, float> ranker_scores;
-  float ranker_score_coefficient = kDefaultRankerScoreCoefficient;
-  float ranker_score_boost = kDefaultRankerScoreBoost;
-  const bool should_rerank = ShouldReRankQueryBased();
-  if (should_rerank) {
-    ranker_scores = ranker_->Rank();
-    ranker_score_coefficient = base::GetFieldTrialParamByFeatureAsDouble(
-        app_list_features::kEnableQueryBasedAppsRanker,
-        "arc_app_shortcuts_query_coefficient", ranker_score_coefficient);
-    ranker_score_boost = base::GetFieldTrialParamByFeatureAsDouble(
-        app_list_features::kEnableQueryBasedAppsRanker,
-        "arc_app_shortcuts_query_boost", ranker_score_boost);
-  }
 
   SearchProvider::Results search_results;
   for (auto& item : shortcut_items) {
@@ -195,22 +108,9 @@
     // Ignore shortcuts for apps that are not present in the launcher.
     if (!app_info || !app_info->show_in_launcher)
       continue;
-    auto result = std::make_unique<ArcAppShortcutSearchResult>(
+    search_results.emplace_back(std::make_unique<ArcAppShortcutSearchResult>(
         std::move(item), profile_, list_controller_,
-        false /*is_recommendation*/);
-    if (should_rerank) {
-      const auto find_in_ranker = ranker_scores.find(result->id());
-      if (find_in_ranker != ranker_scores.end()) {
-        // TODO(crbug.com/931149): currently, relevance scores for app shortcuts
-        // are always 0, but are included here in case this changes. If this
-        // changes, review their range and possibly update this formula.
-        result->set_relevance(result->relevance() +
-                              ranker_score_coefficient *
-                                  find_in_ranker->second +
-                              ranker_score_boost);
-      }
-    }
-    search_results.emplace_back(std::move(result));
+        false /*is_recommendation*/));
   }
   SwapResults(&search_results);
 }
diff --git a/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.h b/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.h
index 548b38f..76015c59 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.h
+++ b/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_APP_SHORTCUTS_SEARCH_PROVIDER_H_
 #define CHROME_BROWSER_UI_APP_LIST_SEARCH_ARC_ARC_APP_SHORTCUTS_SEARCH_PROVIDER_H_
 
-#include <string>
 #include <vector>
 
 #include "base/macros.h"
@@ -19,34 +18,25 @@
 
 namespace app_list {
 
-class AppSearchResultRanker;
-
 class ArcAppShortcutsSearchProvider : public SearchProvider {
  public:
   ArcAppShortcutsSearchProvider(int max_results,
                                 Profile* profile,
-                                AppListControllerDelegate* list_controller,
-                                AppSearchResultRanker* ranker);
+                                AppListControllerDelegate* list_controller);
   ~ArcAppShortcutsSearchProvider() override;
 
   // SearchProvider:
   void Start(const base::string16& query) override;
-  void Train(const std::string& id, RankingItemType type) override;
 
  private:
-  // QueryBased: filter and rerank results for non-empty queries
   void OnGetAppShortcutGlobalQueryItems(
       std::vector<arc::mojom::AppShortcutItemPtr> shortcut_items);
-  // ZeroState: filter and rerank results for empty queries
-  void UpdateRecomendedResults(
+  void UpdateRecommendedResults(
       std::vector<arc::mojom::AppShortcutItemPtr> shortcut_items);
-  bool ShouldRerankZeroState() const;
-  bool ShouldReRankQueryBased() const;
 
   const int max_results_;
   Profile* const profile_;                            // Owned by ProfileInfo.
   AppListControllerDelegate* const list_controller_;  // Owned by AppListClient.
-  AppSearchResultRanker* ranker_;
 
   base::WeakPtrFactory<ArcAppShortcutsSearchProvider> weak_ptr_factory_;
 
diff --git a/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc
index 6eadf9d..a3706ce 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 
 #include "ash/public/cpp/app_list/app_list_features.h"
@@ -21,8 +22,6 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_test.h"
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h"
 #include "chrome/browser/ui/app_list/test/test_app_list_controller_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -52,19 +51,6 @@
     AppListTestBase::TearDown();
   }
 
-  void CreateRanker(const base::Feature& feature,
-                    const std::map<std::string, std::string>& params = {}) {
-    if (!params.empty()) {
-      scoped_feature_list_.InitAndEnableFeatureWithParameters(feature, params);
-      ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-      ranker_ =
-          std::make_unique<AppSearchResultRanker>(temp_dir_.GetPath(),
-                                                  /*is_ephemeral_user=*/false);
-    } else {
-      scoped_feature_list_.InitWithFeatures({}, {feature});
-    }
-  }
-
   arc::mojom::AppInfo CreateAppInfo(const std::string& name,
                                     const std::string& activity,
                                     const std::string& package_name) {
@@ -93,7 +79,6 @@
 
   base::ScopedTempDir temp_dir_;
   base::test::ScopedFeatureList scoped_feature_list_;
-  std::unique_ptr<AppSearchResultRanker> ranker_;
   std::unique_ptr<test::TestAppListControllerDelegate> controller_;
   ArcAppTest arc_test_;
 
@@ -102,8 +87,6 @@
 };
 
 TEST_P(ArcAppShortcutsSearchProviderTest, Basic) {
-  CreateRanker(app_list_features::kEnableZeroStateAppsRanker);
-  EXPECT_EQ(ranker_, nullptr);
   const bool launchable = GetParam();
 
   const std::string app_id = AddArcAppAndShortcut(
@@ -114,7 +97,7 @@
   constexpr char kQuery[] = "shortlabel";
 
   auto provider = std::make_unique<ArcAppShortcutsSearchProvider>(
-      kMaxResults, profile(), controller_.get(), ranker_.get());
+      kMaxResults, profile(), controller_.get());
   EXPECT_TRUE(provider->results().empty());
   arc::IconDecodeRequest::DisableSafeDecodingForTesting();
 
@@ -129,98 +112,6 @@
   }
 }
 
-TEST_F(ArcAppShortcutsSearchProviderTest, RankerIsDisableWithFlag) {
-  CreateRanker(app_list_features::kEnableQueryBasedAppsRanker);
-  EXPECT_EQ(ranker_, nullptr);
-
-  const std::string app_id = AddArcAppAndShortcut(
-      CreateAppInfo("FakeName", "FakeActivity", kFakeAppPackageName), true);
-  const size_t kMaxResults = 4;
-  constexpr char kQuery[] = "shortlabel";
-  constexpr char kPrefix[] = "appshortcutsearch://";
-  constexpr char kShortcutId[] = "/ShortcutId ";
-
-  // Create a search provider and train with kMaxResults shortcuts.
-  auto provider = std::make_unique<ArcAppShortcutsSearchProvider>(
-      kMaxResults, profile(), controller_.get(), ranker_.get());
-  arc::IconDecodeRequest::DisableSafeDecodingForTesting();
-
-  for (size_t i = 0; i < kMaxResults; i++) {
-    provider->Train(
-        base::StrCat({kPrefix, app_id, kShortcutId, base::NumberToString(i)}),
-        RankingItemType::kArcAppShortcut);
-  }
-  provider->Start(base::UTF8ToUTF16(kQuery));
-
-  // Currently, without ranker, relevance scores for app
-  // shortcuts are always 0.
-  const auto& results = provider->results();
-  for (const auto& result : results)
-    EXPECT_EQ(result->relevance(), 0);
-}
-
-TEST_F(ArcAppShortcutsSearchProviderTest, RankerImproveScores) {
-  CreateRanker(app_list_features::kEnableQueryBasedAppsRanker,
-               {{"rank_arc_app_shortcuts", "true"}, {"max_items_to_get", "6"}});
-  EXPECT_NE(ranker_, nullptr);
-
-  const std::string app_id = AddArcAppAndShortcut(
-      CreateAppInfo("FakeName", "FakeActivity", kFakeAppPackageName), true);
-  const size_t kMaxResults = 6;
-  constexpr char kQuery[] = "shortlabel";
-  constexpr char kPrefix[] = "appshortcutsearch://";
-  constexpr char kShortcutId[] = "/ShortcutId ";
-
-  // Create a search provider and train with kMaxResults shortcuts.
-  auto provider = std::make_unique<ArcAppShortcutsSearchProvider>(
-      kMaxResults, profile(), controller_.get(), ranker_.get());
-  arc::IconDecodeRequest::DisableSafeDecodingForTesting();
-
-  for (size_t i = 0; i < kMaxResults; i++) {
-    provider->Train(
-        base::StrCat({kPrefix, app_id, kShortcutId, base::NumberToString(i)}),
-        RankingItemType::kArcAppShortcut);
-  }
-  provider->Start(base::UTF8ToUTF16(kQuery));
-  // Verify search results to see whether they were increased.
-  const auto& results = provider->results();
-  for (const auto& result : results)
-    EXPECT_GT(result->relevance(), 0);
-}
-
-TEST_F(ArcAppShortcutsSearchProviderTest, EmptyQueries) {
-  CreateRanker(app_list_features::kEnableZeroStateAppsRanker,
-               {{"rank_arc_app_shortcuts", "true"}, {"max_items_to_get", "6"}});
-  EXPECT_NE(ranker_, nullptr);
-
-  const std::string app_id = AddArcAppAndShortcut(
-      CreateAppInfo("FakeName", "FakeActivity", kFakeAppPackageName), true);
-  const size_t kMaxResults = 6;
-  constexpr char kQuery[] = "";
-  constexpr char kPrefix[] = "appshortcutsearch://";
-  constexpr char kShortcutId[] = "/ShortcutId ";
-
-  // Create a search provider
-  auto provider = std::make_unique<ArcAppShortcutsSearchProvider>(
-      kMaxResults, profile(), controller_.get(), ranker_.get());
-  arc::IconDecodeRequest::DisableSafeDecodingForTesting();
-
-  for (size_t i = 0; i < kMaxResults; i++) {
-    provider->Train(
-        base::StrCat({kPrefix, app_id, kShortcutId, base::NumberToString(i)}),
-        RankingItemType::kArcAppShortcut);
-  }
-  provider->Start(base::UTF8ToUTF16(kQuery));
-  // Verify search results.
-  const auto& results = provider->results();
-  EXPECT_EQ(results.size(), kMaxResults);
-  for (const auto& result : results) {
-    EXPECT_EQ(ash::SearchResultDisplayType::kRecommendation,
-              result->display_type());
-    EXPECT_GT(result->relevance(), 0);
-  }
-}
-
 INSTANTIATE_TEST_SUITE_P(, ArcAppShortcutsSearchProviderTest, testing::Bool());
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_controller.cc b/chrome/browser/ui/app_list/search/search_controller.cc
index 9c3f1b46..e89c4a9 100644
--- a/chrome/browser/ui/app_list/search/search_controller.cc
+++ b/chrome/browser/ui/app_list/search/search_controller.cc
@@ -23,9 +23,7 @@
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
 #include "content/public/browser/system_connector.h"
@@ -72,9 +70,6 @@
                                    AppListControllerDelegate* list_controller,
                                    Profile* profile)
     : mixer_(std::make_unique<Mixer>(model_updater)),
-      app_ranker_(std::make_unique<AppSearchResultRanker>(
-          profile->GetPath(),
-          chromeos::ProfileHelper::IsEphemeralUserProfile(profile))),
       list_controller_(list_controller) {
   std::unique_ptr<SearchResultRanker> ranker =
       std::make_unique<SearchResultRanker>(profile,
@@ -185,10 +180,6 @@
   return nullptr;
 }
 
-AppSearchResultRanker* SearchController::GetAppSearchResultRanker() {
-  return app_ranker_.get();
-}
-
 SearchResultRanker* SearchController::GetNonAppSearchResultRanker() {
   return mixer_->GetNonAppSearchResultRanker();
 }
diff --git a/chrome/browser/ui/app_list/search/search_controller.h b/chrome/browser/ui/app_list/search/search_controller.h
index 543db34..13ba625 100644
--- a/chrome/browser/ui/app_list/search/search_controller.h
+++ b/chrome/browser/ui/app_list/search/search_controller.h
@@ -88,7 +88,6 @@
   std::unique_ptr<Mixer> mixer_;
   using Providers = std::vector<std::unique_ptr<SearchProvider>>;
   Providers providers_;
-  std::unique_ptr<AppSearchResultRanker> app_ranker_;
   AppListControllerDelegate* list_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchController);
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc
index 46ef031..3d728262 100644
--- a/chrome/browser/ui/app_list/search/search_controller_factory.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -72,8 +72,6 @@
       std::make_unique<SearchController>(model_updater, list_controller,
                                          profile);
 
-  AppSearchResultRanker* app_ranker = controller->GetAppSearchResultRanker();
-
   // Add mixer groups. There are four main groups: answer card, apps
   // and omnibox. Each group has a "soft" maximum number of results. However, if
   // a query turns up very few results, the mixer may take more than this
@@ -88,10 +86,10 @@
   size_t omnibox_group_id = controller->AddGroup(kMaxOmniboxResults, 1.0, 0.0);
 
   // Add search providers.
-  controller->AddProvider(apps_group_id, std::make_unique<AppSearchProvider>(
-                                             profile, list_controller,
-                                             base::DefaultClock::GetInstance(),
-                                             model_updater, app_ranker));
+  controller->AddProvider(
+      apps_group_id, std::make_unique<AppSearchProvider>(
+                         profile, list_controller,
+                         base::DefaultClock::GetInstance(), model_updater));
   controller->AddProvider(omnibox_group_id, std::make_unique<OmniboxProvider>(
                                                 profile, list_controller));
   if (app_list_features::IsAnswerCardEnabled()) {
@@ -152,7 +150,7 @@
     controller->AddProvider(
         app_shortcut_group_id,
         std::make_unique<ArcAppShortcutsSearchProvider>(
-            kMaxAppShortcutResults, profile, list_controller, app_ranker));
+            kMaxAppShortcutResults, profile, list_controller));
   }
 
   return controller;
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc b/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc
index 0d5be3b9..ae52d287 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.cc
@@ -90,6 +90,17 @@
   return RankingItemType::kApp;
 }
 
+std::string NormalizeAppId(const std::string& id) {
+  std::string app_id(id);
+  // No existing scheme names include the delimiter string "://".
+  std::size_t delimiter_index = app_id.find("://");
+  if (delimiter_index != std::string::npos)
+    app_id.erase(0, delimiter_index + 3);
+  if (!app_id.empty() && app_id.back() == '/')
+    app_id.pop_back();
+  return app_id;
+}
+
 std::string SimplifyUrlId(const std::string& url_id) {
   std::string result(url_id);
 
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h b/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h
index 9f11f118..29cc6450 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h
@@ -39,6 +39,11 @@
 RankingItemType RankingItemTypeFromChromeAppListItem(
     const ChromeAppListItem& item);
 
+// Normalizes app IDs by removing any scheme prefix and trailing slash:
+// "arc://[id]/" to "[id]". This is necessary because apps launched from
+// different parts of the launcher have differently formatted IDs.
+std::string NormalizeAppId(const std::string& id);
+
 // Given a search result ID representing a URL, removes some components of the
 // URL such as the query and fragment. This is intended to normalize URLs that
 // should be considered the same for the purposes of ranking.
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util_unittest.cc
index 0dd6086..f44dbdaf 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util_unittest.cc
@@ -102,4 +102,18 @@
             "docs.google.com/edit/hash/view");
 }
 
+TEST_F(RankingItemUtilTest, NormalizeAppID) {
+  const std::string raw_id = "mgndgikekgjfcpckkfioiadnlibdjbkf";
+  const std::string id_with_scheme =
+      "chrome-extension://mgndgikekgjfcpckkfioiadnlibdjbkf";
+  const std::string id_with_slash = "mgndgikekgjfcpckkfioiadnlibdjbkf/";
+  const std::string id_with_scheme_and_slash =
+      "chrome-extension://mgndgikekgjfcpckkfioiadnlibdjbkf/";
+
+  EXPECT_EQ(NormalizeAppId(raw_id), raw_id);
+  EXPECT_EQ(NormalizeAppId(id_with_scheme), raw_id);
+  EXPECT_EQ(NormalizeAppId(id_with_slash), raw_id);
+  EXPECT_EQ(NormalizeAppId(id_with_scheme_and_slash), raw_id);
+}
+
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
index 4be36f9..04cc0ff2 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
+#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h"
 #include "url/gurl.h"
@@ -38,7 +39,7 @@
 constexpr char kLogFileOpenType[] = "RecurrenceRanker.LogFileOpenType";
 
 // Represents each model used within the SearchResultRanker.
-enum class Model { NONE, MIXED_TYPES };
+enum class Model { NONE, APPS, MIXED_TYPES };
 
 // Returns the model relevant for predicting launches for results with the given
 // |type|.
@@ -51,6 +52,10 @@
     case RankingItemType::kOmniboxHistory:
     case RankingItemType::kOmniboxSearch:
       return Model::MIXED_TYPES;
+    // Currently we don't rank arc app shortcuts. If this changes, add a case
+    // here.
+    case RankingItemType::kApp:
+      return Model::APPS;
     default:
       return Model::NONE;
   }
@@ -99,11 +104,25 @@
         return SimplifyGoogleDocsUrlId(id);
       else
         return SimplifyUrlId(id);
+    case RankingItemType::kApp:
+      return NormalizeAppId(id);
     default:
       return id;
   }
 }
 
+// Linearly maps |score| to the range [min, max].
+// |score| is assumed to be within [0.0, 1.0]; if it's greater than 1.0
+// then max is returned; if it's less than 0.0, then min is returned.
+float ReRange(const float score, const float min, const float max) {
+  if (score >= 1.0f)
+    return max;
+  if (score <= 0.0f)
+    return min;
+
+  return min + score * (max - min);
+}
+
 }  // namespace
 
 SearchResultRanker::SearchResultRanker(Profile* profile,
@@ -199,6 +218,10 @@
         profile_->GetPath().AppendASCII("zero_state_mixed_types_ranker.proto"),
         config, chromeos::ProfileHelper::IsEphemeralUserProfile(profile_));
   }
+
+  app_ranker_ = std::make_unique<AppSearchResultRanker>(
+      profile_->GetPath(),
+      chromeos::ProfileHelper::IsEphemeralUserProfile(profile_));
 }
 
 void SearchResultRanker::FetchRankings(const base::string16& query) {
@@ -218,6 +241,9 @@
     query_mixed_ranks_ =
         query_based_mixed_types_ranker_->Rank(base::UTF16ToUTF8(query));
   }
+
+  if (app_ranker_)
+    app_ranks_ = app_ranker_->Rank();
 }
 
 void SearchResultRanker::Rank(Mixer::SortedResults* results) {
@@ -252,6 +278,11 @@
               3.0);
         }
       }
+    } else if (model == Model::APPS && app_ranker_) {
+      const auto& it = app_ranks_.find(result.result->id());
+      if (it != app_ranks_.end()) {
+        result.score = ReRange(it->second, 0.67, 1.0);
+      }
     }
   }
 }
@@ -270,7 +301,8 @@
         static_cast<int>(app_launch_data.launched_from));
   }
 
-  if (ModelForType(app_launch_data.ranking_item_type) == Model::MIXED_TYPES) {
+  auto model = ModelForType(app_launch_data.ranking_item_type);
+  if (model == Model::MIXED_TYPES) {
     if (results_list_group_ranker_) {
       results_list_group_ranker_->Record(base::NumberToString(
           static_cast<int>(app_launch_data.ranking_item_type)));
@@ -279,6 +311,8 @@
           NormalizeId(app_launch_data.id, app_launch_data.ranking_item_type),
           app_launch_data.query);
     }
+  } else if (model == Model::APPS) {
+    app_ranker_->Train(NormalizeAppId(app_launch_data.id));
   }
 }
 
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
index 8b1f09ef..24348a9 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h
@@ -21,6 +21,7 @@
 #include "chrome/browser/ui/app_list/search/mixer.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_data.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_event_logger.h"
+#include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_util.h"
 
 namespace app_list {
@@ -115,6 +116,10 @@
   // TODO(931149): Move the AppSearchResultRanker instance and associated logic
   // to here.
 
+  // Ranks apps and arc app shortcuts on-device.
+  std::unique_ptr<AppSearchResultRanker> app_ranker_;
+  base::flat_map<std::string, float> app_ranks_;
+
   Profile* profile_;
 };
 
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
index dcc7b6c..5b0a5e64 100644
--- a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
+++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
@@ -188,6 +188,39 @@
                                               HasId("B"), HasId("A"))));
 }
 
+TEST_F(SearchResultRankerTest, AppModelImprovesScores) {
+  auto ranker = MakeRanker(false);
+  ranker->InitializeRankers();
+  Wait();
+
+  AppLaunchData app_A;
+  app_A.id = "A";
+  app_A.ranking_item_type = RankingItemType::kApp;
+
+  AppLaunchData app_B;
+  app_B.id = "B";
+  app_B.ranking_item_type = RankingItemType::kApp;
+
+  for (int i = 0; i < 20; ++i) {
+    ranker->Train(app_A);
+    ranker->Train(app_B);
+    ranker->Train(app_A);
+  }
+  ranker->FetchRankings(base::string16());
+
+  auto results =
+      MakeSearchResults({"A", "B", "C", "D"},
+                        {ResultType::kInstalledApp, ResultType::kInstalledApp,
+                         ResultType::kInstalledApp, ResultType::kInstalledApp},
+                        {0.1f, 0.2f, 0.3f, 0.4f});
+
+  ranker->Rank(&results);
+  // The relevance scores put D > C > B > A, but we've trained on A the most,
+  // B half as much, and C and D not at all. So we expect A > B > D > C.
+  EXPECT_THAT(results, WhenSorted(ElementsAre(HasId("A"), HasId("B"),
+                                              HasId("D"), HasId("C"))));
+}
+
 TEST_F(SearchResultRankerTest, DefaultQueryMixedModelImprovesScores) {
   // Without the |use_category_model| parameter, the ranker defaults to the item
   // model.  With the |config| parameter, the ranker uses the default predictor
diff --git a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
index 3e1b4d6..b92626b 100644
--- a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
@@ -85,8 +85,6 @@
 
 constexpr char kSettingsInternalName[] = "Settings";
 
-constexpr bool kEphemeralUser = true;
-
 // Waits for base::Time::Now() is updated.
 void WaitTimeUpdated() {
   base::RunLoop run_loop;
@@ -123,11 +121,8 @@
 
   void CreateSearch() {
     clock_.SetNow(kTestCurrentTime);
-    // Create ranker here so that tests can modify feature flags.
-    ranker_ = std::make_unique<AppSearchResultRanker>(temp_dir_.GetPath(),
-                                                      kEphemeralUser);
     app_search_ = std::make_unique<AppSearchProvider>(
-        profile_.get(), nullptr, &clock_, model_updater_.get(), ranker_.get());
+        profile_.get(), nullptr, &clock_, model_updater_.get());
   }
 
   void CreateSearchWithContinueReading() {
@@ -250,11 +245,6 @@
   const SearchProvider::Results& results() { return app_search_->results(); }
   ArcAppTest& arc_test() { return arc_test_; }
 
-  // Train the |app_search| provider with id.
-  void Train(const std::string& id) {
-    app_search_->Train(id, RankingItemType::kApp);
-  }
-
   void CallViewClosing() { app_search_->ViewClosing(); }
 
   sync_sessions::SyncedSessionTracker* session_tracker() {
@@ -268,7 +258,6 @@
   std::unique_ptr<FakeAppListModelUpdater> model_updater_;
   std::unique_ptr<AppSearchProvider> app_search_;
   std::unique_ptr<::test::TestAppListControllerDelegate> controller_;
-  std::unique_ptr<AppSearchResultRanker> ranker_;
   ArcAppTest arc_test_;
 
   // For continue reading.
@@ -314,21 +303,6 @@
               result == "Fake App 1,Packaged App 1");
 }
 
-TEST_F(AppSearchProviderTest, NormalizeAppID) {
-  const std::string raw_id = "mgndgikekgjfcpckkfioiadnlibdjbkf";
-  const std::string id_with_scheme =
-      "chrome-extension://mgndgikekgjfcpckkfioiadnlibdjbkf";
-  const std::string id_with_slash = "mgndgikekgjfcpckkfioiadnlibdjbkf/";
-  const std::string id_with_scheme_and_slash =
-      "chrome-extension://mgndgikekgjfcpckkfioiadnlibdjbkf/";
-
-  EXPECT_EQ(AppSearchProvider::NormalizeIDForTest(raw_id), raw_id);
-  EXPECT_EQ(AppSearchProvider::NormalizeIDForTest(id_with_scheme), raw_id);
-  EXPECT_EQ(AppSearchProvider::NormalizeIDForTest(id_with_slash), raw_id);
-  EXPECT_EQ(AppSearchProvider::NormalizeIDForTest(id_with_scheme_and_slash),
-            raw_id);
-}
-
 TEST_F(AppSearchProviderTest, DisableAndEnable) {
   CreateSearch();
 
@@ -671,50 +645,6 @@
             RunQuery(""));
 }
 
-TEST_F(AppSearchProviderTest, FetchRecommendationsFromRanker) {
-  base::test::ScopedFeatureList scoped_feature_list_;
-  scoped_feature_list_.InitWithFeatures(
-      {app_list_features::kEnableZeroStateAppsRanker}, {});
-  CreateSearch();
-
-  extensions::ExtensionPrefs* prefs =
-      extensions::ExtensionPrefs::Get(profile_.get());
-
-  prefs->SetLastLaunchTime(kHostedAppId, base::Time::FromInternalValue(20));
-  prefs->SetLastLaunchTime(kPackagedApp1Id, base::Time::FromInternalValue(10));
-  prefs->SetLastLaunchTime(kPackagedApp2Id, base::Time::FromInternalValue(5));
-  EXPECT_EQ("Hosted App,Packaged App 1,Packaged App 2,Settings,Camera",
-            RunQuery(""));
-
-  Train(kPackagedApp2Id);
-  Train(kPackagedApp2Id);
-  Train(kPackagedApp1Id);
-  EXPECT_EQ("Packaged App 2,Packaged App 1,Hosted App,Settings,Camera",
-            RunQuery(""));
-}
-
-TEST_F(AppSearchProviderTest, RankerIsDisabledWithFlag) {
-  base::test::ScopedFeatureList scoped_feature_list_;
-  scoped_feature_list_.InitWithFeatures(
-      {}, {app_list_features::kEnableZeroStateAppsRanker});
-  CreateSearch();
-
-  extensions::ExtensionPrefs* prefs =
-      extensions::ExtensionPrefs::Get(profile_.get());
-
-  prefs->SetLastLaunchTime(kHostedAppId, base::Time::FromInternalValue(20));
-  prefs->SetLastLaunchTime(kPackagedApp1Id, base::Time::FromInternalValue(10));
-  prefs->SetLastLaunchTime(kPackagedApp2Id, base::Time::FromInternalValue(5));
-  EXPECT_EQ("Hosted App,Packaged App 1,Packaged App 2,Settings,Camera",
-            RunQuery(""));
-
-  Train(kPackagedApp2Id);
-  Train(kPackagedApp2Id);
-  Train(kPackagedApp1Id);
-  EXPECT_EQ("Hosted App,Packaged App 1,Packaged App 2,Settings,Camera",
-            RunQuery(""));
-}
-
 TEST_F(AppSearchProviderTest, FilterDuplicate) {
   arc_test().SetUp(profile());
 
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h
index b7e42ee..2e272c9 100644
--- a/chrome/browser/ui/browser_dialogs.h
+++ b/chrome/browser/ui/browser_dialogs.h
@@ -17,7 +17,6 @@
 #include "chrome/browser/ui/bookmarks/bookmark_editor.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/native_file_system_permission_context.h"
-#include "content/public/browser/resource_request_info.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/native_widget_types.h"
 
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 836724fb..efa2ac0 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -460,8 +460,8 @@
       bool is_source_keyboard) = 0;
 
   // Shows User Happiness Tracking Survey's invitation bubble anchored to the
-  // app menu button.
-  virtual void ShowHatsBubbleFromAppMenuButton() = 0;
+  // app menu button that will lead to a survey identified by |site_id|.
+  virtual void ShowHatsBubbleFromAppMenuButton(const std::string& site_id) = 0;
 
   // Executes |command| registered by |extension|.
   virtual void ExecuteExtensionCommand(const extensions::Extension* extension,
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc
index 0b955619..b03d31af 100644
--- a/chrome/browser/ui/hats/hats_service.cc
+++ b/chrome/browser/ui/hats/hats_service.cc
@@ -85,7 +85,7 @@
   if (ShouldShowSurvey(kHatsSurveyTriggerSatisfaction)) {
     Browser* browser = chrome::FindLastActive();
     if (browser && browser->is_type_tabbed()) {
-      browser->window()->ShowHatsBubbleFromAppMenuButton();
+      browser->window()->ShowHatsBubbleFromAppMenuButton(en_site_id_);
 
       DictionaryPrefUpdate update(profile_->GetPrefs(),
                                   prefs::kHatsSurveyMetadata);
diff --git a/chrome/browser/ui/input_method/input_method_engine.cc b/chrome/browser/ui/input_method/input_method_engine.cc
index 05cec7a..ca35ec0 100644
--- a/chrome/browser/ui/input_method/input_method_engine.cc
+++ b/chrome/browser/ui/input_method/input_method_engine.cc
@@ -114,15 +114,6 @@
   }
 }
 
-void InputMethodEngine::DeleteSurroundingTextToInputContext(
-    int offset,
-    size_t number_of_chars) {
-  ui::IMEInputContextHandlerInterface* input_context =
-      ui::IMEBridge::Get()->GetInputContextHandler();
-  if (input_context)
-    input_context->DeleteSurroundingText(offset, number_of_chars);
-}
-
 bool InputMethodEngine::SendKeyEvent(ui::KeyEvent* event,
                                      const std::string& code) {
   DCHECK(event);
@@ -149,13 +140,6 @@
   return true;
 }
 
-void InputMethodEngine::ConfirmCompositionText() {
-  ui::IMEInputContextHandlerInterface* input_context =
-      ui::IMEBridge::Get()->GetInputContextHandler();
-  if (input_context)
-    input_context->ConfirmCompositionText();
-}
-
 bool InputMethodEngine::IsActive() const {
   return true;
 }
diff --git a/chrome/browser/ui/input_method/input_method_engine.h b/chrome/browser/ui/input_method/input_method_engine.h
index dbed7431..0e080b0f 100644
--- a/chrome/browser/ui/input_method/input_method_engine.h
+++ b/chrome/browser/ui/input_method/input_method_engine.h
@@ -37,10 +37,7 @@
       const std::vector<ui::ImeTextSpan>& text_spans) override;
   void CommitTextToInputContext(int context_id,
                                 const std::string& text) override;
-  void DeleteSurroundingTextToInputContext(int offset,
-                                           size_t number_of_chars) override;
   bool SendKeyEvent(ui::KeyEvent* ui_event, const std::string& code) override;
-  void ConfirmCompositionText() override;
   bool IsActive() const override;
 
   std::string GetExtensionId() const;
diff --git a/chrome/browser/ui/input_method/input_method_engine_base.cc b/chrome/browser/ui/input_method/input_method_engine_base.cc
index 40ee0f2..46a3344 100644
--- a/chrome/browser/ui/input_method/input_method_engine_base.cc
+++ b/chrome/browser/ui/input_method/input_method_engine_base.cc
@@ -150,8 +150,6 @@
     : current_input_type_(ui::TEXT_INPUT_TYPE_NONE),
       context_id_(0),
       next_context_id_(1),
-      composition_text_(new ui::CompositionText()),
-      composition_cursor_(0),
       profile_(nullptr),
       next_request_id_(1),
       composition_changed_(false),
@@ -212,12 +210,10 @@
   std::string last_component_id{active_component_id_};
   active_component_id_.clear();
   ConfirmCompositionText();
-  composition_text_.reset(new ui::CompositionText());
   observer_->OnDeactivated(last_component_id);
 }
 
 void InputMethodEngineBase::Reset() {
-  composition_text_.reset(new ui::CompositionText());
   observer_->OnReset(active_component_id_);
 }
 
@@ -276,9 +272,7 @@
     return false;
   }
 
-  composition_cursor_ = 0;
-  composition_text_.reset(new ui::CompositionText());
-  UpdateComposition(*composition_text_, composition_cursor_, false);
+  UpdateComposition(ui::CompositionText(), 0, false);
   return true;
 }
 
@@ -367,12 +361,10 @@
     return false;
   }
 
-  composition_cursor_ = cursor;
-  composition_text_.reset(new ui::CompositionText());
-  composition_text_->text = base::UTF8ToUTF16(text);
-
-  composition_text_->selection.set_start(selection_start);
-  composition_text_->selection.set_end(selection_end);
+  ui::CompositionText composition_text;
+  composition_text.text = base::UTF8ToUTF16(text);
+  composition_text.selection.set_start(selection_start);
+  composition_text.selection.set_end(selection_end);
 
   // TODO: Add support for displaying selected text in the composition string.
   for (auto segment = segments.begin(); segment != segments.end(); ++segment) {
@@ -395,11 +387,11 @@
 
     ime_text_span.start_offset = segment->start;
     ime_text_span.end_offset = segment->end;
-    composition_text_->ime_text_spans.push_back(ime_text_span);
+    composition_text.ime_text_spans.push_back(ime_text_span);
   }
 
   // TODO(nona): Makes focus out mode configuable, if necessary.
-  UpdateComposition(*composition_text_, composition_cursor_, true);
+  UpdateComposition(composition_text, cursor, true);
   return true;
 }
 
@@ -420,11 +412,7 @@
 
   // When there is composition text, commit it to the text field first before
   // changing the composition range.
-  if (!composition_text_->text.empty()) {
-    const std::string composition_text_utf8 =
-        base::UTF16ToUTF8(composition_text_->text);
-    CommitTextToInputContext(context_id, composition_text_utf8);
-  }
+  ConfirmCompositionText();
 
   std::vector<ui::ImeTextSpan> text_spans;
   for (const auto& segment : segments) {
@@ -490,4 +478,20 @@
   return request_id;
 }
 
+void InputMethodEngineBase::DeleteSurroundingTextToInputContext(
+    int offset,
+    size_t number_of_chars) {
+  ui::IMEInputContextHandlerInterface* input_context =
+      ui::IMEBridge::Get()->GetInputContextHandler();
+  if (input_context)
+    input_context->DeleteSurroundingText(offset, number_of_chars);
+}
+
+void InputMethodEngineBase::ConfirmCompositionText() {
+  ui::IMEInputContextHandlerInterface* input_context =
+      ui::IMEBridge::Get()->GetInputContextHandler();
+  if (input_context)
+    input_context->ConfirmCompositionText();
+}
+
 }  // namespace input_method
diff --git a/chrome/browser/ui/input_method/input_method_engine_base.h b/chrome/browser/ui/input_method/input_method_engine_base.h
index d29b62c..b92acf9 100644
--- a/chrome/browser/ui/input_method/input_method_engine_base.h
+++ b/chrome/browser/ui/input_method/input_method_engine_base.h
@@ -225,13 +225,12 @@
   virtual void CommitTextToInputContext(int context_id,
                                         const std::string& text) = 0;
   // Notifies InputContextHandler to delete surrounding text.
-  virtual void DeleteSurroundingTextToInputContext(int offset,
-                                                   size_t number_of_chars) = 0;
+  void DeleteSurroundingTextToInputContext(int offset, size_t number_of_chars);
   // Sends the key event to the window tree host.
   virtual bool SendKeyEvent(ui::KeyEvent* ui_event,
                             const std::string& code) = 0;
   // Notifies InputContextHandler to commit any composition text.
-  virtual void ConfirmCompositionText() = 0;
+  void ConfirmCompositionText();
 
   ui::TextInputType current_input_type_;
 
@@ -250,10 +249,6 @@
   // The observer object recieving events for this IME.
   std::unique_ptr<InputMethodEngineBase::Observer> observer_;
 
-  // The current preedit text, and it's cursor position.
-  std::unique_ptr<ui::CompositionText> composition_text_;
-  int composition_cursor_;
-
   Profile* profile_;
 
   using RequestMap =
diff --git a/chrome/browser/ui/libgtkui/native_theme_gtk.cc b/chrome/browser/ui/libgtkui/native_theme_gtk.cc
index 3044d7b1..0929cd7a 100644
--- a/chrome/browser/ui/libgtkui/native_theme_gtk.cc
+++ b/chrome/browser/ui/libgtkui/native_theme_gtk.cc
@@ -408,7 +408,8 @@
                     theme_name.find("contrast") != std::string::npos);
 }
 
-SkColor NativeThemeGtk::GetSystemColor(ColorId color_id) const {
+SkColor NativeThemeGtk::GetSystemColor(ColorId color_id,
+                                       ColorScheme color_scheme) const {
   if (color_cache_[color_id])
     return color_cache_[color_id].value();
 
@@ -420,7 +421,8 @@
 void NativeThemeGtk::PaintArrowButton(cc::PaintCanvas* canvas,
                                       const gfx::Rect& rect,
                                       Part direction,
-                                      State state) const {
+                                      State state,
+                                      ColorScheme color_scheme) const {
   auto context = GetStyleContextFromCss(
       GtkVersionCheck(3, 20)
           ? "GtkScrollbar#scrollbar #contents GtkButton#button"
@@ -454,7 +456,8 @@
     Part part,
     State state,
     const ScrollbarTrackExtraParams& extra_params,
-    const gfx::Rect& rect) const {
+    const gfx::Rect& rect,
+    ColorScheme color_scheme) const {
   PaintWidget(
       canvas, rect,
       GetStyleContextFromCss(GtkVersionCheck(3, 20)
@@ -468,7 +471,8 @@
     Part part,
     State state,
     const gfx::Rect& rect,
-    NativeTheme::ScrollbarOverlayColorTheme theme) const {
+    NativeTheme::ScrollbarOverlayColorTheme theme,
+    ColorScheme color_scheme) const {
   auto context = GetStyleContextFromCss(
       GtkVersionCheck(3, 20)
           ? "GtkScrollbar#scrollbar #contents #trough #slider"
@@ -479,7 +483,8 @@
 
 void NativeThemeGtk::PaintScrollbarCorner(cc::PaintCanvas* canvas,
                                           State state,
-                                          const gfx::Rect& rect) const {
+                                          const gfx::Rect& rect,
+                                          ColorScheme color_scheme) const {
   auto context = GetStyleContextFromCss(
       GtkVersionCheck(3, 19, 2)
           ? "GtkScrolledWindow#scrolledwindow #junction"
@@ -490,7 +495,8 @@
 void NativeThemeGtk::PaintMenuPopupBackground(
     cc::PaintCanvas* canvas,
     const gfx::Size& size,
-    const MenuBackgroundExtraParams& menu_background) const {
+    const MenuBackgroundExtraParams& menu_background,
+    ColorScheme color_scheme) const {
   PaintWidget(canvas, gfx::Rect(size), GetStyleContextFromCss("GtkMenu#menu"),
               BG_RENDER_RECURSIVE, false);
 }
@@ -499,7 +505,8 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const MenuItemExtraParams& menu_item) const {
+    const MenuItemExtraParams& menu_item,
+    ColorScheme color_scheme) const {
   auto context = GetStyleContextFromCss("GtkMenu#menu GtkMenuItem#menuitem");
   gtk_style_context_set_state(context, StateToStateFlags(state));
   PaintWidget(canvas, rect, context, BG_RENDER_NORMAL, true);
@@ -509,14 +516,15 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const MenuSeparatorExtraParams& menu_separator) const {
+    const MenuSeparatorExtraParams& menu_separator,
+    ColorScheme color_scheme) const {
   // TODO(estade): use GTK to draw vertical separators too. See
   // crbug.com/710183
   if (menu_separator.type == ui::VERTICAL_SEPARATOR) {
     cc::PaintFlags paint;
     paint.setStyle(cc::PaintFlags::kFill_Style);
-    paint.setColor(
-        GetSystemColor(ui::NativeTheme::kColorId_MenuSeparatorColor));
+    paint.setColor(GetSystemColor(ui::NativeTheme::kColorId_MenuSeparatorColor,
+                                  color_scheme));
     canvas->drawRect(gfx::RectToSkRect(rect), paint);
     return;
   }
@@ -589,7 +597,8 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const FrameTopAreaExtraParams& frame_top_area) const {
+    const FrameTopAreaExtraParams& frame_top_area,
+    ColorScheme color_scheme) const {
   auto context = GetStyleContextFromCss(frame_top_area.use_custom_frame
                                             ? "#headerbar.header-bar.titlebar"
                                             : "GtkMenuBar#menubar");
diff --git a/chrome/browser/ui/libgtkui/native_theme_gtk.h b/chrome/browser/ui/libgtkui/native_theme_gtk.h
index e3292b2..3d24b736 100644
--- a/chrome/browser/ui/libgtkui/native_theme_gtk.h
+++ b/chrome/browser/ui/libgtkui/native_theme_gtk.h
@@ -26,44 +26,50 @@
   static NativeThemeGtk* instance();
 
   // Overridden from ui::NativeThemeBase:
-  SkColor GetSystemColor(ColorId color_id) const override;
+  SkColor GetSystemColor(
+      ColorId color_id,
+      ColorScheme color_scheme = ColorScheme::kDefault) const override;
   void PaintArrowButton(cc::PaintCanvas* canvas,
                         const gfx::Rect& rect,
                         Part direction,
-                        State state) const override;
+                        State state,
+                        ColorScheme color_scheme) const override;
   void PaintScrollbarTrack(cc::PaintCanvas* canvas,
                            Part part,
                            State state,
                            const ScrollbarTrackExtraParams& extra_params,
-                           const gfx::Rect& rect) const override;
-  void PaintScrollbarThumb(
-      cc::PaintCanvas* canvas,
-      Part part,
-      State state,
-      const gfx::Rect& rect,
-      NativeTheme::ScrollbarOverlayColorTheme theme) const override;
+                           const gfx::Rect& rect,
+                           ColorScheme color_scheme) const override;
+  void PaintScrollbarThumb(cc::PaintCanvas* canvas,
+                           Part part,
+                           State state,
+                           const gfx::Rect& rect,
+                           NativeTheme::ScrollbarOverlayColorTheme theme,
+                           ColorScheme color_scheme) const override;
   void PaintScrollbarCorner(cc::PaintCanvas* canvas,
                             State state,
-                            const gfx::Rect& rect) const override;
+                            const gfx::Rect& rect,
+                            ColorScheme color_scheme) const override;
   void PaintMenuPopupBackground(
       cc::PaintCanvas* canvas,
       const gfx::Size& size,
-      const MenuBackgroundExtraParams& menu_background) const override;
-  void PaintMenuSeparator(
-      cc::PaintCanvas* canvas,
-      State state,
-      const gfx::Rect& rect,
-      const MenuSeparatorExtraParams& menu_separator) const override;
-  void PaintMenuItemBackground(
-      cc::PaintCanvas* canvas,
-      State state,
-      const gfx::Rect& rect,
-      const MenuItemExtraParams& menu_item) const override;
-  void PaintFrameTopArea(
-      cc::PaintCanvas* canvas,
-      State state,
-      const gfx::Rect& rect,
-      const FrameTopAreaExtraParams& frame_top_area) const override;
+      const MenuBackgroundExtraParams& menu_background,
+      ColorScheme color_scheme) const override;
+  void PaintMenuSeparator(cc::PaintCanvas* canvas,
+                          State state,
+                          const gfx::Rect& rect,
+                          const MenuSeparatorExtraParams& menu_separator,
+                          ColorScheme color_scheme) const override;
+  void PaintMenuItemBackground(cc::PaintCanvas* canvas,
+                               State state,
+                               const gfx::Rect& rect,
+                               const MenuItemExtraParams& menu_item,
+                               ColorScheme color_scheme) const override;
+  void PaintFrameTopArea(cc::PaintCanvas* canvas,
+                         State state,
+                         const gfx::Rect& rect,
+                         const FrameTopAreaExtraParams& frame_top_area,
+                         ColorScheme color_scheme) const override;
 
   void OnThemeChanged(GtkSettings* settings, GtkParamSpec* param);
 
diff --git a/chrome/browser/ui/login/login_handler.cc b/chrome/browser/ui/login/login_handler.cc
index 947fd1a8..115ed66 100644
--- a/chrome/browser/ui/login/login_handler.cc
+++ b/chrome/browser/ui/login/login_handler.cc
@@ -36,7 +36,6 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/origin_util.h"
@@ -60,7 +59,6 @@
 using autofill::PasswordForm;
 using content::BrowserThread;
 using content::NavigationController;
-using content::ResourceRequestInfo;
 using content::WebContents;
 
 namespace {
diff --git a/chrome/browser/ui/login/login_handler.h b/chrome/browser/ui/login/login_handler.h
index 58a1a1c..4970648 100644
--- a/chrome/browser/ui/login/login_handler.h
+++ b/chrome/browser/ui/login/login_handler.h
@@ -21,7 +21,6 @@
 #include "content/public/browser/login_delegate.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "net/base/auth.h"
 
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 87108b6..dcd328b2 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -106,6 +106,7 @@
 #include "chrome/browser/ui/views/profiles/profile_indicator_icon.h"
 #include "chrome/browser/ui/views/profiles/profile_menu_view_base.h"
 #include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.h"
+#include "chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.h"
 #include "chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h"
 #include "chrome/browser/ui/views/status_bubble_views.h"
 #include "chrome/browser/ui/views/tab_contents/chrome_web_contents_view_focus_helper.h"
@@ -1419,13 +1420,13 @@
     return nullptr;
   }
 
-  LocationBarView* location_bar = GetLocationBarView();
-  views::View* anchor_view = location_bar;
-
   send_tab_to_self::SendTabToSelfBubbleViewImpl* bubble =
       new send_tab_to_self::SendTabToSelfBubbleViewImpl(
-          anchor_view, gfx::Point(), web_contents, controller);
-
+          GetLocationBarView(), gfx::Point(), web_contents, controller);
+  PageActionIconView* icon_view =
+      GetLocationBarView()->send_tab_to_self_icon_view();
+  if (icon_view)
+    bubble->SetHighlightedButton(icon_view);
   views::BubbleDialogDelegateView::CreateBubble(bubble);
   bubble->Show(send_tab_to_self::SendTabToSelfBubbleViewImpl::USER_GESTURE);
 
@@ -3010,7 +3011,7 @@
   ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::ICON_AVATAR_BUBBLE);
 }
 
-void BrowserView::ShowHatsBubbleFromAppMenuButton() {
+void BrowserView::ShowHatsBubbleFromAppMenuButton(const std::string& site_id) {
   // Never show any HaTS bubble in Incognito.
   if (!IsRegularOrGuestSession())
     return;
@@ -3022,7 +3023,7 @@
   if (!app_menu_button)
     return;
 
-  HatsBubbleView::Show(app_menu_button, browser());
+  HatsBubbleView::Show(browser(), app_menu_button, site_id);
 }
 
 void BrowserView::ExecuteExtensionCommand(
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 8d25a502..6dbea2d 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -418,7 +418,7 @@
       const signin::ManageAccountsParams& manage_accounts_params,
       signin_metrics::AccessPoint access_point,
       bool is_source_keyboard) override;
-  void ShowHatsBubbleFromAppMenuButton() override;
+  void ShowHatsBubbleFromAppMenuButton(const std::string& site_id) override;
   void ExecuteExtensionCommand(const extensions::Extension* extension,
                                const extensions::Command& command) override;
   ExclusiveAccessContext* GetExclusiveAccessContext() override;
diff --git a/chrome/browser/ui/views/hats/hats_browsertest.cc b/chrome/browser/ui/views/hats/hats_browsertest.cc
index 86cad24..1995322 100644
--- a/chrome/browser/ui/views/hats/hats_browsertest.cc
+++ b/chrome/browser/ui/views/hats/hats_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <memory>
+#include <string>
 
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
@@ -17,7 +18,7 @@
   void ShowUi(const std::string& name) override {
     ASSERT_TRUE(browser()->is_type_tabbed());
     BrowserView::GetBrowserViewForBrowser(InProcessBrowserTest::browser())
-        ->ShowHatsBubbleFromAppMenuButton();
+        ->ShowHatsBubbleFromAppMenuButton(std::string());
   }
 
  private:
diff --git a/chrome/browser/ui/views/hats/hats_bubble_view.cc b/chrome/browser/ui/views/hats/hats_bubble_view.cc
index 0bd51cb..37edd5d 100644
--- a/chrome/browser/ui/views/hats/hats_bubble_view.cc
+++ b/chrome/browser/ui/views/hats/hats_bubble_view.cc
@@ -35,23 +35,28 @@
 }
 
 // static
-void HatsBubbleView::Show(AppMenuButton* anchor_button, Browser* browser) {
+void HatsBubbleView::Show(Browser* browser,
+                          AppMenuButton* anchor_button,
+                          const std::string& site_id) {
   base::RecordAction(base::UserMetricsAction("HatsBubble.Show"));
 
   DCHECK(anchor_button->GetWidget());
   gfx::NativeView parent_view = anchor_button->GetWidget()->GetNativeView();
 
   // Bubble delegate will be deleted when its window is destroyed.
-  auto* bubble = new HatsBubbleView(anchor_button, browser, parent_view);
+  auto* bubble =
+      new HatsBubbleView(browser, anchor_button, site_id, parent_view);
   bubble->SetHighlightedButton(anchor_button);
   bubble->GetWidget()->Show();
 }
 
-HatsBubbleView::HatsBubbleView(AppMenuButton* anchor_button,
-                               Browser* browser,
+HatsBubbleView::HatsBubbleView(Browser* browser,
+                               AppMenuButton* anchor_button,
+                               const std::string& site_id,
                                gfx::NativeView parent_view)
     : BubbleDialogDelegateView(anchor_button, views::BubbleBorder::TOP_RIGHT),
       close_bubble_helper_(this, browser),
+      site_id_(site_id),
       browser_(browser) {
   chrome::RecordDialogCreation(chrome::DialogIdentifier::HATS_BUBBLE);
 
@@ -96,7 +101,7 @@
 }
 
 bool HatsBubbleView::Accept() {
-  HatsWebDialog::Show(browser_);
+  HatsWebDialog::Show(browser_, site_id_);
   return true;
 }
 
diff --git a/chrome/browser/ui/views/hats/hats_bubble_view.h b/chrome/browser/ui/views/hats/hats_bubble_view.h
index 6baf775e..9f509363 100644
--- a/chrome/browser/ui/views/hats/hats_bubble_view.h
+++ b/chrome/browser/ui/views/hats/hats_bubble_view.h
@@ -7,6 +7,8 @@
 
 #include <stddef.h>
 
+#include <string>
+
 #include "base/macros.h"
 #include "chrome/browser/ui/views/close_bubble_on_tab_activation_helper.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
@@ -20,8 +22,11 @@
  public:
   // Returns a pointer to the Hats Bubble being shown. For testing only.
   static views::BubbleDialogDelegateView* GetHatsBubble();
-  // Creates and shows the bubble anchored to the |anchor_button|.
-  static void Show(AppMenuButton* anchor_button, Browser* browser);
+  // Creates and shows the bubble anchored to the |anchor_button| and leads to
+  // a survey identified by |site_id|.
+  static void Show(Browser* browser,
+                   AppMenuButton* anchor_button,
+                   const std::string& site_id);
 
  protected:
   // views::WidgetDelegate:
@@ -41,13 +46,15 @@
   void Layout() override;
 
  private:
-  HatsBubbleView(AppMenuButton* anchor_button,
-                 Browser* browser,
+  HatsBubbleView(Browser* browser,
+                 AppMenuButton* anchor_button,
+                 const std::string& site_id,
                  gfx::NativeView parent_view);
   ~HatsBubbleView() override;
 
   static HatsBubbleView* instance_;
   CloseBubbleOnTabActivationHelper close_bubble_helper_;
+  const std::string site_id_;
   const Browser* browser_;
 
   DISALLOW_COPY_AND_ASSIGN(HatsBubbleView);
diff --git a/chrome/browser/ui/views/hats/hats_web_dialog.cc b/chrome/browser/ui/views/hats/hats_web_dialog.cc
index 161a905..12ab5b6 100644
--- a/chrome/browser/ui/views/hats/hats_web_dialog.cc
+++ b/chrome/browser/ui/views/hats/hats_web_dialog.cc
@@ -9,8 +9,6 @@
 #include "base/bind.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/hats/hats_service.h"
-#include "chrome/browser/ui/hats/hats_service_factory.h"
 #include "chrome/browser/ui/views/chrome_web_dialog_view.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
@@ -71,15 +69,14 @@
 }  // namespace
 
 // static
-void HatsWebDialog::Show(const Browser* browser) {
+void HatsWebDialog::Show(const Browser* browser, const std::string& site_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(browser);
 
   Profile* profile = browser->profile();
 
   // Self deleting upon close.
-  auto* hats_dialog = new HatsWebDialog(
-      HatsServiceFactory::GetForProfile(profile, true)->en_site_id());
+  auto* hats_dialog = new HatsWebDialog(site_id);
 
   // Create a web dialog aligned to the bottom center of the location bar.
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
diff --git a/chrome/browser/ui/views/hats/hats_web_dialog.h b/chrome/browser/ui/views/hats/hats_web_dialog.h
index 01a00bd..b7338846 100644
--- a/chrome/browser/ui/views/hats/hats_web_dialog.h
+++ b/chrome/browser/ui/views/hats/hats_web_dialog.h
@@ -19,7 +19,7 @@
 class HatsWebDialog : public ui::WebDialogDelegate {
  public:
   // Create and show an instance of HatsWebDialog.
-  static void Show(const Browser* browser);
+  static void Show(const Browser* browser, const std::string& site_id);
 
  private:
   // Use Show() above. |site_id| is used to select the survey.
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 7f3edc0..79b15c0 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -574,7 +574,25 @@
 
 void OmniboxViewViews::SetTextAndSelectedRange(const base::string16& text,
                                                const gfx::Range& range) {
+  // Will try to fit as much of unselected text as possible. If possible,
+  // guarantees at least |pad_left| chars of the unselected text are visible. If
+  // possible given the prior guarantee, also guarantees |pad_right| chars of
+  // the selected text are visible.
+  static const uint32_t kPadRight = 30;
+  static const uint32_t kPadLeft = 10;
+
   SetText(text);
+  // Select all the text to prioritize showing unselected text.
+  SelectRange(gfx::Range(range.start(), 0));
+  // Scroll selection right, to ensure |kPadRight| chars of selected text are
+  // shown.
+  SelectRange(gfx::Range(range.start(),
+                         std::min(range.end() + kPadRight, range.start())));
+  // Scroll selection left, to ensure |kPadLeft| chars of unselected text are
+  // shown.
+  SelectRange(
+      gfx::Range(range.start(), range.end() - std::min(kPadLeft, range.end())));
+  // Select the specified selection.
   SelectRange(range);
 }
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index 48eb680..0cc2b2b 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -78,7 +78,7 @@
   // OmniboxViewViews:
   void EmphasizeURLComponents() override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override {}
-  using OmniboxView::IsSelectAll;
+  using OmniboxView::OnInlineAutocompleteTextMaybeChanged;
 
  private:
   // OmniboxViewViews:
@@ -1285,3 +1285,27 @@
   EXPECT_FALSE(omnibox_view()->emphasis_range().IsValid());
   EXPECT_FALSE(omnibox_view()->scheme_range().IsValid());
 }
+
+TEST_F(OmniboxViewViewsTest, OverflowingAutocompleteText) {
+  // Make the Omnibox narrow so it can't fit the entire string (~650px), but
+  // wide enough to fit the user text (~65px).
+  int kOmniboxWidth = 100;
+  gfx::RenderText* render_text = omnibox_view()->GetRenderText();
+  render_text->SetDisplayRect(gfx::Rect(0, 0, kOmniboxWidth, 10));
+
+  omnibox_textfield()->OnFocus();
+  omnibox_view()->OnInlineAutocompleteTextMaybeChanged(
+      base::ASCIIToUTF16("user text. Followed by very long autocompleted text "
+                         "that is unlikely to fit in |kOmniboxWidth|"),
+      10);
+
+  // NOTE: Technically (depending on the font), this expectation could fail if
+  // 'user text' doesn't fit in 100px or the entire string fits in 100px.
+  EXPECT_EQ(render_text->GetUpdatedDisplayOffset().x(), 0);
+  EXPECT_FALSE(omnibox_view()->IsSelectAll());
+
+  // On blur, the display should remain to the start of the text.
+  omnibox_textfield()->OnBlur();
+  EXPECT_EQ(render_text->GetUpdatedDisplayOffset().x(), 0);
+  EXPECT_FALSE(omnibox_view()->IsSelectAll());
+}
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.cc
index 9d5dfc3..73cb4e4e 100644
--- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.cc
+++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_bubble_view_impl.cc
@@ -97,16 +97,6 @@
 
 void SendTabToSelfBubbleViewImpl::Show(DisplayReason reason) {
   ShowForReason(reason);
-  // Keeps the send tab to self icon in omnibox and be highlighted while
-  // showing the bubble.
-  views::Button* highlight_button =
-      BrowserView::GetBrowserViewForBrowser(
-          chrome::FindBrowserWithWebContents(web_contents_))
-          ->toolbar_button_provider()
-          ->GetOmniboxPageActionIconContainerView()
-          ->GetPageActionIconView(PageActionIconType::kSendTabToSelf);
-  highlight_button->SetVisible(true);
-  SetHighlightedButton(highlight_button);
 }
 
 const std::vector<std::unique_ptr<SendTabToSelfBubbleDeviceButton>>&
diff --git a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.cc b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.cc
index 3fb658e..8d5d3ff 100644
--- a/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.cc
+++ b/chrome/browser/ui/views/send_tab_to_self/send_tab_to_self_icon_view.cc
@@ -50,21 +50,28 @@
     return false;
   }
 
-  // Shows the send tab to self icon in omnibox when:
-  // send tab to self feature offered, and
-  // mouse focuses on the omnibox, and
-  // url has not been changed.
-  if (send_tab_to_self::ShouldOfferFeature(web_contents) &&
-      omnibox_view->model()->has_focus() &&
-      !omnibox_view->model()->user_input_in_progress()) {
-    // Shows the animation one time per browser session.
-    if (!was_animation_shown_) {
-      AnimateIn(IDS_OMNIBOX_ICON_SEND_TAB_TO_SELF);
-      was_animation_shown_ = true;
+  if (was_visible) {
+    // If send tab to self icon is showing:
+    // Hides the icon if the url is being editing.
+    if (omnibox_view->model()->user_input_in_progress()) {
+      SetVisible(false);
     }
-    SetVisible(true);
   } else {
-    SetVisible(false);
+    // If send tab to self icon is hiding:
+    // Shows the send tab to self icon in omnibox when:
+    // send tab to self feature offered, and
+    // mouse focuses on the omnibox, and
+    // url has not been changed.
+    if (send_tab_to_self::ShouldOfferFeature(web_contents) &&
+        omnibox_view->model()->has_focus() &&
+        !omnibox_view->model()->user_input_in_progress()) {
+      // Shows the animation one time per window.
+      if (!was_animation_shown_) {
+        AnimateIn(IDS_OMNIBOX_ICON_SEND_TAB_TO_SELF);
+        was_animation_shown_ = true;
+      }
+      SetVisible(true);
+    }
   }
 
   return was_visible != GetVisible();
diff --git a/chrome/browser/ui/webui/about_ui.cc b/chrome/browser/ui/webui/about_ui.cc
index d4cff18..648d293 100644
--- a/chrome/browser/ui/webui/about_ui.cc
+++ b/chrome/browser/ui/webui/about_ui.cc
@@ -586,7 +586,7 @@
 
 void AboutUIHTMLSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   std::string response;
   // Add your data source here, in alphabetical order.
diff --git a/chrome/browser/ui/webui/about_ui.h b/chrome/browser/ui/webui/about_ui.h
index 6860148..0f2ae712 100644
--- a/chrome/browser/ui/webui/about_ui.h
+++ b/chrome/browser/ui/webui/about_ui.h
@@ -26,7 +26,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string& path) override;
   bool ShouldAddContentSecurityPolicy() override;
diff --git a/chrome/browser/ui/webui/about_ui_unittest.cc b/chrome/browser/ui/webui/about_ui_unittest.cc
index 301e194..6f43394 100644
--- a/chrome/browser/ui/webui/about_ui_unittest.cc
+++ b/chrome/browser/ui/webui/about_ui_unittest.cc
@@ -29,7 +29,6 @@
 #include "chromeos/system/fake_statistics_provider.h"
 #include "chromeos/system/statistics_provider.h"
 #include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -123,7 +122,7 @@
   // Starts data request with the |request_url|.
   void StartRequest(const std::string& request_url,
                     TestDataReceiver* data_receiver) {
-    content::ResourceRequestInfo::WebContentsGetter wc_getter;
+    content::WebContents::Getter wc_getter;
     tested_html_source_->StartDataRequest(
         request_url, std::move(wc_getter),
         base::BindRepeating(&TestDataReceiver::OnDataReceived,
diff --git a/chrome/browser/ui/webui/app_launcher_page_ui.cc b/chrome/browser/ui/webui/app_launcher_page_ui.cc
index 7005dd6..521d94e 100644
--- a/chrome/browser/ui/webui/app_launcher_page_ui.cc
+++ b/chrome/browser/ui/webui/app_launcher_page_ui.cc
@@ -100,7 +100,7 @@
 
 void AppLauncherPageUI::HTMLSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
diff --git a/chrome/browser/ui/webui/app_launcher_page_ui.h b/chrome/browser/ui/webui/app_launcher_page_ui.h
index 0b632d6a..b5ad2e1 100644
--- a/chrome/browser/ui/webui/app_launcher_page_ui.h
+++ b/chrome/browser/ui/webui/app_launcher_page_ui.h
@@ -40,7 +40,7 @@
     std::string GetSource() override;
     void StartDataRequest(
         const std::string& path,
-        const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+        const content::WebContents::Getter& wc_getter,
         const content::URLDataSource::GotDataCallback& callback) override;
     std::string GetMimeType(const std::string&) override;
     bool ShouldReplaceExistingSource() override;
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 6a8340d..7aafd91b 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -107,6 +107,10 @@
 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
 #endif
 
+#if BUILDFLAG(ENABLE_WEBUI_TAB_STRIP)
+#include "chrome/browser/ui/webui/tab_strip/tab_strip_ui.h"
+#endif
+
 #if !defined(OS_ANDROID)
 #include "chrome/browser/media/router/media_router_feature.h"
 #include "chrome/browser/ui/webui/app_management/app_management_ui.h"
@@ -666,6 +670,13 @@
     return &NewWebUI<LocalDiscoveryUI>;
   }
 #endif
+
+#if BUILDFLAG(ENABLE_WEBUI_TAB_STRIP)
+  if (url.host_piece() == chrome::kChromeUITabStripHost) {
+    return &NewWebUI<TabStripUI>;
+  }
+#endif
+
   if (url.host_piece() == chrome::kChromeUIWebRtcLogsHost)
     return &NewWebUI<WebRtcLogsUI>;
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/ui/webui/chromeos/cellular_setup/mobile_setup_ui.cc b/chrome/browser/ui/webui/chromeos/cellular_setup/mobile_setup_ui.cc
index 5eaf0f3..10ec51e 100644
--- a/chrome/browser/ui/webui/chromeos/cellular_setup/mobile_setup_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/cellular_setup/mobile_setup_ui.cc
@@ -178,7 +178,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string&) override { return "text/html"; }
   bool ShouldAddContentSecurityPolicy() override { return false; }
@@ -270,7 +270,7 @@
 
 void MobileSetupUIHTMLSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   // Sanity checks that activation was requested for an appropriate network.
   const NetworkState* network =
diff --git a/chrome/browser/ui/webui/chromeos/image_source.cc b/chrome/browser/ui/webui/chromeos/image_source.cc
index d5942fc..d459c036 100644
--- a/chrome/browser/ui/webui/chromeos/image_source.cc
+++ b/chrome/browser/ui/webui/chromeos/image_source.cc
@@ -55,7 +55,7 @@
 
 void ImageSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& got_data_callback) {
   if (!IsWhitelisted(path)) {
     got_data_callback.Run(nullptr);
diff --git a/chrome/browser/ui/webui/chromeos/image_source.h b/chrome/browser/ui/webui/chromeos/image_source.h
index 5d7a5af..6d3376c 100644
--- a/chrome/browser/ui/webui/chromeos/image_source.h
+++ b/chrome/browser/ui/webui/chromeos/image_source.h
@@ -27,11 +27,10 @@
 
   // content::URLDataSource implementation.
   std::string GetSource() override;
-  void StartDataRequest(
-      const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const content::URLDataSource::GotDataCallback& got_data_callback)
-      override;
+  void StartDataRequest(const std::string& path,
+                        const content::WebContents::Getter& wc_getter,
+                        const content::URLDataSource::GotDataCallback&
+                            got_data_callback) override;
 
   std::string GetMimeType(const std::string& path) override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.cc b/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.cc
index 01aed9f..e86ea51 100644
--- a/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.cc
+++ b/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.cc
@@ -35,7 +35,7 @@
 
 void ScreenlockIconSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   if (!icon_provider_) {
     callback.Run(GetDefaultIcon().As1xPNGBytes().get());
diff --git a/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.h b/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.h
index d6715f1a..44b13c43 100644
--- a/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.h
+++ b/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.h
@@ -24,7 +24,7 @@
   std::string GetSource() const override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
 
   std::string GetMimeType(const std::string& path) const override;
diff --git a/chrome/browser/ui/webui/chromeos/slow_trace_ui.cc b/chrome/browser/ui/webui/chromeos/slow_trace_ui.cc
index 07d906c..c5c1b2c 100644
--- a/chrome/browser/ui/webui/chromeos/slow_trace_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/slow_trace_ui.cc
@@ -34,7 +34,7 @@
 
 void SlowTraceSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   int trace_id = 0;
   size_t pos = path.find('#');
diff --git a/chrome/browser/ui/webui/chromeos/slow_trace_ui.h b/chrome/browser/ui/webui/chromeos/slow_trace_ui.h
index 77a04463..8d000798 100644
--- a/chrome/browser/ui/webui/chromeos/slow_trace_ui.h
+++ b/chrome/browser/ui/webui/chromeos/slow_trace_ui.h
@@ -32,7 +32,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string& path) override;
   bool AllowCaching() override;
diff --git a/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc b/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc
index 889a692e..8dee3fe 100644
--- a/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc
+++ b/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc
@@ -39,7 +39,7 @@
 
 void TerminalSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   base::FilePath file_path(kTerminalRoot);
   if (path.empty()) {
diff --git a/chrome/browser/ui/webui/chromeos/terminal/terminal_source.h b/chrome/browser/ui/webui/chromeos/terminal/terminal_source.h
index dc92284..b5acfde 100644
--- a/chrome/browser/ui/webui/chromeos/terminal/terminal_source.h
+++ b/chrome/browser/ui/webui/chromeos/terminal/terminal_source.h
@@ -8,8 +8,8 @@
 #include <string>
 
 #include "base/macros.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/url_data_source.h"
+#include "content/public/browser/web_contents.h"
 
 class TerminalSource : public content::URLDataSource {
  public:
@@ -21,7 +21,7 @@
 
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
 
   std::string GetMimeType(const std::string& path) override;
diff --git a/chrome/browser/ui/webui/chromeos/user_image_source.cc b/chrome/browser/ui/webui/chromeos/user_image_source.cc
index 63c8676..e8ca63d 100644
--- a/chrome/browser/ui/webui/chromeos/user_image_source.cc
+++ b/chrome/browser/ui/webui/chromeos/user_image_source.cc
@@ -179,7 +179,7 @@
 
 void UserImageSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   std::string email;
   int frame = -1;
diff --git a/chrome/browser/ui/webui/chromeos/user_image_source.h b/chrome/browser/ui/webui/chromeos/user_image_source.h
index 1e73aed..f20af23 100644
--- a/chrome/browser/ui/webui/chromeos/user_image_source.h
+++ b/chrome/browser/ui/webui/chromeos/user_image_source.h
@@ -33,7 +33,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string& path) override;
 
diff --git a/chrome/browser/ui/webui/chromeos/video_source.cc b/chrome/browser/ui/webui/chromeos/video_source.cc
index 4db1b33..6144e57 100644
--- a/chrome/browser/ui/webui/chromeos/video_source.cc
+++ b/chrome/browser/ui/webui/chromeos/video_source.cc
@@ -68,7 +68,7 @@
 
 void VideoSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& got_data_callback) {
   if (!IsWhitelisted(path)) {
     got_data_callback.Run(nullptr);
diff --git a/chrome/browser/ui/webui/chromeos/video_source.h b/chrome/browser/ui/webui/chromeos/video_source.h
index 316509a..4da591d 100644
--- a/chrome/browser/ui/webui/chromeos/video_source.h
+++ b/chrome/browser/ui/webui/chromeos/video_source.h
@@ -29,11 +29,10 @@
 
   // content::URLDataSource:
   std::string GetSource() override;
-  void StartDataRequest(
-      const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const content::URLDataSource::GotDataCallback& got_data_callback)
-      override;
+  void StartDataRequest(const std::string& path,
+                        const content::WebContents::Getter& wc_getter,
+                        const content::URLDataSource::GotDataCallback&
+                            got_data_callback) override;
   std::string GetMimeType(const std::string& path) override;
 
  private:
diff --git a/chrome/browser/ui/webui/devtools_ui.cc b/chrome/browser/ui/webui/devtools_ui.cc
index a9cc1d8..1fd9c57 100644
--- a/chrome/browser/ui/webui/devtools_ui.cc
+++ b/chrome/browser/ui/webui/devtools_ui.cc
@@ -96,10 +96,9 @@
   // content::URLDataSource implementation.
   std::string GetSource() override;
 
-  void StartDataRequest(
-      const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const GotDataCallback& callback) override;
+  void StartDataRequest(const std::string& path,
+                        const content::WebContents::Getter& wc_getter,
+                        const GotDataCallback& callback) override;
 
  private:
   struct PendingRequest;
@@ -164,7 +163,7 @@
 
 void DevToolsDataSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   // Serve request from local bundle.
   std::string bundled_path_prefix(chrome::kChromeUIDevToolsBundledPath);
diff --git a/chrome/browser/ui/webui/extensions/extension_icon_source.cc b/chrome/browser/ui/webui/extensions/extension_icon_source.cc
index 618914d..11995b5 100644
--- a/chrome/browser/ui/webui/extensions/extension_icon_source.cc
+++ b/chrome/browser/ui/webui/extensions/extension_icon_source.cc
@@ -114,7 +114,7 @@
 
 void ExtensionIconSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   // This is where everything gets started. First, parse the request and make
   // the request data available for later.
diff --git a/chrome/browser/ui/webui/extensions/extension_icon_source.h b/chrome/browser/ui/webui/extensions/extension_icon_source.h
index c7be8dc8..0737257 100644
--- a/chrome/browser/ui/webui/extensions/extension_icon_source.h
+++ b/chrome/browser/ui/webui/extensions/extension_icon_source.h
@@ -72,7 +72,7 @@
   std::string GetMimeType(const std::string&) override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   bool AllowCaching() override;
 
diff --git a/chrome/browser/ui/webui/extensions/extensions_internals_source.cc b/chrome/browser/ui/webui/extensions/extensions_internals_source.cc
index 9c1963ef..69157d3 100644
--- a/chrome/browser/ui/webui/extensions/extensions_internals_source.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_internals_source.cc
@@ -435,7 +435,7 @@
 
 void ExtensionsInternalsSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   std::string json = WriteToString();
   callback.Run(base::RefCountedString::TakeString(&json));
diff --git a/chrome/browser/ui/webui/extensions/extensions_internals_source.h b/chrome/browser/ui/webui/extensions/extensions_internals_source.h
index 4a8a6ca..0b2840ae 100644
--- a/chrome/browser/ui/webui/extensions/extensions_internals_source.h
+++ b/chrome/browser/ui/webui/extensions/extensions_internals_source.h
@@ -22,7 +22,7 @@
   std::string GetMimeType(const std::string& path) override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
 
   // Simpler interface to generate string output, without needing to
diff --git a/chrome/browser/ui/webui/favicon_source.cc b/chrome/browser/ui/webui/favicon_source.cc
index 95f97b45..603e029 100644
--- a/chrome/browser/ui/webui/favicon_source.cc
+++ b/chrome/browser/ui/webui/favicon_source.cc
@@ -35,8 +35,7 @@
 // original URL that started the request, but we're only interested in verifying
 // if it was issued by a history page, for whom this is the case. If it is not
 // possible to obtain the URL, we return the empty GURL.
-GURL GetUnsafeRequestOrigin(
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter) {
+GURL GetUnsafeRequestOrigin(const content::WebContents::Getter& wc_getter) {
   content::WebContents* web_contents = wc_getter.Run();
   return web_contents ? web_contents->GetLastCommittedURL() : GURL();
 }
@@ -77,7 +76,7 @@
 
 void FaviconSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   favicon::FaviconService* favicon_service =
       FaviconServiceFactory::GetForProfile(profile_,
diff --git a/chrome/browser/ui/webui/favicon_source.h b/chrome/browser/ui/webui/favicon_source.h
index d07df2fe..35e52ba 100644
--- a/chrome/browser/ui/webui/favicon_source.h
+++ b/chrome/browser/ui/webui/favicon_source.h
@@ -45,7 +45,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string&) override;
   bool AllowCaching() override;
diff --git a/chrome/browser/ui/webui/favicon_source_unittest.cc b/chrome/browser/ui/webui/favicon_source_unittest.cc
index 2079fbe3..85be1622 100644
--- a/chrome/browser/ui/webui/favicon_source_unittest.cc
+++ b/chrome/browser/ui/webui/favicon_source_unittest.cc
@@ -17,7 +17,6 @@
 #include "components/favicon/core/test/mock_favicon_service.h"
 #include "components/favicon_base/favicon_url_parser.h"
 #include "content/public/browser/browser_context.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/web_contents_tester.h"
@@ -27,7 +26,7 @@
 #include "ui/resources/grit/ui_resources.h"
 
 using GotDataCallback = content::URLDataSource::GotDataCallback;
-using WebContentsGetter = content::ResourceRequestInfo::WebContentsGetter;
+using WebContentsGetter = content::WebContents::Getter;
 using testing::_;
 using testing::Return;
 using testing::ReturnArg;
diff --git a/chrome/browser/ui/webui/fileicon_source.cc b/chrome/browser/ui/webui/fileicon_source.cc
index 7706c0f..a9e963a 100644
--- a/chrome/browser/ui/webui/fileicon_source.cc
+++ b/chrome/browser/ui/webui/fileicon_source.cc
@@ -114,7 +114,7 @@
 
 void FileIconSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   base::FilePath file_path;
   IconLoader::IconSize icon_size = IconLoader::NORMAL;
diff --git a/chrome/browser/ui/webui/fileicon_source.h b/chrome/browser/ui/webui/fileicon_source.h
index 38fd779..d607cf1 100644
--- a/chrome/browser/ui/webui/fileicon_source.h
+++ b/chrome/browser/ui/webui/fileicon_source.h
@@ -28,7 +28,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string&) override;
   bool AllowCaching() override;
diff --git a/chrome/browser/ui/webui/fileicon_source_unittest.cc b/chrome/browser/ui/webui/fileicon_source_unittest.cc
index 42dd71a..ab56ab3 100644
--- a/chrome/browser/ui/webui/fileicon_source_unittest.cc
+++ b/chrome/browser/ui/webui/fileicon_source_unittest.cc
@@ -118,9 +118,7 @@
                     base::FilePath(kBasicExpectations[i].unescaped_path),
                     kBasicExpectations[i].scale_factor,
                     kBasicExpectations[i].size, CallbackIsNull()));
-    source->StartDataRequest(
-        kBasicExpectations[i].request_path,
-        content::ResourceRequestInfo::WebContentsGetter(),
-        callback);
+    source->StartDataRequest(kBasicExpectations[i].request_path,
+                             content::WebContents::Getter(), callback);
   }
 }
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
index 1a5607b..61d7565 100644
--- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
+++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -89,7 +89,7 @@
   std::string GetContentSecurityPolicyImgSrc() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
 
  private:
@@ -462,7 +462,7 @@
 
 void InterstitialHTMLSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   content::WebContents* web_contents = wc_getter.Run();
   if (!web_contents) {
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.cc b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
index 9102ea0..48f2a16 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.cc
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
@@ -150,7 +150,7 @@
 
 void NewTabUI::NewTabHTMLSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.h b/chrome/browser/ui/webui/ntp/new_tab_ui.h
index 61e2451..01d668a 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.h
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.h
@@ -57,7 +57,7 @@
     std::string GetSource() override;
     void StartDataRequest(
         const std::string& path,
-        const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+        const content::WebContents::Getter& wc_getter,
         const content::URLDataSource::GotDataCallback& callback) override;
     std::string GetMimeType(const std::string&) override;
     bool ShouldReplaceExistingSource() override;
diff --git a/chrome/browser/ui/webui/prefs_internals_source.cc b/chrome/browser/ui/webui/prefs_internals_source.cc
index 382f02f..152af75 100644
--- a/chrome/browser/ui/webui/prefs_internals_source.cc
+++ b/chrome/browser/ui/webui/prefs_internals_source.cc
@@ -29,7 +29,7 @@
 
 void PrefsInternalsSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   std::string json;
diff --git a/chrome/browser/ui/webui/prefs_internals_source.h b/chrome/browser/ui/webui/prefs_internals_source.h
index d20af55..9223026 100644
--- a/chrome/browser/ui/webui/prefs_internals_source.h
+++ b/chrome/browser/ui/webui/prefs_internals_source.h
@@ -21,7 +21,7 @@
   std::string GetMimeType(const std::string& path) override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
 
  private:
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
new file mode 100644
index 0000000..b4fe116
--- /dev/null
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.cc
@@ -0,0 +1,29 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/tab_strip/tab_strip_ui.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/tab_strip_resources.h"
+#include "chrome/grit/tab_strip_resources_map.h"
+#include "content/public/browser/web_ui_data_source.h"
+
+TabStripUI::TabStripUI(content::WebUI* web_ui)
+    : content::WebUIController(web_ui) {
+  Profile* profile = Profile::FromWebUI(web_ui);
+  content::WebUIDataSource* html_source =
+      content::WebUIDataSource::Create(chrome::kChromeUITabStripHost);
+
+  for (size_t i = 0; i < kTabStripResourcesSize; ++i) {
+    html_source->AddResourcePath(kTabStripResources[i].name,
+                                 kTabStripResources[i].value);
+  }
+
+  html_source->SetDefaultResource(IDR_TAB_STRIP_HTML);
+
+  content::WebUIDataSource::Add(profile, html_source);
+}
+
+TabStripUI::~TabStripUI() {}
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui.h b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.h
new file mode 100644
index 0000000..4a9822af
--- /dev/null
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui.h
@@ -0,0 +1,22 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_TAB_STRIP_TAB_STRIP_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_TAB_STRIP_TAB_STRIP_UI_H_
+
+#include "base/macros.h"
+#include "content/public/browser/web_ui_controller.h"
+
+// The WebUI version of the tab strip in the browser. It is currently only
+// supported on ChromeOS in tablet mode.
+class TabStripUI : public content::WebUIController {
+ public:
+  TabStripUI(content::WebUI* web_ui);
+  ~TabStripUI() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TabStripUI);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_TAB_STRIP_TAB_STRIP_UI_H_
diff --git a/chrome/browser/ui/webui/test_data_source.cc b/chrome/browser/ui/webui/test_data_source.cc
index b857b4f..3cc9b08b 100644
--- a/chrome/browser/ui/webui/test_data_source.cc
+++ b/chrome/browser/ui/webui/test_data_source.cc
@@ -31,7 +31,7 @@
 
 void TestDataSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   base::PostTaskWithTraits(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
diff --git a/chrome/browser/ui/webui/test_data_source.h b/chrome/browser/ui/webui/test_data_source.h
index 680979c..07ac490 100644
--- a/chrome/browser/ui/webui/test_data_source.h
+++ b/chrome/browser/ui/webui/test_data_source.h
@@ -21,7 +21,7 @@
  private:
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
 
   std::string GetMimeType(const std::string& path) override;
diff --git a/chrome/browser/ui/webui/theme_source.cc b/chrome/browser/ui/webui/theme_source.cc
index 673b625..cf6acc95 100644
--- a/chrome/browser/ui/webui/theme_source.cc
+++ b/chrome/browser/ui/webui/theme_source.cc
@@ -80,7 +80,7 @@
 
 void ThemeSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   // Default scale factor if not specified.
   float scale = 1.0f;
diff --git a/chrome/browser/ui/webui/theme_source.h b/chrome/browser/ui/webui/theme_source.h
index aa323d6..321ea0b8 100644
--- a/chrome/browser/ui/webui/theme_source.h
+++ b/chrome/browser/ui/webui/theme_source.h
@@ -24,7 +24,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string& path) override;
   scoped_refptr<base::SingleThreadTaskRunner> TaskRunnerForRequestPath(
diff --git a/chrome/browser/ui/webui/theme_source_unittest.cc b/chrome/browser/ui/webui/theme_source_unittest.cc
index abbf029..71b511c 100644
--- a/chrome/browser/ui/webui/theme_source_unittest.cc
+++ b/chrome/browser/ui/webui/theme_source_unittest.cc
@@ -24,10 +24,8 @@
   size_t result_data_size() const { return result_data_size_; }
 
   void StartDataRequest(const std::string& source) {
-    theme_source()->StartDataRequest(
-        source,
-        content::ResourceRequestInfo::WebContentsGetter(),
-        callback_);
+    theme_source()->StartDataRequest(source, content::WebContents::Getter(),
+                                     callback_);
   }
 
   size_t result_data_size_;
diff --git a/chrome/chrome_elf/BUILD.gn b/chrome/chrome_elf/BUILD.gn
index 8d2c7b1..3274b05 100644
--- a/chrome/chrome_elf/BUILD.gn
+++ b/chrome/chrome_elf/BUILD.gn
@@ -70,7 +70,6 @@
   }
 
   deps = [
-    ":blacklist",
     ":chrome_elf_manifest",
     ":chrome_elf_resources",
     ":constants",
@@ -111,19 +110,6 @@
 ## chrome_elf sub targets
 ##------------------------------------------------------------------------------
 
-static_library("blacklist") {
-  sources = [
-    "blacklist/blacklist.cc",
-    "blacklist/blacklist.h",
-  ]
-  deps = [
-    ":constants",
-    ":nt_registry",
-    ":third_party_dlls",
-    "//chrome/install_static:install_static_util",
-  ]
-}
-
 source_set("constants") {
   sources = [
     "chrome_elf_constants.cc",
@@ -232,7 +218,7 @@
   ]
 }
 
-static_library("third_party_dlls") {
+source_set("third_party_dlls") {
   visibility = [ ":*" ]  # Only targets in this file can depend on this.
   sources = [
     "third_party_dlls/beacon.cc",
@@ -297,7 +283,6 @@
   ]
   include_dirs = [ "$target_gen_dir" ]
   deps = [
-    ":blacklist",
     ":constants",
     ":crash",
     ":hook_util",
diff --git a/chrome/chrome_elf/blacklist/OWNERS b/chrome/chrome_elf/blacklist/OWNERS
deleted file mode 100644
index 23a4824..0000000
--- a/chrome/chrome_elf/blacklist/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-caitkp@chromium.org
-csharp@chromium.org
-robertshield@chromium.org
-
-# COMPONENT: Internals>Core
diff --git a/chrome/chrome_elf/blacklist/blacklist.cc b/chrome/chrome_elf/blacklist/blacklist.cc
deleted file mode 100644
index 7752992..0000000
--- a/chrome/chrome_elf/blacklist/blacklist.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-// 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.
-
-#include "chrome/chrome_elf/blacklist/blacklist.h"
-
-#include <windows.h>
-
-#include <assert.h>
-#include <string.h>
-
-#include "chrome/chrome_elf/third_party_dlls/hardcoded_blocklist.h"
-
-namespace blacklist {
-
-namespace {
-
-// Record if the blacklist was successfully initialized so processes can easily
-// determine if the blacklist is enabled for them.
-bool g_blacklist_initialized = false;
-
-}  // namespace
-
-using third_party_dlls::g_troublesome_dlls;
-using third_party_dlls::kTroublesomeDllsMaxCount;
-
-bool g_blocked_dlls[kTroublesomeDllsMaxCount] = {};
-int g_num_blocked_dlls = 0;
-
-int BlacklistSize() {
-  int size = -1;
-  while (blacklist::g_troublesome_dlls[++size] != NULL) {
-  }
-
-  return size;
-}
-
-bool IsBlacklistInitialized() {
-  return g_blacklist_initialized;
-}
-
-bool AddDllToBlacklist(const wchar_t* dll_name) {
-  int blacklist_size = BlacklistSize();
-  // We need to leave one space at the end for the null pointer.
-  if (blacklist_size + 1 >= static_cast<int>(kTroublesomeDllsMaxCount))
-    return false;
-  for (int i = 0; i < blacklist_size; ++i) {
-    if (!_wcsicmp(g_troublesome_dlls[i], dll_name))
-      return true;
-  }
-
-  // Copy string to blacklist.
-  wchar_t* str_buffer = new wchar_t[wcslen(dll_name) + 1];
-  wcscpy(str_buffer, dll_name);
-
-  g_troublesome_dlls[blacklist_size] = str_buffer;
-  g_blocked_dlls[blacklist_size] = false;
-  return true;
-}
-
-bool RemoveDllFromBlacklist(const wchar_t* dll_name) {
-  int blacklist_size = BlacklistSize();
-  for (int i = 0; i < blacklist_size; ++i) {
-    if (!_wcsicmp(g_troublesome_dlls[i], dll_name)) {
-      // Found the thing to remove. Delete it then replace it with the last
-      // element.
-      delete[] g_troublesome_dlls[i];
-      g_troublesome_dlls[i] = g_troublesome_dlls[blacklist_size - 1];
-      g_troublesome_dlls[blacklist_size - 1] = NULL;
-
-      // Also update the stats recording if we have blocked this dll or not.
-      if (g_blocked_dlls[i])
-        --g_num_blocked_dlls;
-      g_blocked_dlls[i] = g_blocked_dlls[blacklist_size - 1];
-      return true;
-    }
-  }
-  return false;
-}
-
-// TODO(csharp): Maybe store these values in the registry so we can
-// still report them if Chrome crashes early.
-void SuccessfullyBlocked(const wchar_t** blocked_dlls, int* size) {
-  if (size == NULL)
-    return;
-
-  // If the array isn't valid or big enough, just report the size it needs to
-  // be and return.
-  if (blocked_dlls == NULL && *size < g_num_blocked_dlls) {
-    *size = g_num_blocked_dlls;
-    return;
-  }
-
-  *size = g_num_blocked_dlls;
-
-  int strings_to_fill = 0;
-  for (int i = 0; strings_to_fill < g_num_blocked_dlls && g_troublesome_dlls[i];
-       ++i) {
-    if (g_blocked_dlls[i]) {
-      blocked_dlls[strings_to_fill] = g_troublesome_dlls[i];
-      ++strings_to_fill;
-    }
-  }
-}
-
-void BlockedDll(size_t blocked_index) {
-  assert(blocked_index < kTroublesomeDllsMaxCount);
-
-  if (!g_blocked_dlls[blocked_index] &&
-      blocked_index < kTroublesomeDllsMaxCount) {
-    ++g_num_blocked_dlls;
-    g_blocked_dlls[blocked_index] = true;
-  }
-}
-
-int DllMatch(const std::wstring& module_name) {
-  if (module_name.empty())
-    return -1;
-
-  for (int i = 0; blacklist::g_troublesome_dlls[i] != NULL; ++i) {
-    if (_wcsicmp(module_name.c_str(), blacklist::g_troublesome_dlls[i]) == 0)
-      return i;
-  }
-  return -1;
-}
-
-}  // namespace blacklist
diff --git a/chrome/chrome_elf/blacklist/blacklist.h b/chrome/chrome_elf/blacklist/blacklist.h
deleted file mode 100644
index f2f9d8d..0000000
--- a/chrome/chrome_elf/blacklist/blacklist.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_CHROME_ELF_BLACKLIST_BLACKLIST_H_
-#define CHROME_CHROME_ELF_BLACKLIST_BLACKLIST_H_
-
-#include <stddef.h>
-
-#include <string>
-
-namespace blacklist {
-
-// Return the size of the current blacklist.
-extern "C" int BlacklistSize();
-
-// Returns if true if the blacklist has been initialized.
-extern "C" bool IsBlacklistInitialized();
-
-// Adds the given dll name to the blacklist. Returns true if the dll name is in
-// the blacklist when this returns, false on error. Note that this will copy
-// |dll_name| and will leak it on exit if the string is not subsequently removed
-// using RemoveDllFromBlacklist.
-// Exposed for testing only, this shouldn't be exported from chrome_elf.dll.
-extern "C" bool AddDllToBlacklist(const wchar_t* dll_name);
-
-// Removes the given dll name from the blacklist. Returns true if it was
-// removed, false on error.
-// Exposed for testing only, this shouldn't be exported from chrome_elf.dll.
-extern "C" bool RemoveDllFromBlacklist(const wchar_t* dll_name);
-
-// Returns a list of all the dlls that have been successfully blocked by the
-// blacklist via blocked_dlls, if there is enough space (according to |size|).
-// |size| will always be modified to be the number of dlls that were blocked.
-// The caller doesn't own the strings and isn't expected to free them. These
-// strings won't be hanging unless RemoveDllFromBlacklist is called, but it
-// is only exposed in tests (and should stay that way).
-extern "C" void SuccessfullyBlocked(const wchar_t** blocked_dlls, int* size);
-
-// Record that the dll at the given index was blocked.
-extern "C" void BlockedDll(size_t blocked_index);
-
-// Legacy match function.
-// Returns the index of the blacklist found in |g_troublesome_dlls|, or -1.
-int DllMatch(const std::wstring& module_name);
-
-}  // namespace blacklist
-
-#endif  // CHROME_CHROME_ELF_BLACKLIST_BLACKLIST_H_
diff --git a/chrome/chrome_elf/chrome_elf_arm64.def b/chrome/chrome_elf/chrome_elf_arm64.def
index 1da85bc4..1cdc2c2 100644
--- a/chrome/chrome_elf/chrome_elf_arm64.def
+++ b/chrome/chrome_elf/chrome_elf_arm64.def
@@ -29,11 +29,6 @@
   ; From chrome/install_static
   GetInstallDetailsPayload
 
-  ; From chrome/chrome_elf/blacklist/blacklist.cc
-  AddDllToBlacklist
-  IsBlacklistInitialized
-  SuccessfullyBlocked
-
   ; From chrome/chrome_elf/third_party_dlls/logs.cc
   DrainLog
   RegisterLogNotification
diff --git a/chrome/chrome_elf/chrome_elf_x64.def b/chrome/chrome_elf/chrome_elf_x64.def
index bda181c..bf953ec 100644
--- a/chrome/chrome_elf/chrome_elf_x64.def
+++ b/chrome/chrome_elf/chrome_elf_x64.def
@@ -29,11 +29,6 @@
   ; From chrome/install_static
   GetInstallDetailsPayload
 
-  ; From chrome/chrome_elf/blacklist/blacklist.cc
-  AddDllToBlacklist
-  IsBlacklistInitialized
-  SuccessfullyBlocked
-
   ; From chrome/chrome_elf/third_party_dlls/logs.cc
   DrainLog
   RegisterLogNotification
diff --git a/chrome/chrome_elf/chrome_elf_x86.def b/chrome/chrome_elf/chrome_elf_x86.def
index 238b4ca..71118659 100644
--- a/chrome/chrome_elf/chrome_elf_x86.def
+++ b/chrome/chrome_elf/chrome_elf_x86.def
@@ -29,11 +29,6 @@
   ; From chrome/install_static
   GetInstallDetailsPayload
 
-  ; From chrome/chrome_elf/blacklist/blacklist.cc
-  AddDllToBlacklist
-  IsBlacklistInitialized
-  SuccessfullyBlocked
-
   ; From chrome/chrome_elf/third_party_dlls/logs.cc
   DrainLog
   RegisterLogNotification
diff --git a/chrome/chrome_elf/third_party_dlls/hardcoded_blocklist.cc b/chrome/chrome_elf/third_party_dlls/hardcoded_blocklist.cc
index 3f1c435..8d1d193 100644
--- a/chrome/chrome_elf/third_party_dlls/hardcoded_blocklist.cc
+++ b/chrome/chrome_elf/third_party_dlls/hardcoded_blocklist.cc
@@ -4,35 +4,12 @@
 
 #include "chrome/chrome_elf/third_party_dlls/hardcoded_blocklist.h"
 
-#include <windows.h>
-
 namespace third_party_dlls {
 
 namespace {
 
-// Utility function for converting UTF-8 to UTF-16.
-// Note: Not using base::UTF8ToUTF16() because chrome_elf can not have any
-//       dependencies on //base.
-bool UTF8ToUTF16(const std::string& utf8, std::wstring* utf16) {
-  assert(utf16);
-
-  if (utf8.empty()) {
-    utf16->clear();
-    return true;
-  }
-
-  int size_needed_chars = ::MultiByteToWideChar(
-      CP_UTF8, 0, utf8.c_str(), static_cast<int>(utf8.size()), nullptr, 0);
-  if (!size_needed_chars)
-    return false;
-
-  utf16->resize(size_needed_chars);
-  return ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(),
-                               static_cast<int>(utf8.size()), &(*utf16)[0],
-                               size_needed_chars);
-}
-
-}  // namespace
+// Max size of the DLL blocklist.
+constexpr size_t kDllBlocklistMaxSize = 64u;
 
 // The DLLs listed here are known (or under strong suspicion) of causing crashes
 // when they are loaded in the browser. DLLs should only be added to this list
@@ -40,64 +17,57 @@
 // For more information about how this list is generated, and how to get off
 // of it, see:
 // https://sites.google.com/a/chromium.org/dev/Home/third-party-developers
-// NOTE: Please remember to update the DllHash enum in histograms.xml when
-//       adding a new value to the blacklist.
-// TODO(pmonette): Change to const char* const when the
-//                 chrome/chrome_elf/blacklist directory gets deleted.
-const wchar_t* g_troublesome_dlls[kTroublesomeDllsMaxCount] = {
-    L"949ba8b6a9.dll",           // Coupon Time.
-    L"activedetect32.dll",       // Lenovo One Key Theater.
-                                 // See crbug.com/379218.
-    L"activedetect64.dll",       // Lenovo One Key Theater.
-    L"bitguard.dll",             // Unknown (suspected malware).
-    L"bsvc.dll",                 // Unknown (suspected adware).
-    L"chrmxtn.dll",              // Unknown (keystroke logger).
-    L"cplushook.dll",            // Unknown (suspected malware).
-    L"crdli.dll",                // Linkury Inc.
-    L"crdli64.dll",              // Linkury Inc.
-    L"datamngr.dll",             // Unknown (suspected adware).
-    L"dpinterface32.dll",        // Unknown (suspected adware).
-    L"explorerex.dll",           // Unknown (suspected adware).
-    L"hk.dll",                   // Unknown (keystroke logger).
-    L"libapi2hook.dll",          // V-Bates.
-    L"libinject.dll",            // V-Bates.
-    L"libinject2.dll",           // V-Bates.
-    L"libredir2.dll",            // V-Bates.
-    L"libsvn_tsvn32.dll",        // TortoiseSVN.
-    L"libwinhook.dll",           // V-Bates.
-    L"lmrn.dll",                 // Unknown.
-    L"minisp.dll",               // Unknown (suspected malware).
-    L"minisp32.dll",             // Unknown (suspected malware).
-    L"offerswizarddll.dll",      // Unknown (suspected adware).
-    L"safetynut.dll",            // Unknown (suspected adware).
-    L"smdmf.dll",                // Unknown (suspected adware).
-    L"spappsv32.dll",            // Unknown (suspected adware).
-    L"systemk.dll",              // Unknown (suspected adware).
-    L"vntsrv.dll",               // Virtual New Tab by APN LLC.
-    L"wajam_goblin_64.dll",      // Wajam Internet Technologies.
-    L"wajam_goblin.dll",         // Wajam Internet Technologies.
-    L"windowsapihookdll32.dll",  // Lenovo One Key Theater.
-                                 // See crbug.com/379218.
-    L"windowsapihookdll64.dll",  // Lenovo One Key Theater.
-    L"virtualcamera.ax",         // %PROGRAMFILES%\ASUS\VirtualCamera.
-                                 // See crbug.com/422522.
-    L"ycwebcamerasource.ax",     // CyberLink Youcam, crbug.com/424159
+const char* const kDllBlocklist[kDllBlocklistMaxSize] = {
+    "949ba8b6a9.dll",           // Coupon Time.
+    "activedetect32.dll",       // Lenovo One Key Theater.
+                                // See crbug.com/379218.
+    "activedetect64.dll",       // Lenovo One Key Theater.
+    "bitguard.dll",             // Unknown (suspected malware).
+    "bsvc.dll",                 // Unknown (suspected adware).
+    "chrmxtn.dll",              // Unknown (keystroke logger).
+    "cplushook.dll",            // Unknown (suspected malware).
+    "crdli.dll",                // Linkury Inc.
+    "crdli64.dll",              // Linkury Inc.
+    "datamngr.dll",             // Unknown (suspected adware).
+    "dpinterface32.dll",        // Unknown (suspected adware).
+    "explorerex.dll",           // Unknown (suspected adware).
+    "hk.dll",                   // Unknown (keystroke logger).
+    "libapi2hook.dll",          // V-Bates.
+    "libinject.dll",            // V-Bates.
+    "libinject2.dll",           // V-Bates.
+    "libredir2.dll",            // V-Bates.
+    "libsvn_tsvn32.dll",        // TortoiseSVN.
+    "libwinhook.dll",           // V-Bates.
+    "lmrn.dll",                 // Unknown.
+    "minisp.dll",               // Unknown (suspected malware).
+    "minisp32.dll",             // Unknown (suspected malware).
+    "offerswizarddll.dll",      // Unknown (suspected adware).
+    "safetynut.dll",            // Unknown (suspected adware).
+    "smdmf.dll",                // Unknown (suspected adware).
+    "spappsv32.dll",            // Unknown (suspected adware).
+    "systemk.dll",              // Unknown (suspected adware).
+    "vntsrv.dll",               // Virtual New Tab by APN LLC.
+    "wajam_goblin_64.dll",      // Wajam Internet Technologies.
+    "wajam_goblin.dll",         // Wajam Internet Technologies.
+    "windowsapihookdll32.dll",  // Lenovo One Key Theater.
+                                // See crbug.com/379218.
+    "windowsapihookdll64.dll",  // Lenovo One Key Theater.
+    "virtualcamera.ax",         // %PROGRAMFILES%\ASUS\VirtualCamera.
+                                // See crbug.com/422522.
+    "ycwebcamerasource.ax",     // CyberLink Youcam, crbug.com/424159
     // Keep this null pointer here to mark the end of the list.
     nullptr,
 };
 
+}  // namespace
+
 bool DllMatch(const std::string& module_name) {
   if (module_name.empty())
     return false;
 
-  // Convert UTF-8 to UTF-16 for this comparison.
-  std::wstring wide_module_name;
-  if (!UTF8ToUTF16(module_name, &wide_module_name))
-    return false;
-
-  for (int i = 0; g_troublesome_dlls[i] != nullptr; ++i) {
-    if (_wcsicmp(wide_module_name.c_str(), g_troublesome_dlls[i]) == 0)
-      return i;
+  for (int i = 0; kDllBlocklist[i] != nullptr; ++i) {
+    if (strcmp(module_name.c_str(), kDllBlocklist[i]) == 0)
+      return true;
   }
 
   return false;
diff --git a/chrome/chrome_elf/third_party_dlls/hardcoded_blocklist.h b/chrome/chrome_elf/third_party_dlls/hardcoded_blocklist.h
index c3f989d3..3a8103ee 100644
--- a/chrome/chrome_elf/third_party_dlls/hardcoded_blocklist.h
+++ b/chrome/chrome_elf/third_party_dlls/hardcoded_blocklist.h
@@ -9,12 +9,6 @@
 
 namespace third_party_dlls {
 
-// Max size of the DLL blocklist.
-constexpr size_t kTroublesomeDllsMaxCount = 64u;
-
-// The DLL blacklist.
-extern const wchar_t* g_troublesome_dlls[kTroublesomeDllsMaxCount];
-
 // Returns true if a matching name is found in the hard-coded blocklist.
 // Note: |module_name| must be an ASCII encoded string.
 bool DllMatch(const std::string& module_name);
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index c47abebf..829a8013 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -196,6 +196,10 @@
       sources += [ "$root_gen_dir/chrome/print_preview_resources.pak" ]
       deps += [ "//chrome/browser/resources:print_preview_resources" ]
     }
+    if (enable_webui_tab_strip) {
+      sources += [ "$root_gen_dir/chrome/tab_strip_resources.pak" ]
+      deps += [ "//chrome/browser/resources:tab_strip_resources" ]
+    }
   }
 }
 
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 76c9d43..b12bf4e 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -49,6 +49,7 @@
     "ENABLE_SIMPLE_BROWSER_SERVICE_OUT_OF_PROCESS=$enable_simple_browser_service_out_of_process",
     "ENABLE_SUPERVISED_USERS=$enable_supervised_users",
     "ENABLE_WAYLAND_SERVER=$enable_wayland_server",
+    "ENABLE_WEBUI_TAB_STRIP=$enable_webui_tab_strip",
     "PGO_BUILD=$pgo_build",
     "OPTIMIZE_WEBUI=$optimize_webui",
   ]
diff --git a/chrome/common/features.gni b/chrome/common/features.gni
index 120beac..3a0f643 100644
--- a/chrome/common/features.gni
+++ b/chrome/common/features.gni
@@ -86,6 +86,7 @@
   "enable_printing=$enable_basic_printing",
   "enable_service_discovery=$enable_service_discovery",
   "enable_vr=$enable_vr",
+  "enable_webui_tab_strip=$enable_webui_tab_strip",
   "safe_browsing_mode=$safe_browsing_mode",
   "optimize_webui=$optimize_webui",
 ]
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 4ea75d7..3724463 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -336,6 +336,10 @@
 const char kChromeUIPrintHost[] = "print";
 #endif
 
+#if BUILDFLAG(ENABLE_WEBUI_TAB_STRIP)
+const char kChromeUITabStripHost[] = "tab-strip";
+#endif
+
 const char kChromeUIWebRtcLogsHost[] = "webrtc-logs";
 
 // Settings sub pages.
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index f6935a3..07ccb8c 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -297,6 +297,10 @@
 extern const char kChromeUIPrintHost[];
 #endif
 
+#if BUILDFLAG(ENABLE_WEBUI_TAB_STRIP)
+extern const char kChromeUITabStripHost[];
+#endif
+
 extern const char kChromeUIWebRtcLogsHost[];
 
 // Settings sub-pages.
diff --git a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/ChromeFileProvider.java b/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/ChromeFileProvider.java
index d454428..79c4d67 100644
--- a/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/ChromeFileProvider.java
+++ b/chrome/lib/util/public/android/java/src/org/chromium/chrome/browser/util/ChromeFileProvider.java
@@ -68,7 +68,8 @@
      * @param context Activity context that is used to access package manager.
      * @param file File for which the Uri is generated.
      */
-    public static Uri generateUri(final Context context, File file) {
+    public static Uri generateUri(final Context context, File file)
+            throws IllegalArgumentException {
         return getUriForFile(context, getAuthority(context), file);
     }
 
diff --git a/chrome/services/cups_ipp_parser/BUILD.gn b/chrome/services/cups_ipp_parser/BUILD.gn
index c390c5b79..76256d5 100644
--- a/chrome/services/cups_ipp_parser/BUILD.gn
+++ b/chrome/services/cups_ipp_parser/BUILD.gn
@@ -9,8 +9,6 @@
 
 source_set("cups_ipp_parser") {
   sources = [
-    "cups_ipp_parser_service.cc",
-    "cups_ipp_parser_service.h",
     "ipp_parser.h",
   ]
 
@@ -25,7 +23,6 @@
     "//chrome/services/cups_ipp_parser/public/mojom",
     "//mojo/public/mojom/base",
     "//printing",
-    "//services/service_manager/public/cpp",
   ]
 
   # We stub the implementation if libCUPS is not present.
diff --git a/chrome/services/cups_ipp_parser/cups_ipp_parser_service.cc b/chrome/services/cups_ipp_parser/cups_ipp_parser_service.cc
deleted file mode 100644
index c82289d5..0000000
--- a/chrome/services/cups_ipp_parser/cups_ipp_parser_service.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/services/cups_ipp_parser/cups_ipp_parser_service.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "chrome/services/cups_ipp_parser/ipp_parser.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace cups_ipp_parser {
-namespace {
-
-void OnIppParserRequest(service_manager::ServiceKeepalive* keepalive,
-                        mojom::IppParserRequest request) {
-  mojo::MakeStrongBinding(std::make_unique<IppParser>(keepalive->CreateRef()),
-                          std::move(request));
-}
-
-}  // namespace
-
-CupsIppParserService::CupsIppParserService(
-    service_manager::mojom::ServiceRequest request)
-    : service_binding_(this, std::move(request)),
-      service_keepalive_(&service_binding_, base::TimeDelta()) {}
-
-CupsIppParserService::~CupsIppParserService() = default;
-
-void CupsIppParserService::OnStart() {
-  registry_.AddInterface(
-      base::BindRepeating(&OnIppParserRequest, &service_keepalive_));
-
-  DVLOG(1) << "CupsIppParserService started.";
-}
-
-void CupsIppParserService::OnBindInterface(
-    const service_manager::BindSourceInfo& source_info,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle interface_pipe) {
-  registry_.BindInterface(interface_name, std::move(interface_pipe));
-}
-
-}  // namespace cups_ipp_parser
diff --git a/chrome/services/cups_ipp_parser/cups_ipp_parser_service.h b/chrome/services/cups_ipp_parser/cups_ipp_parser_service.h
deleted file mode 100644
index 6908c5d..0000000
--- a/chrome/services/cups_ipp_parser/cups_ipp_parser_service.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_SERVICES_CUPS_IPP_PARSER_CUPS_IPP_PARSER_SERVICE_H_
-#define CHROME_SERVICES_CUPS_IPP_PARSER_CUPS_IPP_PARSER_SERVICE_H_
-
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_binding.h"
-#include "services/service_manager/public/cpp/service_keepalive.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
-
-namespace cups_ipp_parser {
-
-// CupsIppParser Service Implementation.
-//
-// This service's sole purpose is parsing CUPS IPP printing requests. It accepts
-// arbitrary byte buffers as input and returns a fully-parsed IPP request,
-// mojom::IppRequest, as a result.
-//
-// Because this service doesn't know the origin of these requests, it
-// treats each request as potentially malicious. As such, this service runs
-// out-of-process, lessening the chance of exposing an exploit to the rest of
-// Chrome.
-//
-// Note: In practice, this service is used to support printing requests incoming
-// from ChromeOS.
-class CupsIppParserService : public service_manager::Service {
- public:
-  explicit CupsIppParserService(service_manager::mojom::ServiceRequest request);
-  ~CupsIppParserService() override;
-
-  // Lifecycle events that occur after the service has started to spinup.
-  void OnStart() override;
-  void OnBindInterface(const service_manager::BindSourceInfo& source_info,
-                       const std::string& interface_name,
-                       mojo::ScopedMessagePipeHandle interface_pipe) override;
-
- private:
-  service_manager::ServiceBinding service_binding_;
-  service_manager::ServiceKeepalive service_keepalive_;
-  service_manager::BinderRegistry registry_;
-
-  DISALLOW_COPY_AND_ASSIGN(CupsIppParserService);
-};
-
-}  // namespace cups_ipp_parser
-
-#endif  // CHROME_SERVICES_CUPS_IPP_PARSER_CUPS_IPP_PARSER_SERVICE_H_
diff --git a/chrome/services/cups_ipp_parser/fake_ipp_parser.cc b/chrome/services/cups_ipp_parser/fake_ipp_parser.cc
index 723ab827..72c6638 100644
--- a/chrome/services/cups_ipp_parser/fake_ipp_parser.cc
+++ b/chrome/services/cups_ipp_parser/fake_ipp_parser.cc
@@ -9,9 +9,8 @@
 
 namespace cups_ipp_parser {
 
-IppParser::IppParser(
-    std::unique_ptr<service_manager::ServiceContextRef> service_ref)
-    : service_ref_(std::move(service_ref)) {}
+IppParser::IppParser(mojo::PendingReceiver<mojom::IppParser> receiver)
+    : receiver_(this, std::move(receiver)) {}
 
 IppParser::~IppParser() = default;
 
diff --git a/chrome/services/cups_ipp_parser/ipp_parser.cc b/chrome/services/cups_ipp_parser/ipp_parser.cc
index c0c6576..b27cca69 100644
--- a/chrome/services/cups_ipp_parser/ipp_parser.cc
+++ b/chrome/services/cups_ipp_parser/ipp_parser.cc
@@ -13,7 +13,6 @@
 #include "base/optional.h"
 #include "chrome/services/cups_ipp_parser/public/cpp/ipp_converter.h"
 #include "chrome/services/cups_proxy/public/cpp/type_conversions.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/http/http_util.h"
 
 namespace cups_ipp_parser {
@@ -140,9 +139,8 @@
 
 }  // namespace
 
-IppParser::IppParser(
-    std::unique_ptr<service_manager::ServiceContextRef> service_ref)
-    : service_ref_(std::move(service_ref)) {}
+IppParser::IppParser(mojo::PendingReceiver<mojom::IppParser> receiver)
+    : receiver_(this, std::move(receiver)) {}
 
 IppParser::~IppParser() = default;
 
diff --git a/chrome/services/cups_ipp_parser/ipp_parser.h b/chrome/services/cups_ipp_parser/ipp_parser.h
index 1503fae..e303191 100644
--- a/chrome/services/cups_ipp_parser/ipp_parser.h
+++ b/chrome/services/cups_ipp_parser/ipp_parser.h
@@ -6,7 +6,8 @@
 #define CHROME_SERVICES_CUPS_IPP_PARSER_IPP_PARSER_H_
 
 #include "chrome/services/cups_ipp_parser/public/mojom/ipp_parser.mojom.h"
-#include "services/service_manager/public/cpp/service_context_ref.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
 namespace cups_ipp_parser {
 
@@ -18,8 +19,7 @@
 // Service.
 class IppParser : public mojom::IppParser {
  public:
-  explicit IppParser(
-      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+  explicit IppParser(mojo::PendingReceiver<mojom::IppParser> receiver);
   ~IppParser() override;
 
  private:
@@ -30,7 +30,7 @@
   void ParseIpp(const std::vector<uint8_t>& to_parse,
                 ParseIppCallback callback) override;
 
-  const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
+  mojo::Receiver<mojom::IppParser> receiver_;
 
   DISALLOW_COPY_AND_ASSIGN(IppParser);
 };
diff --git a/chrome/services/cups_ipp_parser/public/cpp/BUILD.gn b/chrome/services/cups_ipp_parser/public/cpp/BUILD.gn
index 73c36631..78ce7d8b 100644
--- a/chrome/services/cups_ipp_parser/public/cpp/BUILD.gn
+++ b/chrome/services/cups_ipp_parser/public/cpp/BUILD.gn
@@ -41,22 +41,6 @@
   }
 }
 
-if (is_chromeos) {
-  source_set("manifest") {
-    sources = [
-      "manifest.cc",
-      "manifest.h",
-    ]
-
-    deps = [
-      "//base",
-      "//chrome:strings",
-      "//chrome/services/cups_ipp_parser/public/mojom",
-      "//services/service_manager/public/cpp",
-    ]
-  }
-}
-
 # A dummy group to make fuzz targets discoverable.
 group("fuzzers") {
 }
diff --git a/chrome/services/cups_ipp_parser/public/cpp/OWNERS b/chrome/services/cups_ipp_parser/public/cpp/OWNERS
deleted file mode 100644
index 6faeaa47..0000000
--- a/chrome/services/cups_ipp_parser/public/cpp/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-per-file manifest.cc=set noparent
-per-file manifest.cc=file://ipc/SECURITY_OWNERS
-per-file manifest.h=set noparent
-per-file manifest.h=file://ipc/SECURITY_OWNERS
diff --git a/chrome/services/cups_ipp_parser/public/cpp/manifest.cc b/chrome/services/cups_ipp_parser/public/cpp/manifest.cc
deleted file mode 100644
index 6dbd0ef0..0000000
--- a/chrome/services/cups_ipp_parser/public/cpp/manifest.cc
+++ /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.
-
-#include "chrome/services/cups_ipp_parser/public/cpp/manifest.h"
-
-#include <set>
-
-#include "base/no_destructor.h"
-#include "chrome/grit/generated_resources.h"
-#include "chrome/services/cups_ipp_parser/public/mojom/constants.mojom.h"
-#include "chrome/services/cups_ipp_parser/public/mojom/ipp_parser.mojom.h"
-#include "services/service_manager/public/cpp/manifest_builder.h"
-
-const service_manager::Manifest& GetCupsIppParserManifest() {
-  static base::NoDestructor<service_manager::Manifest> manifest{
-      service_manager::ManifestBuilder()
-          .WithServiceName(cups_ipp_parser::mojom::kCupsIppParserServiceName)
-          .WithDisplayName(IDS_UTILITY_PROCESS_CUPS_IPP_PARSER_SERVICE_NAME)
-          .WithOptions(
-              service_manager::ManifestOptionsBuilder()
-                  .WithExecutionMode(service_manager::Manifest::ExecutionMode::
-                                         kOutOfProcessBuiltin)
-                  .WithSandboxType("utility")
-                  .WithInstanceSharingPolicy(
-                      service_manager::Manifest::InstanceSharingPolicy::
-                          kSharedAcrossGroups)
-                  .Build())
-          .ExposeCapability("ipp_parser",
-                            service_manager::Manifest::InterfaceList<
-                                cups_ipp_parser::mojom::IppParser>())
-          .Build()};
-  return *manifest;
-}
diff --git a/chrome/services/cups_ipp_parser/public/cpp/manifest.h b/chrome/services/cups_ipp_parser/public/cpp/manifest.h
deleted file mode 100644
index a6baf2f1..0000000
--- a/chrome/services/cups_ipp_parser/public/cpp/manifest.h
+++ /dev/null
@@ -1,12 +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 CHROME_SERVICES_CUPS_IPP_PARSER_PUBLIC_CPP_MANIFEST_H_
-#define CHROME_SERVICES_CUPS_IPP_PARSER_PUBLIC_CPP_MANIFEST_H_
-
-#include "services/service_manager/public/cpp/manifest.h"
-
-const service_manager::Manifest& GetCupsIppParserManifest();
-
-#endif  // CHROME_SERVICES_CUPS_IPP_PARSER_PUBLIC_CPP_MANIFEST_H_
diff --git a/chrome/services/cups_ipp_parser/public/mojom/BUILD.gn b/chrome/services/cups_ipp_parser/public/mojom/BUILD.gn
index b36a1fa9a..426c63c 100644
--- a/chrome/services/cups_ipp_parser/public/mojom/BUILD.gn
+++ b/chrome/services/cups_ipp_parser/public/mojom/BUILD.gn
@@ -7,7 +7,6 @@
 
 mojom("mojom") {
   sources = [
-    "constants.mojom",
     "ipp_parser.mojom",
   ]
 
diff --git a/chrome/services/cups_ipp_parser/public/mojom/constants.mojom b/chrome/services/cups_ipp_parser/public/mojom/constants.mojom
deleted file mode 100644
index 1e41ed9f..0000000
--- a/chrome/services/cups_ipp_parser/public/mojom/constants.mojom
+++ /dev/null
@@ -1,7 +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.
-
-module cups_ipp_parser.mojom;
-
-const string kCupsIppParserServiceName = "cups_ipp_parser";
diff --git a/chrome/services/cups_proxy/BUILD.gn b/chrome/services/cups_proxy/BUILD.gn
index f163e54..5d45be4 100644
--- a/chrome/services/cups_proxy/BUILD.gn
+++ b/chrome/services/cups_proxy/BUILD.gn
@@ -22,8 +22,6 @@
     "//chrome/services/cups_proxy/public/mojom",
     "//chromeos/dbus",
     "//net",
-    "//services/service_manager/public/cpp",
-    "//services/service_manager/public/mojom",
   ]
 
   # We stub this service if libCUPS is not present.
diff --git a/chrome/services/cups_proxy/cups_proxy_service.h b/chrome/services/cups_proxy/cups_proxy_service.h
index 8bf4fe3..65345ca 100644
--- a/chrome/services/cups_proxy/cups_proxy_service.h
+++ b/chrome/services/cups_proxy/cups_proxy_service.h
@@ -12,10 +12,6 @@
 #include "base/observer_list.h"
 #include "base/observer_list_types.h"
 #include "chrome/services/cups_proxy/public/mojom/proxy.mojom.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_binding.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
 
 namespace cups_proxy {
 
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index 2c5ffd41..c29b0589 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -175,7 +175,7 @@
 
 #if defined(OS_CHROMEOS) || defined(OS_MACOSX) || defined(OS_WIN) || \
     defined(OS_LINUX)
-  void ShowHatsBubbleFromAppMenuButton() override {}
+  void ShowHatsBubbleFromAppMenuButton(const std::string& site_id) override {}
 #endif
 
   void ExecuteExtensionCommand(const extensions::Extension* extension,
diff --git a/chrome/test/base/web_ui_browser_test.cc b/chrome/test/base/web_ui_browser_test.cc
index 9b35a89..eaab1a4 100644
--- a/chrome/test/base/web_ui_browser_test.cc
+++ b/chrome/test/base/web_ui_browser_test.cc
@@ -395,7 +395,7 @@
 
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override {
     std::string dummy_html = "<html><body>Dummy</body></html>";
     scoped_refptr<base::RefCountedString> response =
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS
index e512e59..6b099a5 100644
--- a/chrome/utility/DEPS
+++ b/chrome/utility/DEPS
@@ -1,7 +1,7 @@
 include_rules = [
   "+chrome/grit",
   "+chrome/installer/util",
-  "+chrome/services/cups_ipp_parser/cups_ipp_parser_service.h",
+  "+chrome/services/cups_ipp_parser/ipp_parser.h",
   "+chrome/services/cups_ipp_parser/public/mojom",
   "+chrome/services/file_util/file_util_service.h",
   "+chrome/services/file_util/public/mojom",
diff --git a/chrome/utility/OWNERS b/chrome/utility/OWNERS
index 0ecff5f..b7d9a0fd 100644
--- a/chrome/utility/OWNERS
+++ b/chrome/utility/OWNERS
@@ -1,3 +1,4 @@
 # For service-related code
 per-file chrome_content_utility_client.*=rockot@google.com
-# COMPONENT: Internals>Services>ServiceManager
+per-file services.cc=rockot@google.com
+# COMPONENT: Internals>Services
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index 85e4ce0..1f8f536 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -93,11 +93,6 @@
 #include "chrome/utility/printing_handler.h"
 #endif
 
-#if BUILDFLAG(ENABLE_PRINTING) && defined(OS_CHROMEOS)
-#include "chrome/services/cups_ipp_parser/cups_ipp_parser_service.h"  // nogncheck
-#include "chrome/services/cups_ipp_parser/public/mojom/constants.mojom.h"  // nogncheck
-#endif
-
 #if BUILDFLAG(FULL_SAFE_BROWSING) || defined(OS_CHROMEOS)
 #include "chrome/services/file_util/file_util_service.h"  // nogncheck
 #include "chrome/services/file_util/public/mojom/constants.mojom.h"  // nogncheck
@@ -266,12 +261,6 @@
   if (service_name == chromeos::ime::mojom::kServiceName)
     return std::make_unique<chromeos::ime::ImeService>(std::move(request));
 
-#if BUILDFLAG(ENABLE_PRINTING)
-  if (service_name == cups_ipp_parser::mojom::kCupsIppParserServiceName)
-    return std::make_unique<cups_ipp_parser::CupsIppParserService>(
-        std::move(request));
-#endif
-
 #if BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
   if (service_name == chromeos::assistant::mojom::kAudioDecoderServiceName) {
     return std::make_unique<chromeos::assistant::AssistantAudioDecoderService>(
diff --git a/chrome/utility/services.cc b/chrome/utility/services.cc
index b33775b..5669206f 100644
--- a/chrome/utility/services.cc
+++ b/chrome/utility/services.cc
@@ -14,6 +14,7 @@
 #include "components/services/unzip/public/mojom/unzipper.mojom.h"
 #include "components/services/unzip/unzipper_impl.h"
 #include "mojo/public/cpp/bindings/service_factory.h"
+#include "printing/buildflags/buildflags.h"
 
 #if defined(OS_WIN)
 #include "chrome/services/util_win/public/mojom/util_win.mojom.h"
@@ -25,6 +26,11 @@
 #include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
 #endif  // !defined(OS_ANDROID)
 
+#if BUILDFLAG(ENABLE_PRINTING) && defined(OS_CHROMEOS)
+#include "chrome/services/cups_ipp_parser/ipp_parser.h"  // nogncheck
+#include "chrome/services/cups_ipp_parser/public/mojom/ipp_parser.mojom.h"  // nogncheck
+#endif
+
 namespace {
 
 auto RunFilePatcher(mojo::PendingReceiver<patch::mojom::FilePatcher> receiver) {
@@ -50,6 +56,13 @@
 }
 #endif  // !defined(OS_ANDROID)
 
+#if BUILDFLAG(ENABLE_PRINTING) && defined(OS_CHROMEOS)
+auto RunCupsIppParser(
+    mojo::PendingReceiver<cups_ipp_parser::mojom::IppParser> receiver) {
+  return std::make_unique<cups_ipp_parser::IppParser>(std::move(receiver));
+}
+#endif
+
 }  // namespace
 
 mojo::ServiceFactory* GetMainThreadServiceFactory() {
@@ -57,9 +70,14 @@
   static base::NoDestructor<mojo::ServiceFactory> factory {
     RunFilePatcher,
     RunUnzipper,
+
 #if defined(OS_WIN)
     RunWindowsUtility,
 #endif  // defined(OS_WIN)
+
+#if BUILDFLAG(ENABLE_PRINTING) && defined(OS_CHROMEOS)
+    RunCupsIppParser,
+#endif
   };
   // clang-format on
   return factory.get();
diff --git a/chromeos/audio/OWNERS b/chromeos/audio/OWNERS
index e71cb32..f224695 100644
--- a/chromeos/audio/OWNERS
+++ b/chromeos/audio/OWNERS
@@ -1,2 +1,3 @@
 jennyz@chromium.org
 hychao@chromium.org
+# COMPONENT: OS>Kernel>Audio
diff --git a/components/arc/common/BUILD.gn b/components/arc/common/BUILD.gn
index 8599964..9026142 100644
--- a/components/arc/common/BUILD.gn
+++ b/components/arc/common/BUILD.gn
@@ -68,7 +68,7 @@
     public_deps = [
       ":media",
       ":notifications",
-      "//media/capture/video/chromeos/mojo:cros_camera",
+      "//media/capture/video/chromeos/mojom:cros_camera",
       "//mojo/public/mojom/base",
       "//services/device/public/mojom:usb",
       "//services/media_session/public/mojom",
diff --git a/components/arc/common/camera.mojom b/components/arc/common/camera.mojom
index 424bf5b..04106e6 100644
--- a/components/arc/common/camera.mojom
+++ b/components/arc/common/camera.mojom
@@ -6,7 +6,7 @@
 
 module arc.mojom;
 
-import "media/capture/video/chromeos/mojo/cros_camera_service.mojom";
+import "media/capture/video/chromeos/mojom/cros_camera_service.mojom";
 
 struct CameraDeviceInfo {
   string device_path@0;
diff --git a/components/arc/video_accelerator/arc_video_accelerator_util.cc b/components/arc/video_accelerator/arc_video_accelerator_util.cc
index adc6db3..b49edce 100644
--- a/components/arc/video_accelerator/arc_video_accelerator_util.cc
+++ b/components/arc/video_accelerator/arc_video_accelerator_util.cc
@@ -8,6 +8,8 @@
 #include <unistd.h>
 
 #include "base/files/platform_file.h"
+#include "base/numerics/checked_math.h"
+#include "media/base/video_frame.h"
 #include "media/gpu/macros.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 
@@ -50,4 +52,49 @@
   return true;
 }
 
+bool VerifyVideoFrame(media::VideoPixelFormat pixel_format,
+                      const gfx::Size& coded_size,
+                      int fd,
+                      const std::vector<VideoFramePlane>& planes) {
+  const size_t num_planes = media::VideoFrame::NumPlanes(pixel_format);
+  if (planes.size() != num_planes || num_planes == 0) {
+    VLOGF(1) << "Invalid number of dmabuf planes passed: " << planes.size()
+             << ", expected: " << num_planes;
+    return false;
+  }
+
+  // We expect offset monotonically increase.
+  for (size_t i = 1; i < num_planes; i++) {
+    if (planes[i].offset < planes[i - 1].offset)
+      return false;
+  }
+
+  size_t file_size_in_bytes;
+  if (!GetFileSize(fd, &file_size_in_bytes))
+    return false;
+
+  for (size_t i = 0; i < planes.size(); ++i) {
+    const auto& plane = planes[i];
+
+    DVLOGF(4) << "Plane " << i << ", offset: " << plane.offset
+              << ", stride: " << plane.stride;
+
+    // Check |offset| + (the size of a plane) on each plane is not larger than
+    // |file_size_in_bytes|. This ensures we don't access out of a buffer
+    // referred by |fd|.
+    size_t row_bytes =
+        media::VideoFrame::RowBytes(i, pixel_format, coded_size.height());
+    base::CheckedNumeric<size_t> current_size(plane.offset);
+    current_size += base::CheckMul(plane.stride, row_bytes);
+
+    if (!current_size.IsValid() ||
+        current_size.ValueOrDie() > file_size_in_bytes) {
+      VLOGF(1) << "Invalid strides/offsets.";
+      return false;
+    }
+  }
+
+  return true;
+}
+
 }  // namespace arc
diff --git a/components/arc/video_accelerator/arc_video_accelerator_util.h b/components/arc/video_accelerator/arc_video_accelerator_util.h
index 3bcfa38..8d25e6b6 100644
--- a/components/arc/video_accelerator/arc_video_accelerator_util.h
+++ b/components/arc/video_accelerator/arc_video_accelerator_util.h
@@ -5,16 +5,28 @@
 #ifndef COMPONENTS_ARC_VIDEO_ACCELERATOR_ARC_VIDEO_ACCELERATOR_UTIL_H_
 #define COMPONENTS_ARC_VIDEO_ACCELERATOR_ARC_VIDEO_ACCELERATOR_UTIL_H_
 
+#include <vector>
+
 #include "base/files/scoped_file.h"
+#include "components/arc/video_accelerator/video_frame_plane.h"
+#include "media/base/video_types.h"
 #include "mojo/public/cpp/system/handle.h"
+#include "ui/gfx/geometry/size.h"
+
 namespace arc {
 
 // Creates ScopedFD from given mojo::ScopedHandle.
 // Returns invalid ScopedFD on failure.
 base::ScopedFD UnwrapFdFromMojoHandle(mojo::ScopedHandle handle);
 
-// Return the file size of |fd|.
+// Return the file size of |fd| in bytes.
 bool GetFileSize(const int fd, size_t* size);
 
+// Return true iff |planes| is valid for a video frame located on |fd|
+// and of |pixel_format| and |coded_size|.
+bool VerifyVideoFrame(media::VideoPixelFormat pixel_format,
+                      const gfx::Size& coded_size,
+                      int fd,
+                      const std::vector<VideoFramePlane>& planes);
 }  // namespace arc
 #endif  // COMPONENTS_ARC_VIDEO_ACCELERATOR_ARC_VIDEO_ACCELERATOR_UTIL_H_
diff --git a/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc b/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc
index 86e04b25..53d2313 100644
--- a/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc
+++ b/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc
@@ -68,42 +68,6 @@
   }
 }
 
-// Return true iff |planes| is valid for a video frame located on |dmabuf_fd|
-// and of |pixel_format|.
-bool VerifyDmabuf(media::VideoPixelFormat pixel_format,
-                  const gfx::Size& coded_size,
-                  int dmabuf_fd,
-                  const std::vector<arc::VideoFramePlane>& planes) {
-  const size_t num_planes = media::VideoFrame::NumPlanes(pixel_format);
-  if (planes.size() != num_planes || num_planes == 0) {
-    VLOGF(1) << "Invalid number of dmabuf planes passed: " << planes.size()
-             << ", expected: " << num_planes;
-    return false;
-  }
-
-  size_t size;
-  if (!arc::GetFileSize(dmabuf_fd, &size))
-    return false;
-
-  for (size_t i = 0; i < planes.size(); ++i) {
-    const auto& plane = planes[i];
-
-    DVLOGF(4) << "Plane " << i << ", offset: " << plane.offset
-              << ", stride: " << plane.stride;
-
-    size_t rows = media::VideoFrame::Rows(i, pixel_format, coded_size.height());
-    base::CheckedNumeric<size_t> current_size(plane.offset);
-    current_size += base::CheckMul(plane.stride, rows);
-
-    if (!current_size.IsValid() || current_size.ValueOrDie() > size) {
-      VLOGF(1) << "Invalid strides/offsets.";
-      return false;
-    }
-  }
-
-  return true;
-}
-
 }  // namespace
 
 namespace arc {
@@ -527,7 +491,7 @@
     }
     gmb_handle.native_pixmap_handle = std::move(protected_native_pixmap);
   } else {
-    if (!VerifyDmabuf(pixel_format, coded_size_, handle_fd.get(), planes)) {
+    if (!VerifyVideoFrame(pixel_format, coded_size_, handle_fd.get(), planes)) {
       VLOGF(1) << "Failed verifying dmabuf";
       client_->NotifyError(
           mojom::VideoDecodeAccelerator::Result::INVALID_ARGUMENT);
diff --git a/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc b/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
index 351180d..9d76950 100644
--- a/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
+++ b/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
@@ -153,8 +153,45 @@
     return;
   }
 
-  size_t allocation_size =
-      media::VideoFrame::AllocationSize(format, coded_size_);
+  if (!VerifyVideoFrame(format, coded_size_, fd.get(), planes)) {
+    client_->NotifyError(Error::kInvalidArgumentError);
+    return;
+  }
+
+  const size_t num_planes = media::VideoFrame::NumPlanes(format);
+  // This is guaranteed because format is I420 here.
+  DCHECK_EQ(num_planes, 3u);
+  std::vector<media::VideoFrameLayout::Plane> layout_planes(num_planes);
+  for (size_t i = 0; i < num_planes; i++) {
+    layout_planes[i].stride = planes[i].stride;
+    layout_planes[i].offset = planes[i].offset;
+    if (i != num_planes - 1) {
+      layout_planes[i].size = planes[i + 1].offset - planes[i].offset;
+    } else {
+      layout_planes[i].size =
+          media::VideoFrame::Rows(i, format, visible_size_.height()) *
+          planes[i].stride;
+    }
+  }
+
+  auto layout = media::VideoFrameLayout::CreateWithPlanes(
+      format, coded_size_, std::move(layout_planes));
+  if (!layout) {
+    DLOG(ERROR) << "Failed to create VideoFrameLayout.";
+    client_->NotifyError(Error::kInvalidArgumentError);
+    return;
+  }
+
+  base::CheckedNumeric<size_t> map_size = planes[0].offset;
+  for (size_t i = 0; i < num_planes; i++) {
+    map_size += layout->planes()[i].size;
+  }
+  if (!map_size.IsValid()) {
+    DLOG(ERROR) << "Invalid map_size";
+    client_->NotifyError(Error::kInvalidArgumentError);
+    return;
+  }
+
   // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763.
   // TODO(rockot): This fd comes from a mojo::ScopedHandle in
   // GpuArcVideoService::BindSharedMemory. That should be passed through,
@@ -164,24 +201,11 @@
       base::subtle::PlatformSharedMemoryRegion::Take(
           std::move(fd),
           base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe,
-          allocation_size, guid);
+          map_size.ValueOrDie(), guid);
   base::UnsafeSharedMemoryRegion shared_region =
       base::UnsafeSharedMemoryRegion::Deserialize(std::move(platform_region));
-
-  base::CheckedNumeric<off_t> map_offset = planes[0].offset;
-  base::CheckedNumeric<size_t> map_size = allocation_size;
-  const uint32_t aligned_offset =
-      planes[0].offset % base::SysInfo::VMAllocationGranularity();
-  map_offset -= aligned_offset;
-  map_size += aligned_offset;
-
-  if (!map_offset.IsValid() || !map_size.IsValid()) {
-    DLOG(ERROR) << "Invalid map_offset or map_size";
-    client_->NotifyError(Error::kInvalidArgumentError);
-    return;
-  }
   base::WritableSharedMemoryMapping mapping =
-      shared_region.MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie());
+      shared_region.MapAt(0u, map_size.ValueOrDie());
   if (!mapping.IsValid()) {
     DLOG(ERROR) << "Failed to map memory.";
     client_->NotifyError(Error::kPlatformFailureError);
@@ -189,12 +213,23 @@
   }
 
   uint8_t* shm_memory = mapping.GetMemoryAsSpan<uint8_t>().data();
-  auto frame = media::VideoFrame::WrapExternalData(
-      format, coded_size_, gfx::Rect(visible_size_), visible_size_,
-      shm_memory + aligned_offset, allocation_size,
+  DCHECK_EQ(layout->planes().size(), num_planes);
+  auto frame = media::VideoFrame::WrapExternalYuvDataWithLayout(
+      *layout, gfx::Rect(visible_size_), visible_size_,
+      shm_memory + layout->planes()[0].offset,
+      shm_memory + layout->planes()[1].offset,
+      shm_memory + layout->planes()[2].offset,
       base::TimeDelta::FromMicroseconds(timestamp));
-  frame->BackWithOwnedSharedMemory(std::move(shared_region), std::move(mapping),
-                                   planes[0].offset);
+  if (!frame) {
+    DLOG(ERROR) << "Failed to create VideoFrame";
+    client_->NotifyError(Error::kInvalidArgumentError);
+    return;
+  }
+  frame->BackWithOwnedSharedMemory(std::move(shared_region),
+                                   std::move(mapping));
+  // Add the function to |callback| to |frame|'s  destruction observer. When the
+  // |frame| goes out of scope, it executes |callback|.
+  frame->AddDestructionObserver(std::move(callback));
   accelerator_->Encode(frame, force_keyframe);
 }
 
diff --git a/components/arc/video_accelerator/protected_buffer_manager.cc b/components/arc/video_accelerator/protected_buffer_manager.cc
index af955f3..3acab7d 100644
--- a/components/arc/video_accelerator/protected_buffer_manager.cc
+++ b/components/arc/video_accelerator/protected_buffer_manager.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/memory/shared_memory.h"
 #include "base/system/sys_info.h"
+#include "base/threading/thread_checker.h"
 #include "components/arc/video_accelerator/protected_buffer_allocator.h"
 #include "media/gpu/macros.h"
 #include "mojo/public/cpp/system/buffer.h"
diff --git a/components/autofill/core/browser/autofill_download_manager.cc b/components/autofill/core/browser/autofill_download_manager.cc
index c543f3e..48ef6d2 100644
--- a/components/autofill/core/browser/autofill_download_manager.cc
+++ b/components/autofill/core/browser/autofill_download_manager.cc
@@ -381,6 +381,12 @@
   return out;
 }
 
+std::string FieldTypeToString(int type) {
+  return base::StrCat(
+      {base::NumberToString(type), std::string("/"),
+       AutofillType(static_cast<ServerFieldType>(type)).ToString()});
+}
+
 LogBuffer& operator<<(LogBuffer& out,
                       const autofill::AutofillUploadContents& upload) {
   if (!out.active())
@@ -411,9 +417,11 @@
     out << Tr{} << Attrib{"style", "font-weight: bold"}
         << "field_signature:" << field.signature();
 
-    LogBuffer autofill_type;
-    autofill_type << Tag{"span"} << field.autofill_type();
-    out << Tr{} << "autofill_type:" << std::move(autofill_type);
+    std::vector<std::string> types_as_strings;
+    types_as_strings.reserve(field.autofill_type_size());
+    for (int type : field.autofill_type())
+      types_as_strings.emplace_back(FieldTypeToString(type));
+    out << Tr{} << "autofill_type:" << types_as_strings;
 
     LogBuffer validities;
     validities << Tag{"span"} << "[";
diff --git a/components/autofill/core/browser/logging/log_buffer.cc b/components/autofill/core/browser/logging/log_buffer.cc
index a9fe4db..c678c92 100644
--- a/components/autofill/core/browser/logging/log_buffer.cc
+++ b/components/autofill/core/browser/logging/log_buffer.cc
@@ -55,9 +55,6 @@
 // and the lengths of strings should be relatively small and we reduce the
 // memory consumption of the DOM, which may grow rather large.
 //
-// TODO(crbug.com/928595) Provide a FindStringKey that returns a mutable string
-// and append to that string.
-//
 // If the last child of the element in buffer is a text node, append |text| to
 // it and return true (successful coalescing). Otherwise return false.
 bool TryCoalesceString(std::vector<base::Value>* buffer,
@@ -72,8 +69,8 @@
   auto& last_child = children->GetList().back();
   if (!IsTextNode(last_child))
     return false;
-  const std::string* old_text = last_child.FindStringKey("value");
-  last_child.SetStringKey("value", base::StrCat({*old_text, text}));
+  std::string* old_text = last_child.FindStringKey("value");
+  old_text->append(text.data(), text.size());
   return true;
 }
 
diff --git a/components/autofill/core/browser/logging/log_buffer.h b/components/autofill/core/browser/logging/log_buffer.h
index ff6f448..0a429471 100644
--- a/components/autofill/core/browser/logging/log_buffer.h
+++ b/components/autofill/core/browser/logging/log_buffer.h
@@ -166,6 +166,18 @@
   return buf;
 }
 
+template <typename T>
+LogBuffer& operator<<(LogBuffer& buf, const std::vector<T>& values) {
+  buf << "[";
+  for (size_t i = 0; i < values.size(); ++i) {
+    if (i)
+      buf << ", ";
+    buf << values.at(i);
+  }
+  buf << "]";
+  return buf;
+}
+
 // This is syntactic sugar for creating table rows in a LogBuffer. Each
 // value streamed into this LogTableRowBuffer is wrapped by a <td> element.
 // The entire row is wrapped by a <tr>.
diff --git a/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc b/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc
index 166f7b6..f3a7473 100644
--- a/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc
+++ b/components/chromeos_camera/mjpeg_decode_accelerator_unittest.cc
@@ -74,6 +74,10 @@
 // images. This is used for measuring of the similarity of two images.
 constexpr double kDecodeSimilarityThreshold = 1.25;
 
+// The buffer usage used to create GpuMemoryBuffer for testing.
+constexpr gfx::BufferUsage kBufferUsage =
+    gfx::BufferUsage::SCANOUT_CPU_READ_WRITE;
+
 // Environment to create test data for all test cases.
 class MjpegDecodeAcceleratorTestEnvironment;
 MjpegDecodeAcceleratorTestEnvironment* g_env;
@@ -190,6 +194,10 @@
       const gfx::Size& coded_size,
       const gfx::Size& visible_size);
 
+  // Gets a list of supported DMA-buf frame formats for
+  // CreateDmaBufVideoFrame().
+  std::vector<media::VideoPixelFormat> GetSupportedDmaBufFormats();
+
   // Used for InputSizeChange test case. The image size should be smaller than
   // |kDefaultJpegFilename|.
   std::unique_ptr<ParsedJpegImage> image_data_1280x720_black_;
@@ -297,8 +305,7 @@
   }
   std::unique_ptr<gfx::GpuMemoryBuffer> gmb =
       gpu_memory_buffer_manager_->CreateGpuMemoryBuffer(
-          coded_size, *gfx_format, gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE,
-          gpu::kNullSurfaceHandle);
+          coded_size, *gfx_format, kBufferUsage, gpu::kNullSurfaceHandle);
   if (!gmb) {
     LOG(ERROR) << "Failed to create GpuMemoryBuffer";
     return nullptr;
@@ -349,6 +356,23 @@
       base::TimeDelta());
 }
 
+std::vector<media::VideoPixelFormat>
+MjpegDecodeAcceleratorTestEnvironment::GetSupportedDmaBufFormats() {
+  constexpr media::VideoPixelFormat kPreferredFormats[] = {
+      media::PIXEL_FORMAT_NV12,
+      media::PIXEL_FORMAT_YV12,
+  };
+  std::vector<media::VideoPixelFormat> supported_formats;
+  for (const media::VideoPixelFormat format : kPreferredFormats) {
+    const base::Optional<gfx::BufferFormat> gfx_format =
+        media::VideoPixelFormatToGfxBufferFormat(format);
+    if (gfx_format && gpu_memory_buffer_manager_->IsFormatAndUsageSupported(
+                          *gfx_format, kBufferUsage))
+      supported_formats.push_back(format);
+  }
+  return supported_formats;
+}
+
 enum ClientState {
   CS_CREATED,
   CS_INITIALIZED,
@@ -531,9 +555,11 @@
 
   if (use_dmabuf_) {
     // TODO(kamesan): create test cases for more formats when they're used.
+    std::vector<media::VideoPixelFormat> supported_formats =
+        g_env->GetSupportedDmaBufFormats();
+    ASSERT_FALSE(supported_formats.empty());
     hw_out_dmabuf_frame_ = g_env->CreateDmaBufVideoFrame(
-        media::PIXEL_FORMAT_NV12, image_file->coded_size,
-        image_file->visible_size);
+        supported_formats[0], image_file->coded_size, image_file->visible_size);
     ASSERT_TRUE(hw_out_dmabuf_frame_);
     frame_mapper_ = media::VideoFrameMapperFactory::CreateMapper(
         hw_out_dmabuf_frame_->format(), true);
diff --git a/components/dbus/menu/BUILD.gn b/components/dbus/menu/BUILD.gn
index de7f7ab..ad0135d1 100644
--- a/components/dbus/menu/BUILD.gn
+++ b/components/dbus/menu/BUILD.gn
@@ -2,10 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/ui.gni")
+
 component("menu") {
   sources = [
     "menu.cc",
     "menu.h",
+    "menu_property_list.cc",
+    "menu_property_list.h",
     "properties_interface.cc",
     "properties_interface.h",
     "success_barrier_callback.cc",
@@ -17,18 +21,22 @@
   deps = [
     "//base",
     "//base:i18n",
+  ]
+  public_deps = [
+    "//dbus",
     "//skia",
     "//ui/base",
     "//ui/gfx",
   ]
-  public_deps = [
-    "//dbus",
-  ]
+  if (use_x11) {
+    configs += [ "//build/config/linux:x11" ]
+  }
 }
 
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "menu_property_list_unittest.cc",
     "success_barrier_callback_unittest.cc",
     "types_unittest.cc",
   ]
diff --git a/components/dbus/menu/DEPS b/components/dbus/menu/DEPS
index 153f3f4..0d3f0e9 100644
--- a/components/dbus/menu/DEPS
+++ b/components/dbus/menu/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
   "+dbus",
   "+ui/base",
+  "+ui/events/keycodes",
+  "+ui/gfx/image",
 ]
diff --git a/components/dbus/menu/menu.cc b/components/dbus/menu/menu.cc
index 5d40909..b02b807 100644
--- a/components/dbus/menu/menu.cc
+++ b/components/dbus/menu/menu.cc
@@ -6,6 +6,7 @@
 
 #include <limits>
 #include <memory>
+#include <set>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -17,7 +18,6 @@
 #include "components/dbus/menu/properties_interface.h"
 #include "components/dbus/menu/success_barrier_callback.h"
 #include "ui/base/accelerators/accelerator.h"
-#include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
 #include "ui/base/models/menu_model.h"
 #include "ui/base/models/simple_menu_model.h"
 
@@ -46,6 +46,7 @@
 uint32_t kPropertyValueVersion = 3;
 
 // Signals.
+const char kSignalItemsPropertiesUpdated[] = "ItemsPropertiesUpdated";
 const char kSignalLayoutUpdated[] = "LayoutUpdated";
 
 // Creates a variant with the default value for |property_name|, or an empty
@@ -78,6 +79,20 @@
   return DbusString(base::i18n::IsRTL() ? "rtl " : "ltr");
 }
 
+void WriteRemovedProperties(dbus::MessageWriter* writer,
+                            const MenuPropertyChanges& removed_props) {
+  dbus::MessageWriter removed_props_writer(nullptr);
+  writer->OpenArray("(ias)", &removed_props_writer);
+  for (const auto& pair : removed_props) {
+    dbus::MessageWriter struct_writer(nullptr);
+    removed_props_writer.OpenStruct(&struct_writer);
+    struct_writer.AppendInt32(pair.first);
+    struct_writer.AppendArrayOfStrings(pair.second);
+    removed_props_writer.CloseContainer(&struct_writer);
+  }
+  writer->CloseContainer(&removed_props_writer);
+}
+
 }  // namespace
 
 DbusMenu::MenuItem::MenuItem(int32_t id,
@@ -165,24 +180,66 @@
 void DbusMenu::SetModel(ui::MenuModel* model, bool send_signal) {
   items_.clear();
 
+  std::map<std::string, DbusVariant> properties;
+  std::vector<int32_t> children;
   if (model) {
-    std::map<std::string, DbusVariant> properties;
     properties["children-display"] = MakeDbusVariant(DbusString("submenu"));
-    items_[0] = std::make_unique<MenuItem>(
-        0, std::move(properties), ConvertMenu(model), nullptr, nullptr, -1);
-  } else {
-    items_[0] = std::make_unique<MenuItem>(
-        0, std::map<std::string, DbusVariant>(), std::vector<int32_t>(),
-        nullptr, nullptr, -1);
+    children = ConvertMenu(model);
+  }
+  items_[0] = std::make_unique<MenuItem>(
+      0, std::move(properties), std::move(children), nullptr, nullptr, -1);
+
+  if (send_signal)
+    SendLayoutChangedSignal(0);
+}
+
+void DbusMenu::MenuLayoutUpdated(ui::MenuModel* model) {
+  MenuItem* item = FindMenuItemForModel(model, items_[0].get());
+  DCHECK(item);
+  DeleteItemChildren(item);
+  item->children = ConvertMenu(model);
+  SendLayoutChangedSignal(item->id);
+}
+
+void DbusMenu::MenuItemsPropertiesUpdated(
+    const std::vector<MenuItemReference>& menu_items) {
+  if (menu_items.empty())
+    return;
+
+  MenuPropertyChanges updated_props;
+  MenuPropertyChanges removed_props;
+  for (const auto& menu_item : menu_items) {
+    ui::MenuModel* menu = menu_item.first;
+    int index = menu_item.second;
+    MenuItem* parent = FindMenuItemForModel(menu, items_[0].get());
+    MenuItem* item = nullptr;
+    for (int32_t id : parent->children) {
+      MenuItem* child = items_[id].get();
+      DCHECK_EQ(child->containing_menu, menu);
+      if (child->containing_menu_index == index) {
+        item = child;
+        break;
+      }
+    }
+    DCHECK(item);
+
+    auto old_properties = std::move(item->properties);
+    item->properties = ComputeMenuPropertiesForMenuItem(menu, index);
+    MenuPropertyList item_updated_props;
+    MenuPropertyList item_removed_props;
+    ComputeMenuPropertyChanges(old_properties, item->properties,
+                               &item_updated_props, &item_removed_props);
+    if (!item_updated_props.empty())
+      updated_props[item->id] = std::move(item_updated_props);
+    if (!item_removed_props.empty())
+      removed_props[item->id] = std::move(item_removed_props);
   }
 
-  if (send_signal) {
-    dbus::Signal signal(kInterfaceDbusMenu, kSignalLayoutUpdated);
-    dbus::MessageWriter writer(&signal);
-    writer.AppendUint32(++revision_);  // Revision of the new layout.
-    writer.AppendInt32(0);             // Parent item whose layout changed.
-    menu_->SendSignal(&signal);
-  }
+  dbus::Signal signal(kInterfaceDbusMenu, kSignalItemsPropertiesUpdated);
+  dbus::MessageWriter writer(&signal);
+  WriteUpdatedProperties(&writer, updated_props);
+  WriteRemovedProperties(&writer, removed_props);
+  menu_->SendSignal(&signal);
 }
 
 // static
@@ -270,12 +327,12 @@
   dbus::MessageReader id_reader(nullptr);
   if (!response->reader().PopArray(&id_reader))
     return;
-  std::set<int32_t> ids;
+  std::vector<int32_t> ids;
   while (id_reader.HasMoreData()) {
     int32_t id;
     if (!id_reader.PopInt32(&id))
       return;
-    ids.insert(id);
+    ids.push_back(id);
   }
 
   std::set<std::string> property_filter;
@@ -292,15 +349,14 @@
   dbus::MessageWriter& writer = response->Writer();
   dbus::MessageWriter item_writer(nullptr);
   writer.OpenArray("(ia{sv})", &item_writer);
-  for (const auto& item_pair : items_) {
-    if (!ids.empty() && !base::Contains(ids, item_pair.first))
-      continue;
+
+  auto write_item = [&](int32_t id, const MenuItem& item) {
     dbus::MessageWriter struct_writer(nullptr);
     item_writer.OpenStruct(&struct_writer);
-    struct_writer.AppendInt32(item_pair.first);
+    struct_writer.AppendInt32(id);
     dbus::MessageWriter property_writer(nullptr);
     struct_writer.OpenArray("{sv}", &property_writer);
-    for (const auto& property_pair : item_pair.second->properties) {
+    for (const auto& property_pair : item.properties) {
       if (!property_filter.empty() &&
           !base::Contains(property_filter, property_pair.first)) {
         continue;
@@ -313,7 +369,19 @@
     }
     struct_writer.CloseContainer(&property_writer);
     item_writer.CloseContainer(&struct_writer);
+  };
+
+  if (ids.empty()) {
+    for (const auto& item_pair : items_)
+      write_item(item_pair.first, *item_pair.second);
+  } else {
+    for (int32_t id : ids) {
+      auto it = items_.find(id);
+      if (it != items_.end())
+        write_item(id, *it->second);
+    }
   }
+
   writer.CloseContainer(&item_writer);
 }
 
@@ -321,7 +389,7 @@
   dbus::MessageReader& reader = response->reader();
   int32_t id;
   int32_t depth;
-  std::vector<std::string> property_filter;
+  MenuPropertyList property_filter;
   if (!reader.PopInt32(&id) || !reader.PopInt32(&depth) || depth < -1 ||
       !reader.PopArrayOfStrings(&property_filter)) {
     return;
@@ -393,7 +461,8 @@
       return false;
     item->containing_menu->ActivatedAt(item->containing_menu_index);
   } else {
-    DCHECK_EQ("hovered", type);
+    DCHECK(type == "hovered" || type == "opened" || type == "closed")
+        << "Unexpected type: " << type;
     // Nothing to do.
   }
 
@@ -407,84 +476,13 @@
   items.reserve(menu->GetItemCount());
 
   for (int i = 0; i < menu->GetItemCount(); ++i) {
-    // Properties should only be set if they differ from the default values.
-    std::map<std::string, DbusVariant> properties;
-
-    // The dbusmenu interface has no concept of a "sublabel", "minor text", or
-    // "minor icon" like MenuModel has.  Ignore these rather than trying to
-    // merge them with the regular label and icon.
-    base::string16 label = menu->GetLabelAt(i);
-    if (!label.empty()) {
-      properties["label"] = MakeDbusVariant(DbusString(
-          ui::ConvertAcceleratorsFromWindowsStyle(base::UTF16ToUTF8(label))));
-    }
-
-    if (!menu->IsEnabledAt(i))
-      properties["enabled"] = MakeDbusVariant(DbusBoolean(false));
-    if (!menu->IsVisibleAt(i))
-      properties["visible"] = MakeDbusVariant(DbusBoolean(false));
-
-    gfx::Image icon;
-    if (menu->GetIconAt(i, &icon)) {
-      properties["icon-data"] =
-          MakeDbusVariant(DbusByteArray(icon.As1xPNGBytes()));
-    }
-
-    ui::Accelerator accelerator;
-    if (menu->GetAcceleratorAt(i, &accelerator)) {
-      std::vector<DbusString> parts;
-      if (accelerator.IsCtrlDown())
-        parts.push_back(DbusString("Control"));
-      if (accelerator.IsAltDown())
-        parts.push_back(DbusString("Alt"));
-      if (accelerator.IsShiftDown())
-        parts.push_back(DbusString("Shift"));
-      if (accelerator.IsCmdDown())
-        parts.push_back(DbusString("Super"));
-      parts.push_back(
-          DbusString(base::UTF16ToUTF8(accelerator.KeyCodeToName())));
-      properties["shortcut"] = MakeDbusVariant(
-          MakeDbusArray(DbusArray<DbusString>(std::move(parts))));
-    }
-
-    switch (menu->GetTypeAt(i)) {
-      case ui::MenuModel::TYPE_COMMAND:
-      case ui::MenuModel::TYPE_HIGHLIGHTED:
-        // Nothing special to do.
-        break;
-      case ui::MenuModel::TYPE_CHECK:
-      case ui::MenuModel::TYPE_RADIO:
-        properties["toggle-type"] = MakeDbusVariant(DbusString(
-            menu->GetTypeAt(i) == ui::MenuModel::TYPE_CHECK ? "checkmark"
-                                                            : "radio"));
-        properties["toggle-state"] =
-            MakeDbusVariant(DbusInt32(menu->IsItemCheckedAt(i) ? 1 : 0));
-        break;
-      case ui::MenuModel::TYPE_SEPARATOR:
-        // The dbusmenu interface doesn't have multiple types of separators like
-        // MenuModel.  Just use a regular separator in all cases.
-        properties["type"] = MakeDbusVariant(DbusString("separator"));
-        break;
-      case ui::MenuModel::TYPE_BUTTON_ITEM:
-        // This type of menu represents a row of buttons, but the dbusmenu
-        // interface has no equivalent of this.  Ignore these items for now
-        // since there's currently no uses of it that plumb into this codepath.
-        // If there are button menu items in the future, we'd have to fake them
-        // with multiple menu items.
-        NOTIMPLEMENTED();
-        continue;
-      case ui::MenuModel::TYPE_SUBMENU:
-      case ui::MenuModel::TYPE_ACTIONABLE_SUBMENU:
-        properties["children-display"] = MakeDbusVariant(DbusString("submenu"));
-        break;
-    }
-
     ui::MenuModel* submenu = menu->GetSubmenuModelAt(i);
     std::vector<int32_t> children = ConvertMenu(submenu);
 
     int32_t id = NextItemId();
     items_[id] = std::make_unique<MenuItem>(
-        id, std::move(properties), std::move(children), submenu, menu, i);
+        id, ComputeMenuPropertiesForMenuItem(menu, i), std::move(children),
+        submenu, menu, i);
     items.push_back(id);
   }
 
@@ -500,7 +498,7 @@
 void DbusMenu::WriteMenuItem(const MenuItem* item,
                              dbus::MessageWriter* writer,
                              int32_t depth,
-                             const std::vector<std::string>& property_filter) {
+                             const MenuPropertyList& property_filter) const {
   dbus::MessageWriter struct_writer(nullptr);
   writer->OpenStruct(&struct_writer);
   struct_writer.AppendInt32(item->id);
@@ -525,7 +523,7 @@
     for (int32_t child : item->children) {
       dbus::MessageWriter variant_writer(nullptr);
       children_writer.OpenVariant("(ia{sv}av)", &variant_writer);
-      WriteMenuItem(items_[child].get(), &variant_writer,
+      WriteMenuItem(items_.find(child)->second.get(), &variant_writer,
                     depth == -1 ? -1 : depth - 1, property_filter);
       children_writer.CloseContainer(&variant_writer);
     }
@@ -534,3 +532,60 @@
 
   writer->CloseContainer(&struct_writer);
 }
+
+void DbusMenu::WriteUpdatedProperties(
+    dbus::MessageWriter* writer,
+    const MenuPropertyChanges& updated_props) const {
+  dbus::MessageWriter updated_props_writer(nullptr);
+  writer->OpenArray("(ia{sv})", &updated_props_writer);
+  for (const auto& pair : updated_props) {
+    int32_t id = pair.first;
+    MenuItem* item = items_.find(id)->second.get();
+    dbus::MessageWriter struct_writer(nullptr);
+    updated_props_writer.OpenStruct(&struct_writer);
+    struct_writer.AppendInt32(id);
+    dbus::MessageWriter array_writer(nullptr);
+    struct_writer.OpenArray("{sv}", &array_writer);
+    for (const std::string& key : pair.second) {
+      dbus::MessageWriter dict_entry_writer(nullptr);
+      array_writer.OpenDictEntry(&dict_entry_writer);
+      dict_entry_writer.AppendString(key);
+      item->properties[key].Write(&dict_entry_writer);
+      array_writer.CloseContainer(&dict_entry_writer);
+    }
+    struct_writer.CloseContainer(&array_writer);
+    updated_props_writer.CloseContainer(&struct_writer);
+  }
+  writer->CloseContainer(&updated_props_writer);
+}
+
+DbusMenu::MenuItem* DbusMenu::FindMenuItemForModel(const ui::MenuModel* model,
+                                                   MenuItem* item) const {
+  if (item->menu == model)
+    return item;
+  for (int32_t id : item->children) {
+    MenuItem* child = items_.find(id)->second.get();
+    MenuItem* found = FindMenuItemForModel(model, child);
+    if (found)
+      return found;
+  }
+  return nullptr;
+}
+
+void DbusMenu::DeleteItem(MenuItem* item) {
+  DeleteItemChildren(item);
+  items_.erase(item->id);
+}
+
+void DbusMenu::DeleteItemChildren(MenuItem* item) {
+  for (int32_t id : item->children)
+    DeleteItem(items_.find(id)->second.get());
+}
+
+void DbusMenu::SendLayoutChangedSignal(int32_t id) {
+  dbus::Signal signal(kInterfaceDbusMenu, kSignalLayoutUpdated);
+  dbus::MessageWriter writer(&signal);
+  writer.AppendUint32(++revision_);  // Revision of the new layout.
+  writer.AppendInt32(id);            // Parent item whose layout changed.
+  menu_->SendSignal(&signal);
+}
diff --git a/components/dbus/menu/menu.h b/components/dbus/menu/menu.h
index 5198c80..e6f702a 100644
--- a/components/dbus/menu/menu.h
+++ b/components/dbus/menu/menu.h
@@ -7,12 +7,15 @@
 
 #include <map>
 #include <memory>
+#include <string>
+#include <utility>
 #include <vector>
 
 #include "base/callback_forward.h"
 #include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/dbus/menu/menu_property_list.h"
 #include "components/dbus/menu/types.h"
 #include "dbus/bus.h"
 #include "dbus/exported_object.h"
@@ -28,19 +31,30 @@
 class COMPONENT_EXPORT(DBUS) DbusMenu {
  public:
   using InitializedCallback = base::OnceCallback<void(bool success)>;
+  using MenuItemReference = std::pair<ui::MenuModel*, int>;
 
   // The exported DBus object will not be unregistered upon deletion.  It is the
   // responsibility of the caller to remove it after |this| is deleted.
   DbusMenu(dbus::ExportedObject* exported_object, InitializedCallback callback);
   ~DbusMenu();
 
+  // Should be called when there's a new root menu.
   void SetModel(ui::MenuModel* model, bool send_signal);
 
+  // Should be called when items are added/removed/reordered in a menu.  Prefer
+  // this over SetModel().
+  void MenuLayoutUpdated(ui::MenuModel* model);
+
+  // Should be called when properties on (a group of) menu items change.  Prefer
+  // this over SetModel().
+  void MenuItemsPropertiesUpdated(
+      const std::vector<MenuItemReference>& menu_items);
+
  private:
   struct MenuItem {
    public:
     MenuItem(int32_t id,
-             std::map<std::string, DbusVariant>&& properties,
+             MenuItemProperties&& properties,
              std::vector<int32_t>&& children,
              ui::MenuModel* menu,
              ui::MenuModel* containing_menu,
@@ -48,8 +62,8 @@
     ~MenuItem();
 
     const int32_t id;
-    const std::map<std::string, DbusVariant> properties;
-    const std::vector<int32_t> children;
+    MenuItemProperties properties;
+    std::vector<int32_t> children;
 
     // The MenuModel corresponding to this MenuItem, or null if this MenuItem is
     // not a submenu.  This can happen for leaf items or an empty root item.
@@ -119,7 +133,20 @@
   void WriteMenuItem(const MenuItem* item,
                      dbus::MessageWriter* writer,
                      int32_t depth,
-                     const std::vector<std::string>& property_filter);
+                     const MenuPropertyList& property_filter) const;
+
+  void WriteUpdatedProperties(dbus::MessageWriter* writer,
+                              const MenuPropertyChanges& updated_props) const;
+
+  // Recursively searches |item| and its descendants for the MenuItem
+  // corresponding to |model|.
+  MenuItem* FindMenuItemForModel(const ui::MenuModel* model,
+                                 MenuItem* item) const;
+
+  void DeleteItem(MenuItem* item);
+  void DeleteItemChildren(MenuItem* item);
+
+  void SendLayoutChangedSignal(int32_t id);
 
   dbus::ExportedObject* menu_ = nullptr;
 
diff --git a/components/dbus/menu/menu_property_list.cc b/components/dbus/menu/menu_property_list.cc
new file mode 100644
index 0000000..acbc74fc
--- /dev/null
+++ b/components/dbus/menu/menu_property_list.cc
@@ -0,0 +1,123 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/dbus/menu/menu_property_list.h"
+
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
+#include "ui/base/models/menu_model.h"
+#include "ui/gfx/image/image.h"
+
+#if defined(USE_X11)
+#include <X11/Xlib.h>
+
+#include "ui/events/keycodes/keyboard_code_conversion_x.h"  // nogncheck
+#endif
+
+MenuItemProperties ComputeMenuPropertiesForMenuItem(ui::MenuModel* menu,
+                                                    int i) {
+  // Properties should only be set if they differ from the default values.
+  MenuItemProperties properties;
+
+  // The dbusmenu interface has no concept of a "sublabel", "minor text", or
+  // "minor icon" like MenuModel has.  Ignore these rather than trying to
+  // merge them with the regular label and icon.
+  base::string16 label = menu->GetLabelAt(i);
+  if (!label.empty()) {
+    properties["label"] = MakeDbusVariant(DbusString(
+        ui::ConvertAcceleratorsFromWindowsStyle(base::UTF16ToUTF8(label))));
+  }
+
+  if (!menu->IsEnabledAt(i))
+    properties["enabled"] = MakeDbusVariant(DbusBoolean(false));
+  if (!menu->IsVisibleAt(i))
+    properties["visible"] = MakeDbusVariant(DbusBoolean(false));
+
+  gfx::Image icon;
+  if (menu->GetIconAt(i, &icon)) {
+    properties["icon-data"] =
+        MakeDbusVariant(DbusByteArray(icon.As1xPNGBytes()));
+  }
+
+  ui::Accelerator accelerator;
+  if (menu->GetAcceleratorAt(i, &accelerator)) {
+    std::vector<DbusString> parts;
+    if (accelerator.IsCtrlDown())
+      parts.push_back(DbusString("Control"));
+    if (accelerator.IsAltDown())
+      parts.push_back(DbusString("Alt"));
+    if (accelerator.IsShiftDown())
+      parts.push_back(DbusString("Shift"));
+    if (accelerator.IsCmdDown())
+      parts.push_back(DbusString("Super"));
+#if defined(USE_X11)
+    parts.push_back(DbusString(XKeysymToString(
+        XKeysymForWindowsKeyCode(accelerator.key_code(), false))));
+    properties["shortcut"] =
+        MakeDbusVariant(MakeDbusArray(DbusArray<DbusString>(std::move(parts))));
+#else
+    NOTIMPLEMENTED();
+#endif
+  }
+
+  switch (menu->GetTypeAt(i)) {
+    case ui::MenuModel::TYPE_COMMAND:
+    case ui::MenuModel::TYPE_HIGHLIGHTED:
+      // Nothing special to do.
+      break;
+    case ui::MenuModel::TYPE_CHECK:
+    case ui::MenuModel::TYPE_RADIO:
+      properties["toggle-type"] = MakeDbusVariant(DbusString(
+          menu->GetTypeAt(i) == ui::MenuModel::TYPE_CHECK ? "checkmark"
+                                                          : "radio"));
+      properties["toggle-state"] =
+          MakeDbusVariant(DbusInt32(menu->IsItemCheckedAt(i) ? 1 : 0));
+      break;
+    case ui::MenuModel::TYPE_SEPARATOR:
+      // The dbusmenu interface doesn't have multiple types of separators like
+      // MenuModel.  Just use a regular separator in all cases.
+      properties["type"] = MakeDbusVariant(DbusString("separator"));
+      break;
+    case ui::MenuModel::TYPE_BUTTON_ITEM:
+      // This type of menu represents a row of buttons, but the dbusmenu
+      // interface has no equivalent of this.  Ignore these items for now
+      // since there's currently no uses of it that plumb into this codepath.
+      // If there are button menu items in the future, we'd have to fake them
+      // with multiple menu items.
+      NOTIMPLEMENTED();
+      break;
+    case ui::MenuModel::TYPE_SUBMENU:
+    case ui::MenuModel::TYPE_ACTIONABLE_SUBMENU:
+      properties["children-display"] = MakeDbusVariant(DbusString("submenu"));
+      break;
+  }
+
+  return properties;
+}
+
+void ComputeMenuPropertyChanges(const MenuItemProperties& old_properties,
+                                const MenuItemProperties& new_properties,
+                                MenuPropertyList* item_updated_props,
+                                MenuPropertyList* item_removed_props) {
+  // Compute updated and removed properties.
+  for (const auto& pair : old_properties) {
+    const std::string& key = pair.first;
+    auto new_it = new_properties.find(key);
+    if (new_it != new_properties.end()) {
+      if (new_it->second != pair.second)
+        item_updated_props->push_back(key);
+    } else {
+      item_removed_props->push_back(key);
+    }
+  }
+  // Compute added properties.
+  for (const auto& pair : new_properties) {
+    const std::string& key = pair.first;
+    if (!base::Contains(old_properties, key))
+      item_updated_props->push_back(key);
+  }
+}
diff --git a/components/dbus/menu/menu_property_list.h b/components/dbus/menu/menu_property_list.h
new file mode 100644
index 0000000..93fd377
--- /dev/null
+++ b/components/dbus/menu/menu_property_list.h
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DBUS_MENU_MENU_PROPERTY_LIST_H_
+#define COMPONENTS_DBUS_MENU_MENU_PROPERTY_LIST_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "components/dbus/menu/types.h"
+
+using MenuPropertyList = std::vector<std::string>;
+using MenuItemProperties = std::map<std::string, DbusVariant>;
+using MenuPropertyChanges = std::map<int32_t, MenuPropertyList>;
+
+namespace ui {
+class MenuModel;
+}
+
+// Computes properties for the menu item with index |i| in |menu|.
+COMPONENT_EXPORT(DBUS)
+MenuItemProperties ComputeMenuPropertiesForMenuItem(ui::MenuModel* menu, int i);
+
+// Given inputs |old_properties| and |new_properties|, computes outputs
+// |item_updated_props| and |item_removed_props| suitable for use in
+// com.canonical.dbusmenu.ItemsPropertiesUpdated.
+COMPONENT_EXPORT(DBUS)
+void ComputeMenuPropertyChanges(const MenuItemProperties& old_properties,
+                                const MenuItemProperties& new_properties,
+                                MenuPropertyList* item_updated_props,
+                                MenuPropertyList* item_removed_props);
+
+#endif  // COMPONENTS_DBUS_MENU_MENU_PROPERTY_LIST_H_
diff --git a/components/dbus/menu/menu_property_list_unittest.cc b/components/dbus/menu/menu_property_list_unittest.cc
new file mode 100644
index 0000000..f700bf6
--- /dev/null
+++ b/components/dbus/menu/menu_property_list_unittest.cc
@@ -0,0 +1,361 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/dbus/menu/menu_property_list.h"
+
+#include <memory>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/dbus/menu/types.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/models/menu_model.h"
+#include "ui/base/models/menu_separator_types.h"
+#include "ui/base/models/simple_menu_model.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep_default.h"
+
+namespace {
+
+class TestMenuModel : public ui::SimpleMenuModel,
+                      public ui::SimpleMenuModel::Delegate {
+ public:
+  TestMenuModel(bool checked,
+                bool enabled,
+                bool visible,
+                const base::string16& label,
+                const gfx::Image& icon,
+                const ui::Accelerator& accelerator)
+      : ui::SimpleMenuModel(this),
+        checked_(checked),
+        enabled_(enabled),
+        visible_(visible),
+        label_(label),
+        icon_(icon),
+        accelerator_(accelerator) {}
+  ~TestMenuModel() override = default;
+
+  MenuItemProperties ComputeProperties() {
+    return ComputeMenuPropertiesForMenuItem(this, 0);
+  }
+
+ protected:
+  // ui::MenuModel::
+  bool IsItemDynamicAt(int index) const override {
+    EXPECT_LE(index, 0);
+    // Return true so that GetIconForCommandId() will always be called.
+    return true;
+  }
+
+  // ui::SimpleMenuModel::Delegate:
+  bool IsCommandIdChecked(int command_id) const override {
+    EXPECT_LE(command_id, 0);
+    return checked_;
+  }
+  bool IsCommandIdEnabled(int command_id) const override {
+    EXPECT_LE(command_id, 0);
+    return enabled_;
+  }
+  bool IsCommandIdVisible(int command_id) const override {
+    EXPECT_LE(command_id, 0);
+    return visible_;
+  }
+  base::string16 GetLabelForCommandId(int command_id) const override {
+    EXPECT_LE(command_id, 0);
+    return label_;
+  }
+  bool GetIconForCommandId(int command_id, gfx::Image* icon) const override {
+    EXPECT_LE(command_id, 0);
+    if (icon_.IsEmpty())
+      return false;
+    *icon = icon_;
+    return true;
+  }
+  void ExecuteCommand(int command_id, int event_flags) override {
+    EXPECT_LE(command_id, 0);
+  }
+  bool GetAcceleratorForCommandId(int command_id,
+                                  ui::Accelerator* accelerator) const override {
+    EXPECT_LE(command_id, 0);
+    if (accelerator_ == ui::Accelerator())
+      return false;
+    *accelerator = accelerator_;
+    return true;
+  }
+
+ private:
+  const bool checked_;
+  const bool enabled_;
+  const bool visible_;
+  const base::string16 label_;
+  const gfx::Image icon_;
+  const ui::Accelerator accelerator_;
+};
+
+class TestMenuModelBuilder {
+ public:
+  TestMenuModelBuilder() = default;
+  ~TestMenuModelBuilder() = default;
+
+  TestMenuModelBuilder SetType(ui::MenuModel::ItemType type) const {
+    TestMenuModelBuilder builder = *this;
+    builder.type_ = type;
+    return builder;
+  }
+
+  TestMenuModelBuilder SetChecked(bool checked) const {
+    TestMenuModelBuilder builder = *this;
+    builder.checked_ = checked;
+    return builder;
+  }
+
+  TestMenuModelBuilder SetEnabled(bool enabled) const {
+    TestMenuModelBuilder builder = *this;
+    builder.enabled_ = enabled;
+    return builder;
+  }
+
+  TestMenuModelBuilder SetVisible(bool visible) const {
+    TestMenuModelBuilder builder = *this;
+    builder.visible_ = visible;
+    return builder;
+  }
+
+  TestMenuModelBuilder SetLabel(const std::string& label) const {
+    TestMenuModelBuilder builder = *this;
+    builder.label_ = base::ASCIIToUTF16(label);
+    return builder;
+  }
+
+  TestMenuModelBuilder SetIcon(const gfx::Image& icon) const {
+    TestMenuModelBuilder builder = *this;
+    builder.icon_ = icon;
+    return builder;
+  }
+
+  TestMenuModelBuilder SetAccelerator(
+      const ui::Accelerator& accelerator) const {
+    TestMenuModelBuilder builder = *this;
+    builder.accelerator_ = accelerator;
+    return builder;
+  }
+
+  std::unique_ptr<TestMenuModel> Build() const {
+    auto menu = std::make_unique<TestMenuModel>(checked_, enabled_, visible_,
+                                                label_, icon_, accelerator_);
+    switch (type_) {
+      case ui::MenuModel::TYPE_COMMAND:
+        menu->AddItem(0, label_);
+        break;
+      case ui::MenuModel::TYPE_CHECK:
+        menu->AddCheckItem(0, label_);
+        break;
+      case ui::MenuModel::TYPE_RADIO:
+        menu->AddRadioItem(0, label_, 0);
+        break;
+      case ui::MenuModel::TYPE_SEPARATOR:
+        menu->AddSeparator(ui::MenuSeparatorType::SPACING_SEPARATOR);
+        break;
+      case ui::MenuModel::TYPE_BUTTON_ITEM:
+        NOTIMPLEMENTED();
+        break;
+      case ui::MenuModel::TYPE_SUBMENU:
+        menu->AddSubMenu(0, label_, nullptr);
+        break;
+      case ui::MenuModel::TYPE_ACTIONABLE_SUBMENU:
+        menu->AddActionableSubMenu(0, label_, nullptr);
+        break;
+      case ui::MenuModel::TYPE_HIGHLIGHTED:
+        menu->AddHighlightedItemWithIcon(0, label_, icon_.AsImageSkia());
+        break;
+    }
+    return menu;
+  }
+
+ private:
+  ui::MenuModel::ItemType type_ = ui::MenuModel::TYPE_COMMAND;
+  bool checked_ = false;
+  bool enabled_ = true;
+  bool visible_ = true;
+  base::string16 label_;
+  gfx::Image icon_;
+  ui::Accelerator accelerator_;
+};
+
+}  // namespace
+
+TEST(MenuPropertyListTest, ComputePropertiesBasic) {
+  auto builder = TestMenuModelBuilder();
+  auto menu = builder.Build();
+  MenuItemProperties props;
+  EXPECT_EQ(menu->ComputeProperties(), props);
+
+  // Same for TYPE_HIGHLIGHTED.
+  menu = builder.SetType(ui::MenuModel::TYPE_HIGHLIGHTED).Build();
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+
+TEST(MenuPropertyListTest, ComputePropertiesCheck) {
+  auto menu = TestMenuModelBuilder().SetType(ui::MenuModel::TYPE_CHECK).Build();
+  MenuItemProperties props;
+  props["toggle-type"] = MakeDbusVariant(DbusString("checkmark"));
+  props["toggle-state"] = MakeDbusVariant(DbusInt32(0));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+
+TEST(MenuPropertyListTest, ComputePropertiesRadio) {
+  auto menu = TestMenuModelBuilder().SetType(ui::MenuModel::TYPE_RADIO).Build();
+  MenuItemProperties props;
+  props["toggle-type"] = MakeDbusVariant(DbusString("radio"));
+  props["toggle-state"] = MakeDbusVariant(DbusInt32(0));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+
+TEST(MenuPropertyListTest, ComputePropertiesCheckedState) {
+  auto builder = TestMenuModelBuilder().SetChecked(true);
+
+  // Types other than radio and check should not have toggle-state set.
+  auto menu = builder.Build();
+  MenuItemProperties props;
+  EXPECT_EQ(menu->ComputeProperties(), props);
+
+  // Radio and check buttons should have the toggle-state set.
+  menu = builder.SetType(ui::MenuModel::TYPE_RADIO).Build();
+  props["toggle-type"] = MakeDbusVariant(DbusString("radio"));
+  props["toggle-state"] = MakeDbusVariant(DbusInt32(1));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+
+  menu = builder.SetType(ui::MenuModel::TYPE_CHECK).Build();
+  props["toggle-type"] = MakeDbusVariant(DbusString("checkmark"));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+
+TEST(MenuPropertyListTest, ComputePropertiesSeparator) {
+  auto menu =
+      TestMenuModelBuilder().SetType(ui::MenuModel::TYPE_SEPARATOR).Build();
+  MenuItemProperties props;
+  props["type"] = MakeDbusVariant(DbusString("separator"));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+
+TEST(MenuPropertyListTest, ComputePropertiesSubmenu) {
+  auto builder = TestMenuModelBuilder();
+  auto menu = builder.SetType(ui::MenuModel::TYPE_SUBMENU).Build();
+  MenuItemProperties props;
+  props["children-display"] = MakeDbusVariant(DbusString("submenu"));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+
+  // Same for ACTIONABLE_SUBMENU.
+  menu = builder.SetType(ui::MenuModel::TYPE_ACTIONABLE_SUBMENU).Build();
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+
+TEST(MenuPropertyListTest, ComputePropertiesEnabledState) {
+  auto builder = TestMenuModelBuilder();
+
+  // Enabled.
+  auto menu = builder.SetEnabled(true).Build();
+  MenuItemProperties props;
+  EXPECT_EQ(menu->ComputeProperties(), props);
+
+  // Disabled.
+  menu = builder.SetEnabled(false).Build();
+  props["enabled"] = MakeDbusVariant(DbusBoolean(false));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+
+TEST(MenuPropertyListTest, ComputePropertiesVisibleState) {
+  auto builder = TestMenuModelBuilder();
+
+  // Visible.
+  auto menu = builder.SetVisible(true).Build();
+  MenuItemProperties props;
+  EXPECT_EQ(menu->ComputeProperties(), props);
+
+  // Hidden.
+  menu = builder.SetVisible(false).Build();
+  props["visible"] = MakeDbusVariant(DbusBoolean(false));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+
+TEST(MenuPropertyListTest, ComputePropertiesLabel) {
+  auto builder = TestMenuModelBuilder();
+
+  // No label.
+  auto menu = builder.SetLabel("").Build();
+  MenuItemProperties props;
+  EXPECT_EQ(menu->ComputeProperties(), props);
+
+  // Non-empty label.
+  menu = builder.SetLabel("label value").Build();
+  props["label"] = MakeDbusVariant(DbusString("label value"));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+
+TEST(MenuPropertyListTest, ComputePropertiesIcon) {
+  auto builder = TestMenuModelBuilder();
+
+  // No icon.
+  auto menu = builder.SetIcon(gfx::Image()).Build();
+  MenuItemProperties props;
+  EXPECT_EQ(menu->ComputeProperties(), props);
+
+  // Non-empty label.
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(10, 10);
+  bitmap.eraseARGB(255, 123, 123, 123);
+  gfx::ImageSkia image_skia;
+  image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap, 1.0f));
+  gfx::Image icon(image_skia);
+  menu = builder.SetIcon(icon).Build();
+  props["icon-data"] = MakeDbusVariant(DbusByteArray(icon.As1xPNGBytes()));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+
+#if defined(USE_X11)
+TEST(MenuPropertyListTest, ComputePropertiesAccelerator) {
+  auto builder = TestMenuModelBuilder();
+
+  // No accelerator.
+  auto menu = builder.SetAccelerator(ui::Accelerator()).Build();
+  MenuItemProperties props;
+  EXPECT_EQ(menu->ComputeProperties(), props);
+
+  // Set a key.
+  menu = builder.SetAccelerator(ui::Accelerator(ui::VKEY_A, 0)).Build();
+  props["shortcut"] =
+      MakeDbusVariant(MakeDbusArray(MakeDbusArray(DbusString("a"))));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+
+  // Add modifiers.
+  menu = builder
+             .SetAccelerator(ui::Accelerator(
+                 ui::VKEY_A,
+                 ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN))
+             .Build();
+  props["shortcut"] = MakeDbusVariant(
+      MakeDbusArray(MakeDbusArray(DbusString("Control"), DbusString("Alt"),
+                                  DbusString("Shift"), DbusString("a"))));
+  EXPECT_EQ(menu->ComputeProperties(), props);
+}
+#endif
+
+TEST(MenuPropertyListTest, ComputePropertyChanges) {
+  MenuItemProperties old_props;
+  old_props["1"] = MakeDbusVariant(DbusInt32(1));  // Remains the same.
+  old_props["2"] = MakeDbusVariant(DbusInt32(2));  // Updates to -2.
+  old_props["3"] = MakeDbusVariant(DbusInt32(3));  // Removed.
+
+  MenuItemProperties new_props;
+  new_props["1"] = MakeDbusVariant(DbusInt32(1));
+  new_props["2"] = MakeDbusVariant(DbusInt32(-2));
+  new_props["4"] = MakeDbusVariant(DbusInt32(4));  // Added.
+
+  MenuPropertyList updated;
+  MenuPropertyList removed;
+  ComputeMenuPropertyChanges(old_props, new_props, &updated, &removed);
+  EXPECT_EQ(updated, (MenuPropertyList{"2", "4"}));
+  EXPECT_EQ(removed, (MenuPropertyList{"3"}));
+}
diff --git a/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc b/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
index 53de696..855ff791 100644
--- a/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
+++ b/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
@@ -236,7 +236,7 @@
 
 void DomDistillerViewerSource::StartDataRequest(
     const std::string& path,
-    const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const content::WebContents::Getter& wc_getter,
     const content::URLDataSource::GotDataCallback& callback) {
   content::WebContents* web_contents = wc_getter.Run();
   if (!web_contents)
diff --git a/components/dom_distiller/content/browser/dom_distiller_viewer_source.h b/components/dom_distiller/content/browser/dom_distiller_viewer_source.h
index 1a285dc5..1f984bb1 100644
--- a/components/dom_distiller/content/browser/dom_distiller_viewer_source.h
+++ b/components/dom_distiller/content/browser/dom_distiller_viewer_source.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "components/dom_distiller/content/browser/distiller_ui_handle.h"
 #include "content/public/browser/url_data_source.h"
+#include "content/public/browser/web_contents.h"
 
 namespace dom_distiller {
 
@@ -32,7 +33,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const content::WebContents::Getter& wc_getter,
       const content::URLDataSource::GotDataCallback& callback) override;
   std::string GetMimeType(const std::string& path) override;
   bool ShouldServiceRequest(const GURL& url,
diff --git a/components/gcm_driver/account_tracker.h b/components/gcm_driver/account_tracker.h
index 70ae1f6..e051e96 100644
--- a/components/gcm_driver/account_tracker.h
+++ b/components/gcm_driver/account_tracker.h
@@ -29,7 +29,7 @@
 namespace gcm {
 
 struct AccountIds {
-  std::string account_key;  // The account ID used by OAuth2TokenService.
+  std::string account_key;  // The account ID used by IdentityManager.
   std::string gaia;
   std::string email;
 };
diff --git a/components/gcm_driver/gcm_account_tracker.h b/components/gcm_driver/gcm_account_tracker.h
index 79df8202..a55e724 100644
--- a/components/gcm_driver/gcm_account_tracker.h
+++ b/components/gcm_driver/gcm_account_tracker.h
@@ -97,7 +97,7 @@
   friend class GCMAccountTrackerTest;
 
   // Maps account keys to account states. Keyed by account_ids as used by
-  // OAuth2TokenService.
+  // IdentityManager.
   typedef std::map<std::string, AccountInfo> AccountInfos;
 
   // AccountTracker::Observer overrides.
diff --git a/components/invalidation/impl/gcm_invalidation_bridge_unittest.cc b/components/invalidation/impl/gcm_invalidation_bridge_unittest.cc
index e8efe7a..cfb1d7e 100644
--- a/components/invalidation/impl/gcm_invalidation_bridge_unittest.cc
+++ b/components/invalidation/impl/gcm_invalidation_bridge_unittest.cc
@@ -115,8 +115,8 @@
 TEST_F(GCMInvalidationBridgeTest, RequestToken) {
   base::RunLoop run_loop;
 
-  // Make sure that call to RequestToken reaches OAuth2TokenService and gets
-  // back to callback.
+  // Make sure that call to RequestToken reaches the access token fetcher and
+  // gets back to callback.
   delegate_->RequestToken(
       base::Bind(&GCMInvalidationBridgeTest::RequestTokenFinished,
                  base::Unretained(this), run_loop.QuitClosure()));
diff --git a/components/navigation_interception/intercept_navigation_delegate.cc b/components/navigation_interception/intercept_navigation_delegate.cc
index b5f0536..47d802d 100644
--- a/components/navigation_interception/intercept_navigation_delegate.cc
+++ b/components/navigation_interception/intercept_navigation_delegate.cc
@@ -16,7 +16,6 @@
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
index 3c0c057..caf58487 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -100,9 +100,8 @@
     const std::string& name_space,
     const std::vector<PrefetchURL>& prefetch_urls) {
   if (!prefetch_prefs::IsEnabled(pref_service_)) {
-    if (prefetch_prefs::IsForbiddenCheckDue(pref_service_)) {
+    if (prefetch_prefs::IsForbiddenCheckDue(pref_service_))
       CheckIfEnabledByServer(pref_service_, service_);
-    }
     return;
   }
 
@@ -134,6 +133,14 @@
 
 void PrefetchDispatcherImpl::NewSuggestionsAvailable(
     SuggestionsProvider* suggestions_provider) {
+  // No need to GetKnownContent if prefetching is disabled (however, we don't
+  // want to prevent the server-forbidden check).
+  if (!prefetch_prefs::IsEnabled(pref_service_)) {
+    if (prefetch_prefs::IsForbiddenCheckDue(pref_service_))
+      CheckIfEnabledByServer(pref_service_, service_);
+    return;
+  }
+
   suggestions_provider->GetCurrentArticleSuggestions(
       base::BindOnce(&PrefetchDispatcherImpl::AddSuggestions, GetWeakPtr()));
 }
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 769763c..b329c04 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -226,6 +226,16 @@
 // static
 std::string OmniboxFieldTrial::GetZeroSuggestVariant(
     OmniboxEventProto::PageClassification page_classification) {
+  // Note: This code is required since at this point we have no way to set the
+  // ZeroSuggestVariant parameter state with Finch Forcing groups.
+  if (base::FeatureList::IsEnabled(omnibox::kZeroSuggestionsOnNTP)) {
+    auto result = internal::GetValueForRuleInContextByFeature(
+        omnibox::kZeroSuggestionsOnNTP, kZeroSuggestVariantRule,
+        page_classification);
+    if (!result.empty())
+      return result;
+  }
+
   return internal::GetValueForRuleInContextByFeature(
       omnibox::kOnFocusSuggestions, kZeroSuggestVariantRule,
       page_classification);
diff --git a/components/quirks/quirks_manager.cc b/components/quirks/quirks_manager.cc
index e013ce80..81a1344 100644
--- a/components/quirks/quirks_manager.cc
+++ b/components/quirks/quirks_manager.cc
@@ -93,6 +93,11 @@
 }
 
 // static
+bool QuirksManager::HasInstance() {
+  return !!manager_;
+}
+
+// static
 void QuirksManager::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterDictionaryPref(prefs::kQuirksClientLastServerCheck);
 }
diff --git a/components/quirks/quirks_manager.h b/components/quirks/quirks_manager.h
index 551888be..d96943f 100644
--- a/components/quirks/quirks_manager.h
+++ b/components/quirks/quirks_manager.h
@@ -72,6 +72,7 @@
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
   static void Shutdown();
   static QuirksManager* Get();
+  static bool HasInstance();
 
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
diff --git a/components/safe_browsing/db/v4_update_protocol_manager.cc b/components/safe_browsing/db/v4_update_protocol_manager.cc
index a1d45a69..84325c7 100644
--- a/components/safe_browsing/db/v4_update_protocol_manager.cc
+++ b/components/safe_browsing/db/v4_update_protocol_manager.cc
@@ -65,10 +65,6 @@
       safe_browsing::V4OperationResult::OPERATION_RESULT_MAX);
 }
 
-void RecordTimedOut(bool timed_out) {
-  UMA_HISTOGRAM_BOOLEAN("SafeBrowsing.V4Update.TimedOut", timed_out);
-}
-
 }  // namespace
 
 namespace safe_browsing {
@@ -391,7 +387,6 @@
 }
 
 void V4UpdateProtocolManager::HandleTimeout() {
-  RecordTimedOut(true);
   request_.reset();
   ScheduleNextUpdateWithBackoff(true);
 }
@@ -420,7 +415,6 @@
   last_response_code_ = response_code;
   V4ProtocolManagerUtil::RecordHttpResponseOrErrorCode(
       "SafeBrowsing.V4Update.Network.Result", net_error, last_response_code_);
-  RecordTimedOut(false);
 
   last_response_time_ = Time::Now();
 
diff --git a/components/security_interstitials/core/browser/resources/interstitial_large.html b/components/security_interstitials/core/browser/resources/interstitial_large.html
index 62ee7c46..1303bd2 100644
--- a/components/security_interstitials/core/browser/resources/interstitial_large.html
+++ b/components/security_interstitials/core/browser/resources/interstitial_large.html
@@ -53,6 +53,9 @@
         $i18n{openDetails}
       </button>
     </div>
+    <div id="subnav-wrapper" class="hidden">
+      <a href="#" id="details-link">$i18n{openDetails}</a>
+    </div>
     <div id="details" class="hidden">
       <p>$i18nRaw{explanationParagraph}</p>
       <p id="final-paragraph">$i18nRaw{finalParagraph}</p>
diff --git a/components/security_interstitials/core/browser/resources/interstitial_large.js b/components/security_interstitials/core/browser/resources/interstitial_large.js
index 26de41c..de331b7 100644
--- a/components/security_interstitials/core/browser/resources/interstitial_large.js
+++ b/components/security_interstitials/core/browser/resources/interstitial_large.js
@@ -134,7 +134,13 @@
 
   if (lookalike) {
     var proceed_button = 'proceed-button';
-    var dont_proceed_link = 'dont-proceed-link';
+    // Lookalike warnings use multiple "don't proceed" links. $() syntax only
+    // allows unique IDs (not classes), so we enumerate them all here.
+    var dont_proceed_links = [
+        'dont-proceed-link1',
+        'dont-proceed-link2',
+        'dont-proceed-link3',
+    ];
     $(proceed_button).classList.remove(HIDDEN_CLASS);
 
     $(proceed_button).textContent =
@@ -144,8 +150,10 @@
       sendCommand(SecurityInterstitialCommandId.CMD_PROCEED);
     });
 
-    $(dont_proceed_link).addEventListener('click', function(event) {
-      sendCommand(SecurityInterstitialCommandId.CMD_DONT_PROCEED);
+    dont_proceed_links.forEach(function(link_id) {
+      $(link_id).addEventListener('click', function(event) {
+        sendCommand(SecurityInterstitialCommandId.CMD_DONT_PROCEED);
+      });
     });
   }
 
@@ -163,7 +171,7 @@
       $(overrideElement).textContent =
           loadTimeData.getString('proceedButtonText');
     }
-  } else if (!ssl) {
+  } else if (!ssl && !lookalike) {
     $('final-paragraph').classList.add(HIDDEN_CLASS);
   }
 
@@ -186,11 +194,24 @@
     });
   }
 
-  if (captivePortal || billing || lookalike) {
-    // Captive portal, billing and lookalike pages don't have details button.
+  var details_id = null;
+  if (captivePortal || billing) {
+    // Captive portal and billing pages don't have details buttons.
     $('details-button').classList.add('hidden');
+  } else if (lookalike) {
+    // Lookalike pages has a details link instead.
+    if (loadTimeData.getBoolean('show_advanced')) {
+      $('subnav-wrapper').classList.remove('hidden');
+    }
+
+    $('details-button').classList.add('hidden');
+    details_id = 'details-link';
   } else {
-    $('details-button').addEventListener('click', function(event) {
+    details_id = 'details-button';
+  }
+
+  if (details_id) {
+    $(details_id).addEventListener('click', function(event) {
       var hiddenDetails = $('details').classList.toggle(HIDDEN_CLASS);
 
       if (mobileNav) {
@@ -200,7 +221,7 @@
         $('main-content').classList.remove(HIDDEN_CLASS);
       }
 
-      $('details-button').innerText = hiddenDetails ?
+      $(details_id).innerText = hiddenDetails ?
           loadTimeData.getString('openDetails') :
           loadTimeData.getString('closeDetails');
       if (!expandedDetails) {
diff --git a/components/security_interstitials/core/browser/resources/interstitial_lookalikeurl.css b/components/security_interstitials/core/browser/resources/interstitial_lookalikeurl.css
index 4dd765d..4ad8506a 100644
--- a/components/security_interstitials/core/browser/resources/interstitial_lookalikeurl.css
+++ b/components/security_interstitials/core/browser/resources/interstitial_lookalikeurl.css
@@ -2,7 +2,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
-.lookalike-url a {
+.lookalike-url #main-content a {
   color: var(--google-blue-700);
   text-decoration: none;
 }
@@ -18,3 +18,14 @@
     filter: invert(1);
   }
 }
+
+.lookalike-url #subnav-wrapper {
+  padding: 25px 0 0;
+  margin: 0;
+}
+
+.lookalike-url #details-link {
+  text-transform: uppercase;
+  text-decoration: none;
+  font-size: .875em;
+}
diff --git a/components/security_interstitials_strings.grdp b/components/security_interstitials_strings.grdp
index e9d9f0c0..ce7e2efa 100644
--- a/components/security_interstitials_strings.grdp
+++ b/components/security_interstitials_strings.grdp
@@ -65,21 +65,41 @@
   </message>
 
   <!-- Lookalike URL warning -->
-  <message name="IDS_LOOKALIKE_URL_TITLE" desc="Tab title. Context: the requested URL looks like a more popular URL.">
+  <message name="IDS_LOOKALIKE_URL_TITLE" desc="Tab title. Context: the requested URL might be trying to trick the user since it looks like a more popular URL.">
     Continue to <ph name="DOMAIN">$1<ex>example.com</ex></ph>?
   </message>
-  <message name="IDS_LOOKALIKE_URL_HEADING" desc="Large heading. Context: the error page that's shown when the requested URL looks like a more popular URL.">
-    Continue to &lt;a href="#" id="dont-proceed-link"&gt;<ph name="DOMAIN">$1<ex>example.com</ex></ph>&lt;/a&gt;?
+  <message name="IDS_LOOKALIKE_URL_HEADING" desc="Large heading. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL.">
+    Continue to &lt;a href="#" id="dont-proceed-link1"&gt;<ph name="DOMAIN">$1<ex>example.com</ex></ph>&lt;/a&gt;?
   </message>
-  <message name="IDS_LOOKALIKE_URL_IGNORE" desc="Button text. Context: the error page that's shown when the requested URL looks like a more popular URL. This button dismisses the interstitial and navigates to the originally-requested URL.">
+  <message name="IDS_LOOKALIKE_URL_IGNORE" desc="Button text. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL. This button dismisses the interstitial and navigates to the originally-requested URL.">
     Ignore
   </message>
-  <message name="IDS_LOOKALIKE_URL_CONTINUE" desc="Button text. Context: the error page that's shown when the requested URL looks like a more popular URL. This button dismisses the interstitial and navigates to the suggested (safe) URL.">
+  <message name="IDS_LOOKALIKE_URL_CONTINUE" desc="Button text. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL. This button dismisses the interstitial and navigates to the suggested (safe) URL.">
     Continue
   </message>
-  <message name="IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH" desc="Main paragraph of an error message. Context: the error page that's shown when the requested URL looks like a more popular URL.">
+  <message name="IDS_LOOKALIKE_URL_SHOW_DETAILS" desc="Button text. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL. This button expands the explanation to reveal additional details.">
+    Advanced
+  </message>
+  <message name="IDS_LOOKALIKE_URL_HIDE_DETAILS" desc="Button text. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL. This button hides additional details.">
+    Close advanced
+  </message>
+  <message name="IDS_LOOKALIKE_URL_FINAL_PARAGRAPH" desc="Final paragraph of an error message clarifying what the buttons do. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL.">
+    Clicking Continue will take you to the more common site &lt;a href="#" id="dont-proceed-link3"&gt;<ph name="DOMAIN">$1<ex>example.com</ex></ph>&lt;/a&gt;.
+  </message>
+
+  <message name="IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_ENGAGEMENT" desc="Main paragraph of an error message. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a different URL that the user usually visits.">
     The link you opened goes to a site you don't usually visit. It might be trying to confuse you.
   </message>
+  <message name="IDS_LOOKALIKE_URL_EXPLANATION_ENGAGEMENT" desc="Extended description for an error page hidden behind an 'Advanced' button. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a different URL that the user usually visits.">
+    You usually visit &lt;a href="#" id="dont-proceed-link2"&gt;<ph name="DOMAIN">$1<ex>example.com</ex></ph>&lt;/a&gt;. The URL you just tried to visit appears similar, but does not exactly match the site from your history. Attackers sometimes use this technique to trick or scam you.
+  </message>
+
+  <message name="IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_TOP" desc="Main paragraph of an error message. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL.">
+    The link you opened goes to an uncommon site. It might be trying to confuse you.
+  </message>
+  <message name="IDS_LOOKALIKE_URL_EXPLANATION_TOP" desc="Extended description for an error page hidden behind an 'Advanced' button. Context: the error page that's shown when the requested URL might be trying to trick the user since it looks like a more popular URL.">
+    You usually visit &lt;a href="#" id="dont-proceed-link2"&gt;<ph name="DOMAIN">$1<ex>example.com</ex></ph>&lt;/a&gt;. The site you just tried to visit appears similar to, but does not exactly match, the site from your history. Attackers sometimes use this technique to trick or scam you.
+  </message>
 
   <!-- Clock errors -->
   <message name="IDS_CLOCK_ERROR_TITLE" desc="Tab title. Context: the browser can't load a page because the device's clock is wrong.">
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_EXPLANATION_ENGAGEMENT.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_EXPLANATION_ENGAGEMENT.png.sha1
new file mode 100644
index 0000000..113df80
--- /dev/null
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_EXPLANATION_ENGAGEMENT.png.sha1
@@ -0,0 +1 @@
+ae736df383a1438c0d8a8731ec6f0886f6a70061
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_EXPLANATION_TOP.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_EXPLANATION_TOP.png.sha1
new file mode 100644
index 0000000..7067144
--- /dev/null
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_EXPLANATION_TOP.png.sha1
@@ -0,0 +1 @@
+ceaa8e7cb8069659b8893df6f00218c83fe517ed
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_FINAL_PARAGRAPH.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_FINAL_PARAGRAPH.png.sha1
new file mode 100644
index 0000000..7067144
--- /dev/null
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_FINAL_PARAGRAPH.png.sha1
@@ -0,0 +1 @@
+ceaa8e7cb8069659b8893df6f00218c83fe517ed
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_HIDE_DETAILS.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_HIDE_DETAILS.png.sha1
new file mode 100644
index 0000000..7067144
--- /dev/null
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_HIDE_DETAILS.png.sha1
@@ -0,0 +1 @@
+ceaa8e7cb8069659b8893df6f00218c83fe517ed
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH.png.sha1
deleted file mode 100644
index 55b5d17..0000000
--- a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-260a7f133f2a8fcec1743f8f2bb7538cc7a2fc50
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_ENGAGEMENT.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_ENGAGEMENT.png.sha1
new file mode 100644
index 0000000..113df80
--- /dev/null
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_ENGAGEMENT.png.sha1
@@ -0,0 +1 @@
+ae736df383a1438c0d8a8731ec6f0886f6a70061
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_TOP.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_TOP.png.sha1
new file mode 100644
index 0000000..7067144
--- /dev/null
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_PRIMARY_PARAGRAPH_TOP.png.sha1
@@ -0,0 +1 @@
+ceaa8e7cb8069659b8893df6f00218c83fe517ed
\ No newline at end of file
diff --git a/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_SHOW_DETAILS.png.sha1 b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_SHOW_DETAILS.png.sha1
new file mode 100644
index 0000000..d05953a
--- /dev/null
+++ b/components/security_interstitials_strings_grdp/IDS_LOOKALIKE_URL_SHOW_DETAILS.png.sha1
@@ -0,0 +1 @@
+08aa6eaf98a7ce2e4bb020d4dd4641e56ac8a58e
\ No newline at end of file
diff --git a/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc b/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc
index 701bbe89..bef96b8 100644
--- a/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc
+++ b/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc
@@ -154,9 +154,9 @@
     const CoreAccountId& account_id,
     const GoogleServiceAuthError& error) {
   backoff_entry_.InformOfRequest(!error.IsTransientError());
-  // Drop transient errors to match OAuth2TokenService's stated contract for
-  // GetAuthError() and to allow clients to test proper behavior in the case of
-  // transient errors.
+  // Drop transient errors to match ProfileOAuth2TokenService's stated contract
+  // for GetAuthError() and to allow clients to test proper behavior in the case
+  // of transient errors.
   if (error.IsTransientError())
     return;
 
diff --git a/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.h b/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.h
index 2d1eedc..b55902b 100644
--- a/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.h
+++ b/components/signin/internal/identity_manager/oauth2_token_service_delegate_android.h
@@ -68,8 +68,8 @@
                          const std::vector<CoreAccountId>& prev_ids,
                          const std::vector<CoreAccountId>& curr_ids);
 
-  // Overridden from OAuth2TokenService to complete signout of all
-  // OA2TService aware accounts.
+  // Overridden from ProfileOAuth2TokenService to complete signout of all
+  // POA2TService aware accounts.
   void RevokeAllCredentials() override;
 
   void LoadCredentials(const CoreAccountId& primary_account_id) override;
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
index 2fa03a5..60fe682d 100644
--- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
+++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
@@ -106,7 +106,7 @@
   if (it != errors_.end() && it->second.last_auth_error.IsPersistentError()) {
     VLOG(1) << "Request for token has been rejected due to persistent error #"
             << it->second.last_auth_error.state();
-    // |OAuth2TokenService| will manage the lifetime of this pointer.
+    // |ProfileOAuth2TokenService| will manage the lifetime of this pointer.
     return std::make_unique<OAuth2AccessTokenFetcherImmediateError>(
         consumer, it->second.last_auth_error);
   }
@@ -114,7 +114,7 @@
   if (backoff_entry_.ShouldRejectRequest()) {
     VLOG(1) << "Request for token has been rejected due to backoff rules from"
             << " previous error #" << backoff_error_.state();
-    // |OAuth2TokenService| will manage the lifetime of this pointer.
+    // |ProfileOAuth2TokenService| will manage the lifetime of this pointer.
     return std::make_unique<OAuth2AccessTokenFetcherImmediateError>(
         consumer, backoff_error_);
   }
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_observer.h b/components/signin/internal/identity_manager/profile_oauth2_token_service_observer.h
index f1c6263..b9cc2ce 100644
--- a/components/signin/internal/identity_manager/profile_oauth2_token_service_observer.h
+++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_observer.h
@@ -25,7 +25,7 @@
   // Called whenever the login-scoped refresh token becomes unavailable for
   // account |account_id|.
   virtual void OnRefreshTokenRevoked(const CoreAccountId& account_id) {}
-  // Called after all refresh tokens are loaded during OAuth2TokenService
+  // Called after all refresh tokens are loaded during ProfileOAuth2TokenService
   // startup.
   virtual void OnRefreshTokensLoaded() {}
   // Sent after a batch of refresh token changes is done.
diff --git a/components/signin/public/base/signin_pref_names.cc b/components/signin/public/base/signin_pref_names.cc
index d613924c..494ec235 100644
--- a/components/signin/public/base/signin_pref_names.cc
+++ b/components/signin/public/base/signin_pref_names.cc
@@ -101,7 +101,7 @@
 // True if the token service has been prepared for Dice migration.
 const char kTokenServiceDiceCompatible[] = "token_service.dice_compatible";
 
-// Boolean which stores if the OAuth2TokenService should ignore secondary
+// Boolean which stores if the ProfileOAuth2TokenService should ignore secondary
 // accounts.
 const char kTokenServiceExcludeAllSecondaryAccounts[] =
     "token_service.exclude_all_secondary_accounts";
diff --git a/components/sync/driver/profile_sync_service.h b/components/sync/driver/profile_sync_service.h
index 7491b7a0..8a0f5106 100644
--- a/components/sync/driver/profile_sync_service.h
+++ b/components/sync/driver/profile_sync_service.h
@@ -230,7 +230,7 @@
   // Used by MigrationWatcher.  May return null.
   BackendMigrator* GetBackendMigratorForTest();
 
-  // Used by tests to inspect interaction with OAuth2TokenService.
+  // Used by tests to inspect interaction with the access token fetcher.
   bool IsRetryingAccessTokenFetchForTest() const;
 
   // Used by tests to inspect the OAuth2 access tokens used by PSS.
diff --git a/components/url_formatter/spoof_checks/idn_spoof_checker.cc b/components/url_formatter/spoof_checks/idn_spoof_checker.cc
index a2b3e2d..36c90c9 100644
--- a/components/url_formatter/spoof_checks/idn_spoof_checker.cc
+++ b/components/url_formatter/spoof_checks/idn_spoof_checker.cc
@@ -217,6 +217,9 @@
   //   - {U+0A6B (੫)} => 4,
   //   - {U+09EA (৪), U+0A6A (੪), U+0b6b (୫)} => 8,
   //   - {U+0AED (૭), U+0b68 (୨), U+0C68 (౨)} => 9,
+  //   Map a few dashes that ICU doesn't map. These are already blocked by ICU,
+  //   but mapping them allows us to detect same skeletons.
+  //   - {U+2014 (—), U+4E00 (一), U+2015 (―), U+23EA (⸺), U+2E3B (⸻)} => -,
   extra_confusable_mapper_.reset(icu::Transliterator::createFromRules(
       UNICODE_STRING_SIMPLE("ExtraConf"),
       icu::UnicodeString::fromUTF8(
@@ -234,7 +237,8 @@
           "[зҙӡउওਤ੩૩౩ဒვპ] > 3;"
           "[੫] > 4;"
           "[৪੪୫] > 8;"
-          "[૭୨౨] > 9;"),
+          "[૭୨౨] > 9;"
+          "[—一―⸺⸻] > \\-;"),
       UTRANS_FORWARD, parse_error, status));
   DCHECK(U_SUCCESS(status))
       << "Spoofchecker initalization failed due to an error: "
diff --git a/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc b/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
index d26c6966..2afa440 100644
--- a/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
+++ b/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
@@ -14,6 +14,7 @@
 #include "build/build_config.h"
 #include "components/url_formatter/spoof_checks/idn_spoof_checker.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace url_formatter {
 
@@ -1133,4 +1134,42 @@
   }
 }
 
+// Checks that skeletons are properly generated for domains with blocked
+// characters after using UnsafeIDNToUnicodeWithDetails.
+TEST(IDNSpoofCheckerTest, Skeletons) {
+  // All of these should produce the same skeleton. Not all of these are
+  // explicitly mapped in idn_spoof_checker.cc, ICU already handles some.
+  const GURL kTestCases[] = {
+      // U+2010 (Hyphen)
+      GURL("http://test‐site"),
+      // U+2011 (Non breaking hyphen)
+      GURL("http://test‑site"),
+      // U+2012 (Figure dash)
+      GURL("http://test‒site"),
+      // U+2013 (En dash)
+      GURL("http://test–site"),
+      // U+2014 (Em dash)
+      GURL("http://test—site"),
+      // U+2015 (Horizontal bar)
+      GURL("http://test―site"),
+      // U+4E00 (一)
+      GURL("http://test一site"),
+      // U+2212 (minus sign)
+      GURL("http://test−site"),
+      // U+2E3A (two-em dash)
+      GURL("http://test⸺site"),
+      // U+2E3B (three-em dash)
+      GURL("http://test⸻site"),
+  };
+
+  IDNSpoofChecker checker;
+  for (const GURL& url : kTestCases) {
+    const url_formatter::IDNConversionResult result =
+        UnsafeIDNToUnicodeWithDetails(url.host());
+    Skeletons skeletons = checker.GetSkeletons(result.result);
+    EXPECT_EQ(1u, skeletons.size());
+    EXPECT_EQ("test-site", *skeletons.begin());
+  }
+}
+
 }  // namespace url_formatter
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 637194d8..cfc3d93f2 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -391,8 +391,6 @@
     "appcache/appcache_histograms.h",
     "appcache/appcache_host.cc",
     "appcache/appcache_host.h",
-    "appcache/appcache_interceptor.cc",
-    "appcache/appcache_interceptor.h",
     "appcache/appcache_internals_ui.cc",
     "appcache/appcache_internals_ui.h",
     "appcache/appcache_job.cc",
@@ -432,10 +430,6 @@
     "appcache/appcache_url_loader_job.h",
     "appcache/appcache_url_loader_request.cc",
     "appcache/appcache_url_loader_request.h",
-    "appcache/appcache_url_request.cc",
-    "appcache/appcache_url_request.h",
-    "appcache/appcache_url_request_job.cc",
-    "appcache/appcache_url_request_job.h",
     "appcache/appcache_working_set.cc",
     "appcache/appcache_working_set.h",
     "appcache/chrome_appcache_service.cc",
@@ -728,12 +722,8 @@
     "devtools/devtools_target_registry.h",
     "devtools/devtools_traceable_screenshot.cc",
     "devtools/devtools_traceable_screenshot.h",
-    "devtools/devtools_url_interceptor_request_job.cc",
-    "devtools/devtools_url_interceptor_request_job.h",
     "devtools/devtools_url_loader_interceptor.cc",
     "devtools/devtools_url_loader_interceptor.h",
-    "devtools/devtools_url_request_interceptor.cc",
-    "devtools/devtools_url_request_interceptor.h",
     "devtools/devtools_video_consumer.cc",
     "devtools/devtools_video_consumer.h",
     "devtools/forwarding_agent_host.cc",
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
index b607aab..e0d44081 100644
--- a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -92,21 +92,32 @@
     observer.Wait();
   }
 
-  void GetTextRangeProviderFromTextNode(
-      ComPtr<ITextRangeProvider>& text_range_provider,
-      BrowserAccessibility* target_browser_accessibility) {
-    auto* provider_simple =
-        ToBrowserAccessibilityWin(target_browser_accessibility)->GetCOM();
-    ASSERT_NE(nullptr, provider_simple);
+  BrowserAccessibilityManager* GetManager() const {
+    WebContentsImpl* web_contents =
+        static_cast<WebContentsImpl*>(shell()->web_contents());
+    return web_contents->GetRootBrowserAccessibilityManager();
+  }
+
+  ComPtr<ITextRangeProvider> GetTextRangeProviderFromTextNode(
+      const BrowserAccessibility* target_node) {
+    ComPtr<IRawElementProviderSimple> provider_simple =
+        ToBrowserAccessibilityWin(target_node)->GetCOM();
+    DCHECK_NE(nullptr, provider_simple.Get());
 
     ComPtr<ITextProvider> text_provider;
-    EXPECT_HRESULT_SUCCEEDED(
-        provider_simple->GetPatternProvider(UIA_TextPatternId, &text_provider));
-    ASSERT_NE(nullptr, text_provider.Get());
+    DCHECK(SUCCEEDED(provider_simple->GetPatternProvider(UIA_TextPatternId,
+                                                         &text_provider)));
+    DCHECK_NE(nullptr, text_provider.Get());
 
-    EXPECT_HRESULT_SUCCEEDED(
-        text_provider->get_DocumentRange(&text_range_provider));
-    ASSERT_NE(nullptr, text_range_provider.Get());
+    ComPtr<ITextRangeProvider> text_range_provider;
+    DCHECK(SUCCEEDED(text_provider->get_DocumentRange(&text_range_provider)));
+    return text_range_provider;
+  }
+
+  ComPtr<ITextRangeProvider> GetDocumentRangeForMarkup(
+      const std::string& html_markup) {
+    LoadInitialAccessibilityTreeFromHtml(html_markup);
+    return GetTextRangeProviderFromTextNode(GetManager()->GetRoot());
   }
 
   // Run through ITextRangeProvider::ScrollIntoView top tests. It's assumed that
@@ -338,6 +349,35 @@
     ScrollIntoViewBrowserTestTemplate(expected_role_start, fstart, fstart_arg,
                                       expected_role_end, fend, fend_arg, false);
   }
+
+  void AssertMoveByUnitForMarkup(
+      const TextUnit& unit,
+      const std::string& html_markup,
+      const std::vector<const wchar_t*>& expected_text) {
+    ComPtr<ITextRangeProvider> text_range =
+        GetDocumentRangeForMarkup(html_markup);
+
+    ASSERT_NE(nullptr, text_range);
+    text_range->ExpandToEnclosingUnit(unit);
+
+    size_t index = 0;
+    int count_moved = 1;
+    while (count_moved == 1 && index < expected_text.size()) {
+      EXPECT_UIA_TEXTRANGE_EQ(text_range, expected_text[index++]);
+      ASSERT_HRESULT_SUCCEEDED(text_range->Move(unit, 1, &count_moved));
+    }
+    EXPECT_EQ(expected_text.size(), index);
+    EXPECT_EQ(0, count_moved);
+
+    count_moved = -1;
+    index = expected_text.size();
+    while (count_moved == -1 && index > 0) {
+      EXPECT_UIA_TEXTRANGE_EQ(text_range, expected_text[--index]);
+      ASSERT_HRESULT_SUCCEEDED(text_range->Move(unit, -1, &count_moved));
+    }
+    EXPECT_EQ(0, count_moved);
+    EXPECT_EQ(0u, index);
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
@@ -364,8 +404,8 @@
   EXPECT_TRUE(node->PlatformIsLeaf());
   EXPECT_EQ(0u, node->PlatformChildCount());
 
-  ComPtr<ITextRangeProvider> text_range_provider;
-  GetTextRangeProviderFromTextNode(text_range_provider, node);
+  ComPtr<ITextRangeProvider> text_range_provider =
+      GetTextRangeProviderFromTextNode(node);
   ASSERT_NE(nullptr, text_range_provider.Get());
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"AsdfAsdfAsdf");
 
@@ -568,8 +608,8 @@
   EXPECT_TRUE(node->PlatformIsLeaf());
   EXPECT_EQ(0u, node->PlatformChildCount());
 
-  ComPtr<ITextRangeProvider> text_range_provider;
-  GetTextRangeProviderFromTextNode(text_range_provider, node);
+  ComPtr<ITextRangeProvider> text_range_provider =
+      GetTextRangeProviderFromTextNode(node);
   ASSERT_NE(nullptr, text_range_provider.Get());
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain 1");
 
@@ -641,8 +681,8 @@
   EXPECT_TRUE(node->PlatformIsLeaf());
   EXPECT_EQ(0u, node->PlatformChildCount());
 
-  ComPtr<ITextRangeProvider> text_range_provider;
-  GetTextRangeProviderFromTextNode(text_range_provider, node);
+  ComPtr<ITextRangeProvider> text_range_provider =
+      GetTextRangeProviderFromTextNode(node);
   ASSERT_NE(nullptr, text_range_provider.Get());
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain 1");
 
@@ -795,7 +835,6 @@
       FindNode(ax::mojom::Role::kStaticText, "end");
   ASSERT_NE(nullptr, end_node);
 
-  ComPtr<ITextRangeProvider> text_range_provider;
 
   std::vector<base::string16> paragraphs = {
       L"start",
@@ -806,7 +845,8 @@
   };
 
   // FORWARD NAVIGATION
-  GetTextRangeProviderFromTextNode(text_range_provider, start_node);
+  ComPtr<ITextRangeProvider> text_range_provider =
+      GetTextRangeProviderFromTextNode(start_node);
   ASSERT_NE(nullptr, text_range_provider.Get());
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"start");
 
@@ -877,7 +917,7 @@
       /*expected_count*/ 1);
 
   // REVERSE NAVIGATION
-  GetTextRangeProviderFromTextNode(text_range_provider, end_node);
+  text_range_provider = GetTextRangeProviderFromTextNode(end_node);
   ASSERT_NE(nullptr, text_range_provider.Get());
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"end");
 
@@ -983,7 +1023,7 @@
   };
 
   // FORWARD NAVIGATION
-  GetTextRangeProviderFromTextNode(text_range_provider, start_node);
+  text_range_provider = GetTextRangeProviderFromTextNode(start_node);
   ASSERT_NE(nullptr, text_range_provider.Get());
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"start");
 
@@ -1019,7 +1059,7 @@
       /*expected_count*/ 1);
 
   // REVERSE NAVIGATION
-  GetTextRangeProviderFromTextNode(text_range_provider, end_node);
+  text_range_provider = GetTextRangeProviderFromTextNode(end_node);
   ASSERT_NE(nullptr, text_range_provider.Get());
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"end");
 
@@ -1068,8 +1108,8 @@
   EXPECT_TRUE(node->PlatformIsLeaf());
   EXPECT_EQ(0u, node->PlatformChildCount());
 
-  ComPtr<ITextRangeProvider> text_range_provider;
-  GetTextRangeProviderFromTextNode(text_range_provider, node);
+  ComPtr<ITextRangeProvider> text_range_provider =
+      GetTextRangeProviderFromTextNode(node);
   ASSERT_NE(nullptr, text_range_provider.Get());
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"After frame");
 
@@ -1086,12 +1126,12 @@
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
                                    TextPatternRangeEndpoint_End, TextUnit_Word,
                                    /*count*/ -3,
-                                   /*expected_text*/ L"Text in",
+                                   /*expected_text*/ L"Text in ",
                                    /*expected_count*/ -3);
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
                                    TextPatternRangeEndpoint_End, TextUnit_Word,
                                    /*count*/ 2,
-                                   /*expected_text*/ L"Text in iframe\nAfter",
+                                   /*expected_text*/ L"Text in iframe\nAfter ",
                                    /*expected_count*/ 2);
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
       text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Line,
@@ -1123,11 +1163,11 @@
 
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ 2,
-                  /*expected_text*/ L"Text",
+                  /*expected_text*/ L"Text ",
                   /*expected_count*/ 2);
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ -1,
-                  /*expected_text*/ L"frame",
+                  /*expected_text*/ L"frame\n",
                   /*expected_count*/ -1);
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
       text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Character,
@@ -1203,8 +1243,8 @@
   EXPECT_TRUE(node->PlatformIsLeaf());
   EXPECT_EQ(0u, node->PlatformChildCount());
 
-  ComPtr<ITextRangeProvider> text_range_provider;
-  GetTextRangeProviderFromTextNode(text_range_provider, node);
+  ComPtr<ITextRangeProvider> text_range_provider =
+      GetTextRangeProviderFromTextNode(node);
   ASSERT_NE(nullptr, text_range_provider.Get());
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"After frame");
 
@@ -1221,12 +1261,12 @@
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
                                    TextPatternRangeEndpoint_End, TextUnit_Word,
                                    /*count*/ -3,
-                                   /*expected_text*/ L"Text in",
+                                   /*expected_text*/ L"Text in ",
                                    /*expected_count*/ -3);
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
                                    TextPatternRangeEndpoint_End, TextUnit_Word,
                                    /*count*/ 2,
-                                   /*expected_text*/ L"Text in iframe\nAfter",
+                                   /*expected_text*/ L"Text in iframe\nAfter ",
                                    /*expected_count*/ 2);
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
       text_range_provider, TextPatternRangeEndpoint_End, TextUnit_Line,
@@ -1268,8 +1308,8 @@
   EXPECT_TRUE(node->PlatformIsLeaf());
   EXPECT_EQ(0u, node->PlatformChildCount());
 
-  ComPtr<ITextRangeProvider> text_range_provider;
-  GetTextRangeProviderFromTextNode(text_range_provider, node);
+  ComPtr<ITextRangeProvider> text_range_provider =
+      GetTextRangeProviderFromTextNode(node);
   ASSERT_NE(nullptr, text_range_provider.Get());
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"plain");
 
@@ -1299,4 +1339,28 @@
       text_range_provider->ExpandToEnclosingUnit(TextUnit_Format));
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"italic\ntext");
 }
+
+IN_PROC_BROWSER_TEST_F(AXPlatformNodeTextRangeProviderWinBrowserTest,
+                       EntireMarkupSuccessiveMoveByWord) {
+  AssertMoveByUnitForMarkup(TextUnit_Word, "this is a test.",
+                            {L"this ", L"is ", L"a ", L"test."});
+
+  AssertMoveByUnitForMarkup(TextUnit_Word,
+                            "    this    is      a      test.    ",
+                            {L"this ", L"is ", L"a ", L"test."});
+
+  AssertMoveByUnitForMarkup(
+      TextUnit_Word, "It said: to be continued...",
+      {L"It ", L"said: ", L"to ", L"be ", L"continued..."});
+
+  AssertMoveByUnitForMarkup(TextUnit_Word,
+                            "a <a>link with multiple words</a> and text after.",
+                            {L"a ", L"link ", L"with ", L"multiple ", L"words ",
+                             L"and ", L"text ", L"after."});
+
+  // AssertMoveByUnitForMarkup(
+  //     TextUnit_Word, "<ul><li>item one</li><li>item two</li></ul>",
+  //     {L"* ", L"item ", L"one\n", L"* ", L"item ", L"two"});
+}
+
 }  // namespace content
diff --git a/content/browser/appcache/appcache_interceptor.cc b/content/browser/appcache/appcache_interceptor.cc
deleted file mode 100644
index 22dae8a..0000000
--- a/content/browser/appcache/appcache_interceptor.cc
+++ /dev/null
@@ -1,120 +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 "content/browser/appcache/appcache_interceptor.h"
-
-#include <utility>
-
-#include "content/browser/appcache/appcache_backend_impl.h"
-#include "content/browser/appcache/appcache_host.h"
-#include "content/browser/appcache/appcache_request_handler.h"
-#include "content/browser/appcache/appcache_service_impl.h"
-#include "content/browser/appcache/appcache_url_request.h"
-#include "content/browser/appcache/appcache_url_request_job.h"
-#include "content/browser/appcache/chrome_appcache_service.h"
-#include "content/browser/bad_message.h"
-#include "content/browser/loader/resource_requester_info.h"
-#include "content/common/appcache_interfaces.h"
-#include "net/url_request/url_request.h"
-#include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
-#include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
-
-static int kHandlerKey;  // Value is not used.
-
-namespace content {
-
-void AppCacheInterceptor::SetHandler(
-    net::URLRequest* request,
-    std::unique_ptr<AppCacheRequestHandler> handler) {
-  request->SetUserData(&kHandlerKey, std::move(handler));
-}
-
-AppCacheRequestHandler* AppCacheInterceptor::GetHandler(
-    net::URLRequest* request) {
-  return static_cast<AppCacheRequestHandler*>(
-      request->GetUserData(&kHandlerKey));
-}
-
-void AppCacheInterceptor::SetExtraRequestInfo(
-    net::URLRequest* request,
-    AppCacheServiceImpl* service,
-    const base::UnguessableToken& host_id,
-    ResourceType resource_type,
-    bool should_reset_appcache) {
-  if (!service || host_id.is_empty())
-    return;
-
-  // TODO(michaeln): An invalid host id is indicative of bad data
-  // from a child process. How should we handle that here?
-  AppCacheHost* host = service->GetHost(host_id);
-  if (!host)
-    return;
-
-  SetExtraRequestInfoForHost(request, host, resource_type,
-                             should_reset_appcache);
-}
-
-void AppCacheInterceptor::SetExtraRequestInfoForHost(
-    net::URLRequest* request,
-    AppCacheHost* host,
-    ResourceType resource_type,
-    bool should_reset_appcache) {
-  // Create a handler for this request and associate it with the request.
-  std::unique_ptr<AppCacheRequestHandler> handler =
-      host->CreateRequestHandler(std::make_unique<AppCacheURLRequest>(request),
-                                 resource_type, should_reset_appcache);
-  if (handler)
-    SetHandler(request, std::move(handler));
-}
-
-void AppCacheInterceptor::GetExtraResponseInfo(net::URLRequest* request,
-                                               int64_t* cache_id,
-                                               GURL* manifest_url) {
-  DCHECK(*cache_id == blink::mojom::kAppCacheNoCacheId);
-  DCHECK(manifest_url->is_empty());
-  AppCacheRequestHandler* handler = GetHandler(request);
-  if (handler)
-    handler->GetExtraResponseInfo(cache_id, manifest_url);
-}
-
-AppCacheInterceptor::AppCacheInterceptor() {
-}
-
-AppCacheInterceptor::~AppCacheInterceptor() {
-}
-
-net::URLRequestJob* AppCacheInterceptor::MaybeInterceptRequest(
-    net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
-  AppCacheRequestHandler* handler = GetHandler(request);
-  if (!handler)
-    return nullptr;
-
-  AppCacheJob* job = handler->MaybeLoadResource(network_delegate);
-  return job ? job->AsURLRequestJob() : nullptr;
-}
-
-net::URLRequestJob* AppCacheInterceptor::MaybeInterceptRedirect(
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate,
-    const GURL& location) const {
-  AppCacheRequestHandler* handler = GetHandler(request);
-  if (!handler)
-    return nullptr;
-
-  AppCacheJob* job =
-      handler->MaybeLoadFallbackForRedirect(network_delegate, location);
-  return job ? job->AsURLRequestJob() : nullptr;
-}
-
-net::URLRequestJob* AppCacheInterceptor::MaybeInterceptResponse(
-    net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
-  AppCacheRequestHandler* handler = GetHandler(request);
-  if (!handler)
-    return nullptr;
-
-  AppCacheJob* job = handler->MaybeLoadFallbackForResponse(network_delegate);
-  return job ? job->AsURLRequestJob() : nullptr;
-}
-
-}  // namespace content
diff --git a/content/browser/appcache/appcache_interceptor.h b/content/browser/appcache/appcache_interceptor.h
deleted file mode 100644
index 8eed205..0000000
--- a/content/browser/appcache/appcache_interceptor.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_INTERCEPTOR_H_
-#define CONTENT_BROWSER_APPCACHE_APPCACHE_INTERCEPTOR_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/unguessable_token.h"
-#include "content/common/content_export.h"
-#include "content/public/common/resource_type.h"
-#include "net/url_request/url_request_interceptor.h"
-
-class GURL;
-
-namespace net {
-class URLRequest;
-}
-
-namespace content {
-class AppCacheHost;
-class AppCacheRequestHandler;
-class AppCacheServiceImpl;
-
-// An interceptor to hijack requests and potentially service them out of
-// the appcache.
-class CONTENT_EXPORT AppCacheInterceptor : public net::URLRequestInterceptor {
- public:
-  // Must be called to make a request eligible for retrieval from an appcache.
-  static void SetExtraRequestInfo(net::URLRequest* request,
-                                  AppCacheServiceImpl* service,
-                                  const base::UnguessableToken& host_id,
-                                  ResourceType resource_type,
-                                  bool should_reset_appcache);
-
-  // PlzNavigate
-  // Must be called to make a request eligible for retrieval from an appcache.
-  static void SetExtraRequestInfoForHost(net::URLRequest* request,
-                                         AppCacheHost* host,
-                                         ResourceType resource_type,
-                                         bool should_reset_appcache);
-
-  // May be called after response headers are complete to retrieve extra
-  // info about the response.
-  static void GetExtraResponseInfo(net::URLRequest* request,
-                                   int64_t* cache_id,
-                                   GURL* manifest_url);
-
-  AppCacheInterceptor();
-  ~AppCacheInterceptor() override;
-
- protected:
-  // Override from net::URLRequestInterceptor:
-  net::URLRequestJob* MaybeInterceptRequest(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override;
-  net::URLRequestJob* MaybeInterceptResponse(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override;
-  net::URLRequestJob* MaybeInterceptRedirect(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate,
-      const GURL& location) const override;
-
- private:
-  static void SetHandler(net::URLRequest* request,
-                         std::unique_ptr<AppCacheRequestHandler> handler);
-  static AppCacheRequestHandler* GetHandler(net::URLRequest* request);
-
-  DISALLOW_COPY_AND_ASSIGN(AppCacheInterceptor);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_INTERCEPTOR_H_
diff --git a/content/browser/appcache/appcache_job.cc b/content/browser/appcache/appcache_job.cc
index e5575b2..d6af295 100644
--- a/content/browser/appcache/appcache_job.cc
+++ b/content/browser/appcache/appcache_job.cc
@@ -8,7 +8,6 @@
 #include "content/browser/appcache/appcache_request.h"
 #include "content/browser/appcache/appcache_response.h"
 #include "content/browser/appcache/appcache_url_loader_job.h"
-#include "content/browser/appcache/appcache_url_request_job.h"
 #include "content/public/common/content_features.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
@@ -20,10 +19,6 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-AppCacheURLRequestJob* AppCacheJob::AsURLRequestJob() {
-  return nullptr;
-}
-
 AppCacheURLLoaderJob* AppCacheJob::AsURLLoaderJob() {
   return nullptr;
 }
diff --git a/content/browser/appcache/appcache_job.h b/content/browser/appcache/appcache_job.h
index cf18a72..9ef9f7e 100644
--- a/content/browser/appcache/appcache_job.h
+++ b/content/browser/appcache/appcache_job.h
@@ -18,7 +18,6 @@
 namespace net {
 class HttpRequestHeaders;
 class HttpResponseInfo;
-class URLRequestJob;
 }
 
 namespace content {
@@ -27,7 +26,6 @@
 class AppCacheResponseInfo;
 class AppCacheResponseReader;
 class AppCacheURLLoaderJob;
-class AppCacheURLRequestJob;
 
 // Interface for an AppCache job. This is used to send data stored in the
 // AppCache to networking consumers.
@@ -89,10 +87,6 @@
   // Returns a weak pointer reference to the job.
   virtual base::WeakPtr<AppCacheJob> GetWeakPtr() = 0;
 
-  // Returns the underlying AppCacheURLRequestJob if any. This only applies to
-  // AppCaches loaded via the URLLoader mechanism.
-  virtual AppCacheURLRequestJob* AsURLRequestJob();
-
   // Returns the underlying ApppCacheURLLoaderJob if any. This only applies to
   // AppCaches loaded via the URLRequest mechanism.
   virtual AppCacheURLLoaderJob* AsURLLoaderJob();
diff --git a/content/browser/appcache/appcache_request.cc b/content/browser/appcache/appcache_request.cc
index 9818ec8..58068e9d 100644
--- a/content/browser/appcache/appcache_request.cc
+++ b/content/browser/appcache/appcache_request.cc
@@ -19,18 +19,10 @@
          IsMethodSupportedForAppCache(request->GetMethod());
 }
 
-net::URLRequest* AppCacheRequest::GetURLRequest() {
-  return nullptr;
-}
-
 network::ResourceRequest* AppCacheRequest::GetResourceRequest() {
   return nullptr;
 }
 
-AppCacheURLRequest* AppCacheRequest::AsURLRequest() {
-  return nullptr;
-}
-
 AppCacheURLLoaderRequest* AppCacheRequest::AsURLLoaderRequest() {
   return nullptr;
 }
diff --git a/content/browser/appcache/appcache_request.h b/content/browser/appcache/appcache_request.h
index 7b508e33..4a386a0 100644
--- a/content/browser/appcache/appcache_request.h
+++ b/content/browser/appcache/appcache_request.h
@@ -11,17 +11,12 @@
 #include "content/common/content_export.h"
 #include "url/gurl.h"
 
-namespace net {
-class URLRequest;
-}
-
 namespace network {
 struct ResourceRequest;
 }
 
 namespace content {
 class AppCacheURLLoaderRequest;
-class AppCacheURLRequest;
 
 // Interface for an AppCache request. Subclasses implement this interface to
 // wrap custom request objects like URLRequest, etc to ensure that these
@@ -63,10 +58,6 @@
   static bool IsSchemeAndMethodSupportedForAppCache(
       const AppCacheRequest* request);
 
-  // Returns the underlying AppCacheURLRequest if any. This only applies to
-  // AppCache requests loaded via the URLRequest mechanism
-  virtual AppCacheURLRequest* AsURLRequest();
-
   // Returns the underlying AppCacheURLLoaderRequest if any. This only applies
   // to AppCache requests loaded via the URLLoader mechanism.
   virtual AppCacheURLLoaderRequest* AsURLLoaderRequest();
@@ -78,9 +69,6 @@
 
   AppCacheRequest() {}
 
-  // Getters for the request types we currently support.
-  virtual net::URLRequest* GetURLRequest();
-
   // Returns the underlying ResourceRequest. Please note that only one of
   // GetURLRequest() and GetResourceRequest() should return valid results.
   virtual network::ResourceRequest* GetResourceRequest();
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc
index cb50a28..3c6bfd8 100644
--- a/content/browser/appcache/appcache_request_handler.cc
+++ b/content/browser/appcache/appcache_request_handler.cc
@@ -18,7 +18,6 @@
 #include "content/browser/appcache/appcache_subresource_url_factory.h"
 #include "content/browser/appcache/appcache_url_loader_job.h"
 #include "content/browser/appcache/appcache_url_loader_request.h"
-#include "content/browser/appcache/appcache_url_request_job.h"
 #include "content/browser/navigation_subresource_loader_params.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_job.h"
@@ -254,11 +253,8 @@
 
   // Since the host is being deleted, we don't have to complete any job
   // that is current running. It's destined for the bit bucket anyway.
-  if (job_.get()) {
-    if (job_->AsURLRequestJob())
-      job_->AsURLRequestJob()->Kill();
+  if (job_.get())
     job_.reset();
-  }
 }
 
 void AppCacheRequestHandler::OnServiceDestructionImminent(
@@ -305,35 +301,11 @@
   job_->DeliverNetworkResponse();
 }
 
-void AppCacheRequestHandler::OnPrepareToRestartURLRequest() {
-  DCHECK(job_->AsURLRequestJob());
-  DCHECK(job_->IsDeliveringNetworkResponse() || job_->IsCacheEntryNotFound());
-
-  // Any information about the source of the response is no longer relevant.
-  cache_id_ = blink::mojom::kAppCacheNoCacheId;
-  manifest_url_ = GURL();
-
-  cache_entry_not_found_ = job_->IsCacheEntryNotFound();
-  is_delivering_network_response_ = job_->IsDeliveringNetworkResponse();
-
-  storage()->CancelDelegateCallbacks(this);
-
-  job_.reset();
-}
-
 std::unique_ptr<AppCacheJob> AppCacheRequestHandler::CreateJob(
     net::NetworkDelegate* network_delegate) {
   std::unique_ptr<AppCacheJob> job;
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
-    job = std::make_unique<AppCacheURLLoaderJob>(
-        request_->AsURLLoaderRequest(), storage(), std::move(loader_callback_));
-  } else {
-    job = std::make_unique<AppCacheURLRequestJob>(
-        request_->GetURLRequest(), network_delegate, storage(), host_,
-        is_main_resource(),
-        base::BindOnce(&AppCacheRequestHandler::OnPrepareToRestartURLRequest,
-                       base::Unretained(this)));
-  }
+  job = std::make_unique<AppCacheURLLoaderJob>(
+      request_->AsURLLoaderRequest(), storage(), std::move(loader_callback_));
   job_ = job->GetWeakPtr();
   return job;
 }
diff --git a/content/browser/appcache/appcache_request_handler.h b/content/browser/appcache/appcache_request_handler.h
index 555832e..357bcd4 100644
--- a/content/browser/appcache/appcache_request_handler.h
+++ b/content/browser/appcache/appcache_request_handler.h
@@ -36,7 +36,6 @@
 class AppCacheSubresourceURLFactory;
 class AppCacheRequest;
 class AppCacheRequestHandlerTest;
-class AppCacheURLRequestJob;
 class AppCacheHost;
 
 // An instance is created for each net::URLRequest. The instance survives all
@@ -147,10 +146,6 @@
   void DeliverNetworkResponse();
   void DeliverErrorResponse();
 
-  // Called just before the request is restarted. Grabs the reason for
-  // restarting, so can correctly continue to handle the request.
-  void OnPrepareToRestartURLRequest();
-
   // Helper method to create an AppCacheJob and populate job_.
   // Caller takes ownership of returned value.
   std::unique_ptr<AppCacheJob> CreateJob(
diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc
index 61e1515c..23292cb 100644
--- a/content/browser/appcache/appcache_request_handler_unittest.cc
+++ b/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -31,8 +31,6 @@
 #include "content/browser/appcache/appcache_job.h"
 #include "content/browser/appcache/appcache_url_loader_job.h"
 #include "content/browser/appcache/appcache_url_loader_request.h"
-#include "content/browser/appcache/appcache_url_request.h"
-#include "content/browser/appcache/appcache_url_request_job.h"
 #include "content/browser/appcache/mock_appcache_policy.h"
 #include "content/browser/appcache/mock_appcache_service.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -44,10 +42,6 @@
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_error_job.h"
-#include "net/url_request/url_request_job_factory.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -59,20 +53,12 @@
 
 static const int kMockProcessId = 1;
 
-// Controls whether we instantiate the URLRequest based AppCache handler or
-// the URLLoader based one.
-enum RequestHandlerType {
-  URLREQUEST,
-  URLLOADER,
-};
-
 // TODO(michaeln/ananta)
 // Build on the abstractions provided by the request and the job classes to
 // provide mock request and job classes to the AppCacheRequestHandler class
 // which would make it testable. It would also allow us to avoid the URLRequest
 // and URLLoader semantics in the test cases here,
-class AppCacheRequestHandlerTest
-    : public testing::TestWithParam<RequestHandlerType> {
+class AppCacheRequestHandlerTest : public ::testing::Test {
  public:
   // Helper callback to run a test on our io_thread. The io_thread is spun up
   // once and reused for all tests.
@@ -82,32 +68,6 @@
     (this->*method)();
   }
 
-  // Subclasses to simulate particular responses so test cases can
-  // exercise fallback code paths.
-
-  class MockURLRequestDelegate : public net::URLRequest::Delegate {
-   public:
-    MockURLRequestDelegate() : request_status_(1) {}
-
-    void OnResponseStarted(net::URLRequest* request, int net_error) override {
-      DCHECK_NE(net::ERR_IO_PENDING, net_error);
-      request_status_ = net_error;
-    }
-
-    void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
-      DCHECK_NE(net::ERR_IO_PENDING, bytes_read);
-      if (bytes_read >= 0)
-        request_status_ = net::OK;
-      else
-        request_status_ = bytes_read;
-    }
-
-    int request_status() const { return request_status_; }
-
-   private:
-    int request_status_;
-  };
-
   static void SetUpTestCase() {
     thread_bundle_ = std::make_unique<TestBrowserThreadBundle>(
         TestBrowserThreadBundle::REAL_IO_THREAD);
@@ -129,7 +89,7 @@
     feature_list_.InitWithFeatures({}, {features::kNavigationLoaderOnUI});
   }
 
-  ~AppCacheRequestHandlerTest() {
+  ~AppCacheRequestHandlerTest() override {
     AppCacheRequestHandler::SetRunningInTests(false);
   }
 
@@ -778,7 +738,6 @@
   std::unique_ptr<MockAppCachePolicy> mock_policy_;
   AppCacheHost* host_;
   mojo::Remote<blink::mojom::AppCacheHost> host_remote_;
-  MockURLRequestDelegate delegate_;
   AppCacheRequest* request_;
   std::unique_ptr<net::URLRequest> url_request_;
   std::unique_ptr<AppCacheRequestHandler> handler_;
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc
index 5e660347..39fca4e 100644
--- a/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -32,7 +32,6 @@
 #include "content/browser/appcache/appcache_entry.h"
 #include "content/browser/appcache/appcache_group.h"
 #include "content/browser/appcache/appcache_host.h"
-#include "content/browser/appcache/appcache_interceptor.h"
 #include "content/browser/appcache/appcache_request_handler.h"
 #include "content/browser/appcache/appcache_service_impl.h"
 #include "content/browser/appcache/appcache_url_loader_request.h"
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc
index 5469b163..226cf9a3 100644
--- a/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -372,19 +372,6 @@
   std::vector<AppCacheHost*> update_hosts_;
 };
 
-// Helper factories to simulate redirected URL responses for tests.
-class RedirectFactory : public net::URLRequestJobFactory::ProtocolHandler {
- public:
-  net::URLRequestJob* MaybeCreateJob(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return new net::URLRequestTestJob(
-        request, network_delegate,
-        net::URLRequestTestJob::test_redirect_headers(),
-        net::URLRequestTestJob::test_data_1(), true);
-  }
-};
-
 // Helper class to simulate a URL that returns retry or success.
 class RetryRequestTestJob : public net::URLRequestTestJob {
  public:
@@ -491,16 +478,6 @@
   static int expected_requests_;
 };
 
-class RetryRequestTestJobFactory
-    : public net::URLRequestJobFactory::ProtocolHandler {
- public:
-  net::URLRequestJob* MaybeCreateJob(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return RetryRequestTestJob::RetryFactory(request, network_delegate);
-  }
-};
-
 // static
 const GURL RetryRequestTestJob::kRetryUrl("http://retry");
 int RetryRequestTestJob::num_requests_ = 0;
@@ -681,14 +658,7 @@
   std::unique_ptr<net::URLRequestContext> request_context_;
 };
 
-// Controls whether we instantiate the URLRequest based AppCache handler or
-// the URLLoader based one.
-enum RequestHandlerType {
-  URLREQUEST,
-  URLLOADER,
-};
-
-class AppCacheUpdateJobTest : public testing::TestWithParam<RequestHandlerType>,
+class AppCacheUpdateJobTest : public testing::Test,
                               public AppCacheGroup::UpdateObserver {
  public:
   AppCacheUpdateJobTest()
@@ -720,7 +690,7 @@
                        base::Unretained(this)));
   }
 
-  ~AppCacheUpdateJobTest() {
+  ~AppCacheUpdateJobTest() override {
     loader_factory_getter_ = nullptr;
     // The TestBrowserThreadBundle dtor guarantees that all posted tasks are
     // executed before the IO thread shuts down. It is safe to use the
diff --git a/content/browser/appcache/appcache_url_request.cc b/content/browser/appcache/appcache_url_request.cc
deleted file mode 100644
index 9d2df61..0000000
--- a/content/browser/appcache/appcache_url_request.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/appcache/appcache_url_request.h"
-#include "net/url_request/url_request.h"
-
-namespace content {
-
-const GURL& AppCacheURLRequest::GetURL() const {
-  return url_request_->url();
-}
-
-const std::string& AppCacheURLRequest::GetMethod() const {
-  return url_request_->method();
-}
-
-const GURL& AppCacheURLRequest::GetSiteForCookies() const {
-  return url_request_->site_for_cookies();
-}
-
-const GURL AppCacheURLRequest::GetReferrer() const {
-  return GURL(url_request_->referrer());
-}
-
-bool AppCacheURLRequest::IsSuccess() const {
-  return url_request_->status().is_success();
-}
-
-bool AppCacheURLRequest::IsCancelled() const {
-  return url_request_->status().status() == net::URLRequestStatus::CANCELED;
-}
-
-bool AppCacheURLRequest::IsError() const {
-  return !url_request_->status().is_success();
-}
-
-int AppCacheURLRequest::GetResponseCode() const {
-  return url_request_->GetResponseCode();
-}
-
-std::string AppCacheURLRequest::GetResponseHeaderByName(
-    const std::string& name) const {
-  std::string header;
-  url_request_->GetResponseHeaderByName(name, &header);
-  return header;
-}
-
-net::URLRequest* AppCacheURLRequest::GetURLRequest() {
-  return url_request_;
-}
-
-AppCacheURLRequest* AppCacheURLRequest::AsURLRequest() {
-  return this;
-}
-
-AppCacheURLRequest::AppCacheURLRequest(net::URLRequest* url_request)
-    : url_request_(url_request) {}
-
-AppCacheURLRequest::~AppCacheURLRequest() = default;
-
-}  // namespace content
diff --git a/content/browser/appcache/appcache_url_request.h b/content/browser/appcache/appcache_url_request.h
deleted file mode 100644
index 12af6a12..0000000
--- a/content/browser/appcache/appcache_url_request.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 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.
-
-#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_URL_REQUEST_H_
-#define CONTENT_BROWSER_APPCACHE_APPCACHE_URL_REQUEST_H_
-
-#include "content/browser/appcache/appcache_request.h"
-#include "content/common/content_export.h"
-
-namespace net {
-class URLRequest;
-}  // namespace net
-
-namespace content {
-
-// AppCacheRequest wrapper for the URLRequest class.
-class CONTENT_EXPORT AppCacheURLRequest : public AppCacheRequest {
- public:
-  explicit AppCacheURLRequest(net::URLRequest* url_request);
-  ~AppCacheURLRequest() override;
-
-  // AppCacheRequest overrides.
-  const GURL& GetURL() const override;
-  const std::string& GetMethod() const override;
-  const GURL& GetSiteForCookies() const override;
-  const GURL GetReferrer() const override;
-  bool IsSuccess() const override;
-  bool IsCancelled() const override;
-  bool IsError() const override;
-  int GetResponseCode() const override;
-  std::string GetResponseHeaderByName(const std::string& name) const override;
-  net::URLRequest* GetURLRequest() override;
-  AppCacheURLRequest* AsURLRequest() override;
-
- private:
-  net::URLRequest* url_request_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppCacheURLRequest);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_REQUEST_H_
diff --git a/content/browser/appcache/appcache_url_request_job.cc b/content/browser/appcache/appcache_url_request_job.cc
deleted file mode 100644
index b473d747..0000000
--- a/content/browser/appcache/appcache_url_request_job.cc
+++ /dev/null
@@ -1,301 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/appcache/appcache_url_request_job.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/location.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/browser/appcache/appcache.h"
-#include "content/browser/appcache/appcache_group.h"
-#include "content/browser/appcache/appcache_histograms.h"
-#include "content/browser/appcache/appcache_host.h"
-#include "content/browser/appcache/appcache_response.h"
-#include "content/browser/appcache/appcache_service_impl.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_response_headers.h"
-#include "net/log/net_log_event_type.h"
-#include "net/log/net_log_with_source.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_status.h"
-#include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
-#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
-
-namespace content {
-
-AppCacheURLRequestJob::~AppCacheURLRequestJob() {
-  if (storage_)
-    storage_->CancelDelegateCallbacks(this);
-}
-
-void AppCacheURLRequestJob::Kill() {
-  if (!has_been_killed_) {
-    has_been_killed_ = true;
-    reader_.reset();
-    handler_source_reader_.reset();
-    if (storage_) {
-      storage_->CancelDelegateCallbacks(this);
-      storage_ = nullptr;
-    }
-    host_ = nullptr;
-    info_ = nullptr;
-    cache_ = nullptr;
-    group_ = nullptr;
-    range_response_info_.reset();
-    net::URLRequestJob::Kill();
-    weak_factory_.InvalidateWeakPtrs();
-  }
-}
-
-bool AppCacheURLRequestJob::IsStarted() const {
-  return has_been_started_;
-}
-
-void AppCacheURLRequestJob::DeliverAppCachedResponse(const GURL& manifest_url,
-                                                     int64_t cache_id,
-                                                     const AppCacheEntry& entry,
-                                                     bool is_fallback) {
-  DCHECK(!has_delivery_orders());
-  DCHECK(entry.has_response_id());
-  delivery_type_ = DeliveryType::kAppCached;
-  manifest_url_ = manifest_url;
-  cache_id_ = cache_id;
-  entry_ = entry;
-  is_fallback_ = is_fallback;
-  MaybeBeginDelivery();
-}
-
-void AppCacheURLRequestJob::DeliverNetworkResponse() {
-  DCHECK(!has_delivery_orders());
-  delivery_type_ = DeliveryType::kNetwork;
-  storage_ = nullptr;  // not needed
-  MaybeBeginDelivery();
-}
-
-void AppCacheURLRequestJob::DeliverErrorResponse() {
-  DCHECK(!has_delivery_orders());
-  delivery_type_ = DeliveryType::kError;
-  storage_ = nullptr;  // not needed
-  MaybeBeginDelivery();
-}
-
-AppCacheURLRequestJob* AppCacheURLRequestJob::AsURLRequestJob() {
-  return this;
-}
-
-base::WeakPtr<AppCacheJob> AppCacheURLRequestJob::GetWeakPtr() {
-  return weak_factory_.GetWeakPtr();
-}
-
-base::WeakPtr<AppCacheURLRequestJob>
-AppCacheURLRequestJob::GetDerivedWeakPtr() {
-  return weak_factory_.GetWeakPtr();
-}
-
-AppCacheURLRequestJob::AppCacheURLRequestJob(
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate,
-    AppCacheStorage* storage,
-    AppCacheHost* host,
-    bool is_main_resource,
-    OnPrepareToRestartCallback restart_callback)
-    : net::URLRequestJob(request, network_delegate),
-      host_(host),
-      storage_(storage),
-      has_been_started_(false),
-      has_been_killed_(false),
-      cache_id_(blink::mojom::kAppCacheNoCacheId),
-      is_fallback_(false),
-      is_main_resource_(is_main_resource),
-      on_prepare_to_restart_callback_(std::move(restart_callback)) {
-  DCHECK(storage_);
-}
-
-void AppCacheURLRequestJob::MaybeBeginDelivery() {
-  if (IsStarted() && has_delivery_orders()) {
-    // Start asynchronously so that all error reporting and data
-    // callbacks happen as they would for network requests.
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(&AppCacheURLRequestJob::BeginDelivery,
-                                  GetDerivedWeakPtr()));
-  }
-}
-
-void AppCacheURLRequestJob::BeginDelivery() {
-  DCHECK(has_delivery_orders() && IsStarted());
-
-  if (has_been_killed())
-    return;
-
-  switch (delivery_type_) {
-    case DeliveryType::kNetwork:
-      // To fallthru to the network, we restart the request which will
-      // cause a new job to be created to retrieve the resource from the
-      // network. Our caller is responsible for arranging to not re-intercept
-      // the same request.
-      NotifyRestartRequired();
-      break;
-
-    case DeliveryType::kError:
-      request()->net_log().AddEvent(
-          net::NetLogEventType::APPCACHE_DELIVERING_ERROR_RESPONSE);
-      NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                             net::ERR_FAILED));
-      break;
-
-    case DeliveryType::kAppCached:
-      request()->net_log().AddEvent(
-          is_fallback_
-              ? net::NetLogEventType::APPCACHE_DELIVERING_FALLBACK_RESPONSE
-              : net::NetLogEventType::APPCACHE_DELIVERING_CACHED_RESPONSE);
-      storage_->LoadResponseInfo(manifest_url_, entry_.response_id(), this);
-      break;
-
-    default:
-      NOTREACHED();
-      break;
-  }
-}
-
-void AppCacheURLRequestJob::BeginErrorDelivery(const char* message) {
-  if (host_) {
-    host_->frontend()->LogMessage(blink::mojom::ConsoleMessageLevel::kError,
-                                  message);
-  }
-  delivery_type_ = DeliveryType::kError;
-  storage_ = nullptr;
-  BeginDelivery();
-}
-
-void AppCacheURLRequestJob::OnResponseInfoLoaded(
-    AppCacheResponseInfo* response_info,
-    int64_t response_id) {
-  DCHECK(IsDeliveringAppCacheResponse());
-  if (response_info) {
-    info_ = response_info;
-    reader_ =
-        storage_->CreateResponseReader(manifest_url_, entry_.response_id());
-
-    if (is_range_request())
-      SetupRangeResponse();
-
-    NotifyHeadersComplete();
-  } else {
-    if (storage_->service()->storage() == storage_) {
-      // A resource that is expected to be in the appcache is missing.
-      // See http://code.google.com/p/chromium/issues/detail?id=50657
-      // Instead of failing the request, we restart the request. The retry
-      // attempt will fallthru to the network instead of trying to load
-      // from the appcache.
-      storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
-                                                 entry_.response_id());
-    }
-    cache_entry_not_found_ = true;
-
-    // We fallback to the network unless this job was falling back to the
-    // appcache from the network which had already failed in some way.
-    if (!is_fallback_)
-      NotifyRestartRequired();
-    else
-      BeginErrorDelivery("failed to load appcache response info");
-  }
-}
-
-const net::HttpResponseInfo* AppCacheURLRequestJob::http_info() const {
-  if (!info_.get())
-    return nullptr;
-  if (range_response_info_)
-    return range_response_info_.get();
-  return &info_->http_response_info();
-}
-
-void AppCacheURLRequestJob::OnReadComplete(int result) {
-  DCHECK(IsDeliveringAppCacheResponse());
-  if (result < 0) {
-    if (storage_->service()->storage() == storage_) {
-      storage_->service()->CheckAppCacheResponse(manifest_url_, cache_id_,
-                                                 entry_.response_id());
-    }
-  }
-  ReadRawDataComplete(result);
-}
-
-// net::URLRequestJob overrides ------------------------------------------------
-
-void AppCacheURLRequestJob::Start() {
-  DCHECK(!IsStarted());
-  has_been_started_ = true;
-  start_time_tick_ = base::TimeTicks::Now();
-  MaybeBeginDelivery();
-}
-
-net::LoadState AppCacheURLRequestJob::GetLoadState() const {
-  if (!IsStarted())
-    return net::LOAD_STATE_IDLE;
-  if (!has_delivery_orders())
-    return net::LOAD_STATE_WAITING_FOR_APPCACHE;
-  if (delivery_type_ != DeliveryType::kAppCached)
-    return net::LOAD_STATE_IDLE;
-  if (!info_.get())
-    return net::LOAD_STATE_WAITING_FOR_APPCACHE;
-  if (reader_.get() && reader_->IsReadPending())
-    return net::LOAD_STATE_READING_RESPONSE;
-  return net::LOAD_STATE_IDLE;
-}
-
-bool AppCacheURLRequestJob::GetMimeType(std::string* mime_type) const {
-  if (!http_info())
-    return false;
-  return http_info()->headers->GetMimeType(mime_type);
-}
-
-bool AppCacheURLRequestJob::GetCharset(std::string* charset) {
-  if (!http_info())
-    return false;
-  return http_info()->headers->GetCharset(charset);
-}
-
-void AppCacheURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
-  if (!http_info())
-    return;
-  *info = *http_info();
-}
-
-int AppCacheURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
-  DCHECK(IsDeliveringAppCacheResponse());
-  DCHECK_NE(buf_size, 0);
-  DCHECK(!reader_->IsReadPending());
-  reader_->ReadData(buf, buf_size,
-                    base::BindOnce(&AppCacheURLRequestJob::OnReadComplete,
-                                   base::Unretained(this)));
-  return net::ERR_IO_PENDING;
-}
-
-net::IPEndPoint AppCacheURLRequestJob::GetResponseRemoteEndpoint() const {
-  if (!http_info())
-    return net::IPEndPoint();
-  return http_info()->remote_endpoint;
-}
-
-void AppCacheURLRequestJob::SetExtraRequestHeaders(
-    const net::HttpRequestHeaders& headers) {
-  InitializeRangeRequestInfo(headers);
-}
-
-void AppCacheURLRequestJob::NotifyRestartRequired() {
-  std::move(on_prepare_to_restart_callback_).Run();
-  URLRequestJob::NotifyRestartRequired();
-}
-
-}  // namespace content
diff --git a/content/browser/appcache/appcache_url_request_job.h b/content/browser/appcache/appcache_url_request_job.h
deleted file mode 100644
index 5490033b..0000000
--- a/content/browser/appcache/appcache_url_request_job.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_URL_REQUEST_JOB_H_
-#define CONTENT_BROWSER_APPCACHE_APPCACHE_URL_REQUEST_JOB_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/callback.h"
-#include "content/browser/appcache/appcache_entry.h"
-#include "content/browser/appcache/appcache_job.h"
-#include "content/browser/appcache/appcache_storage.h"
-#include "content/common/content_export.h"
-#include "net/base/ip_endpoint.h"
-#include "net/url_request/url_request_job.h"
-
-namespace net {
-class GrowableIOBuffer;
-}
-
-namespace content {
-class AppCacheHost;
-class AppCacheRequestHandlerTest;
-namespace appcache_url_request_job_unittest {
-class AppCacheURLRequestJobTest;
-}
-
-// A net::URLRequestJob derivative that knows how to return a response stored
-// in the appcache.
-class CONTENT_EXPORT AppCacheURLRequestJob : public AppCacheJob,
-                                             public AppCacheStorage::Delegate,
-                                             public net::URLRequestJob {
- public:
-  // Use AppCacheRequestHandler::CreateJob() instead of calling this directly.
-  //
-  // |restart_callback| will be invoked before the request is restarted. The
-  // caller can use this opportunity to grab state from the
-  // AppCacheURLRequestJob to determine how it should behave when the request is
-  // restarted.
-  //
-  // The constructor is exposed for std::make_unique.
-  AppCacheURLRequestJob(net::URLRequest* request,
-                        net::NetworkDelegate* network_delegate,
-                        AppCacheStorage* storage,
-                        AppCacheHost* host,
-                        bool is_main_resource,
-                        base::OnceClosure restart_callback);
-
-  ~AppCacheURLRequestJob() override;
-
-  // AppCacheJob overrides.
-  bool IsStarted() const override;
-  void DeliverAppCachedResponse(const GURL& manifest_url,
-                                int64_t cache_id,
-                                const AppCacheEntry& entry,
-                                bool is_fallback) override;
-  void DeliverNetworkResponse() override;
-  void DeliverErrorResponse() override;
-  AppCacheURLRequestJob* AsURLRequestJob() override;
-  base::WeakPtr<AppCacheJob> GetWeakPtr() override;
-  base::WeakPtr<AppCacheURLRequestJob> GetDerivedWeakPtr();
-
-  // Accessors for the info about the appcached response, if any,
-  // that this job has been instructed to deliver. These are only
-  // valid to call if is_delivering_appcache_response.
-  const GURL& manifest_url() const { return manifest_url_; }
-  int64_t cache_id() const { return cache_id_; }
-  const AppCacheEntry& entry() const { return entry_; }
-
-  // Returns true if the job has been killed.
-  bool has_been_killed() const {
-    return has_been_killed_;
-  }
-
- private:
-  friend class AppCacheRequestHandlerTest;
-  friend class appcache_url_request_job_unittest::AppCacheURLRequestJobTest;
-  friend class AppCacheRequestHandler;
-
-  using OnPrepareToRestartCallback = base::OnceClosure;
-
-  // Returns true if one of the Deliver methods has been called.
-  bool has_delivery_orders() const { return !IsWaiting(); }
-
-  void MaybeBeginDelivery();
-  void BeginDelivery();
-  void BeginErrorDelivery(const char* message);
-
-  // AppCacheStorage::Delegate methods
-  void OnResponseInfoLoaded(AppCacheResponseInfo* response_info,
-                            int64_t response_id) override;
-
-  const net::HttpResponseInfo* http_info() const;
-
-  // AppCacheResponseReader completion callback
-  void OnReadComplete(int result);
-
-  // net::URLRequestJob methods, see url_request_job.h for doc comments
-  void Start() override;
-  void Kill() override;
-  net::LoadState GetLoadState() const override;
-  bool GetCharset(std::string* charset) override;
-  void GetResponseInfo(net::HttpResponseInfo* info) override;
-  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
-  net::IPEndPoint GetResponseRemoteEndpoint() const override;
-
-  // Sets extra request headers for Job types that support request headers.
-  // This is how we get informed of range-requests.
-  void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
-
-  // FilterContext methods
-  bool GetMimeType(std::string* mime_type) const override;
-
-  // Invokes |prepare_to_restart_callback_| and then calls
-  // net::URLRequestJob::NotifyRestartRequired.
-  void NotifyRestartRequired();
-
-  AppCacheHost* host_;
-  AppCacheStorage* storage_;
-  base::TimeTicks start_time_tick_;
-  bool has_been_started_;
-  bool has_been_killed_;
-  GURL manifest_url_;
-  int64_t cache_id_;
-  AppCacheEntry entry_;
-  bool is_fallback_;
-  bool is_main_resource_;  // Used for histogram logging.
-  scoped_refptr<net::GrowableIOBuffer> handler_source_buffer_;
-  std::unique_ptr<AppCacheResponseReader> handler_source_reader_;
-  scoped_refptr<AppCache> cache_;
-  scoped_refptr<AppCacheGroup> group_;
-  OnPrepareToRestartCallback on_prepare_to_restart_callback_;
-  base::WeakPtrFactory<AppCacheURLRequestJob> weak_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(AppCacheURLRequestJob);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_APPCACHE_APPCACHE_URL_REQUEST_JOB_H_
diff --git a/content/browser/appcache/appcache_url_request_job_unittest.cc b/content/browser/appcache/appcache_url_request_job_unittest.cc
deleted file mode 100644
index 07bd247..0000000
--- a/content/browser/appcache/appcache_url_request_job_unittest.cc
+++ /dev/null
@@ -1,922 +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 "content/browser/appcache/appcache_url_request_job.h"
-
-#include <stdint.h>
-#include <string.h>
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/containers/stack.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_pump_type.h"
-#include "base/pickle.h"
-#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/test/scoped_task_environment.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/browser/appcache/appcache_response.h"
-#include "content/browser/appcache/mock_appcache_service.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/request_priority.h"
-#include "net/http/http_response_headers.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_error_job.h"
-#include "net/url_request/url_request_job_factory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h"
-#include "url/gurl.h"
-
-using net::IOBuffer;
-using net::WrappedIOBuffer;
-
-namespace content {
-namespace appcache_url_request_job_unittest {
-
-const char kHttpBasicHeaders[] = "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
-const char kHttpBasicBody[] = "Hello";
-
-const int kNumBlocks = 4;
-const int kBlockSize = 1024;
-
-// Used as an AppCacheURLRequestJob::OnPrepareToRestartCallback for requests
-// that aren't expected to be restarted.
-void ExpectNotRestarted() {
-  ADD_FAILURE() << "Request unexpectedly restarted";
-}
-
-// Used as an AppCacheURLRequestJob::OnPrepareToRestartCallback for requests
-// that are expected to be restarted. Allows tests to verify it was called by
-// setting |*value| to true when invoked.
-void SetIfCalled(bool* value) {
-  // Expected to be called only once.
-  EXPECT_FALSE(*value);
-  *value = true;
-}
-
-class MockURLRequestJobFactory : public net::URLRequestJobFactory {
- public:
-  MockURLRequestJobFactory() = default;
-
-  ~MockURLRequestJobFactory() override { DCHECK(!job_); }
-
-  void SetJob(std::unique_ptr<net::URLRequestJob> job) {
-    job_ = std::move(job);
-  }
-
-  bool has_job() const { return job_.get() != nullptr; }
-
-  // net::URLRequestJobFactory implementation.
-  net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
-      const std::string& scheme,
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    if (job_) {
-      return job_.release();
-    } else {
-      return new net::URLRequestErrorJob(request,
-                                         network_delegate,
-                                         net::ERR_INTERNET_DISCONNECTED);
-    }
-  }
-
-  net::URLRequestJob* MaybeInterceptRedirect(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate,
-      const GURL& location) const override {
-    return nullptr;
-  }
-
-  net::URLRequestJob* MaybeInterceptResponse(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return nullptr;
-  }
-
-  bool IsHandledProtocol(const std::string& scheme) const override {
-    return scheme == "http";
-  }
-
-  bool IsSafeRedirectTarget(const GURL& location) const override {
-    return false;
-  }
-
- private:
-  // This is mutable because MaybeCreateJobWithProtocolHandler is const.
-  mutable std::unique_ptr<net::URLRequestJob> job_;
-};
-
-class AppCacheURLRequestJobTest : public testing::Test {
- public:
-
-  // Test Harness -------------------------------------------------------------
-  // TODO(michaeln): share this test harness with AppCacheResponseTest
-
-  class MockStorageDelegate : public AppCacheStorage::Delegate {
-   public:
-    explicit MockStorageDelegate(AppCacheURLRequestJobTest* test)
-        : loaded_info_id_(0), test_(test) {
-    }
-
-    void OnResponseInfoLoaded(AppCacheResponseInfo* info,
-                              int64_t response_id) override {
-      loaded_info_ = info;
-      loaded_info_id_ = response_id;
-      test_->ScheduleNextTask();
-    }
-
-    scoped_refptr<AppCacheResponseInfo> loaded_info_;
-    int64_t loaded_info_id_;
-    AppCacheURLRequestJobTest* test_;
-  };
-
-  class MockURLRequestDelegate : public net::URLRequest::Delegate {
-   public:
-    explicit MockURLRequestDelegate(AppCacheURLRequestJobTest* test)
-        : test_(test),
-          received_data_(
-              base::MakeRefCounted<net::IOBuffer>(kNumBlocks * kBlockSize)),
-          did_receive_headers_(false),
-          amount_received_(0),
-          kill_after_amount_received_(0),
-          kill_with_io_pending_(false),
-          request_status_(net::ERR_IO_PENDING) {}
-
-    void OnResponseStarted(net::URLRequest* request, int net_error) override {
-      DCHECK_NE(net::ERR_IO_PENDING, net_error);
-      amount_received_ = 0;
-      did_receive_headers_ = false;
-      request_status_ = net_error;
-      if (net_error == net::OK) {
-        EXPECT_TRUE(request->response_headers());
-        did_receive_headers_ = true;
-        received_info_ = request->response_info();
-        ReadSome(request);
-      } else {
-        RequestComplete();
-      }
-    }
-
-    void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
-      if (bytes_read > 0) {
-        amount_received_ += bytes_read;
-        request_status_ = net::OK;
-
-        if (kill_after_amount_received_ && !kill_with_io_pending_) {
-          if (amount_received_ >= kill_after_amount_received_) {
-            request->Cancel();
-            return;
-          }
-        }
-
-        ReadSome(request);
-
-        if (kill_after_amount_received_ && kill_with_io_pending_) {
-          if (amount_received_ >= kill_after_amount_received_) {
-            request->Cancel();
-            return;
-          }
-        }
-      } else {
-        request_status_ = bytes_read;
-        RequestComplete();
-      }
-    }
-
-    void ReadSome(net::URLRequest* request) {
-      DCHECK(amount_received_ + kBlockSize <= kNumBlocks * kBlockSize);
-      scoped_refptr<IOBuffer> wrapped_buffer =
-          base::MakeRefCounted<net::WrappedIOBuffer>(received_data_->data() +
-                                                     amount_received_);
-      EXPECT_EQ(net::ERR_IO_PENDING,
-                request->Read(wrapped_buffer.get(), kBlockSize));
-    }
-
-    void RequestComplete() {
-      test_->ScheduleNextTask();
-    }
-
-    int request_status() { return request_status_; }
-
-    AppCacheURLRequestJobTest* test_;
-    net::HttpResponseInfo received_info_;
-    scoped_refptr<net::IOBuffer> received_data_;
-    bool did_receive_headers_;
-    int amount_received_;
-    int kill_after_amount_received_;
-    bool kill_with_io_pending_;
-    int request_status_;
-  };
-
-  // Helper callback to run a test on our io_thread. The io_thread is spun up
-  // once and reused for all tests.
-  template <class Method>
-  void MethodWrapper(Method method) {
-    SetUpTest();
-    (this->*method)();
-  }
-
-  static void SetUpTestCase() {
-    scoped_task_environment_ =
-        std::make_unique<base::test::ScopedTaskEnvironment>();
-    io_thread_ =
-        std::make_unique<base::Thread>("AppCacheURLRequestJobTest Thread");
-    base::Thread::Options options(base::MessagePumpType::IO, 0);
-    io_thread_->StartWithOptions(options);
-  }
-
-  static void TearDownTestCase() {
-    io_thread_.reset();
-    scoped_task_environment_.reset();
-  }
-
-  AppCacheURLRequestJobTest() {}
-
-  template <class Method>
-  void RunTestOnIOThread(Method method) {
-    test_finished_event_ = std::make_unique<base::WaitableEvent>(
-        base::WaitableEvent::ResetPolicy::AUTOMATIC,
-        base::WaitableEvent::InitialState::NOT_SIGNALED);
-    io_thread_->task_runner()->PostTask(
-        FROM_HERE,
-        base::BindOnce(&AppCacheURLRequestJobTest::MethodWrapper<Method>,
-                       base::Unretained(this), method));
-    test_finished_event_->Wait();
-  }
-
-  void SetUpTest() {
-    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
-    DCHECK(task_stack_.empty());
-
-    storage_delegate_ = std::make_unique<MockStorageDelegate>(this);
-    service_ = std::make_unique<MockAppCacheService>();
-    expected_read_result_ = 0;
-    expected_write_result_ = 0;
-    written_response_id_ = 0;
-    reader_deletion_count_down_ = 0;
-    writer_deletion_count_down_ = 0;
-
-    restart_callback_invoked_ = false;
-
-    url_request_delegate_ = std::make_unique<MockURLRequestDelegate>(this);
-    job_factory_ = std::make_unique<MockURLRequestJobFactory>();
-    empty_context_ = std::make_unique<net::URLRequestContext>();
-    empty_context_->set_job_factory(job_factory_.get());
-  }
-
-  void TearDownTest() {
-    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
-    request_.reset();
-
-    while (!task_stack_.empty())
-      task_stack_.pop();
-
-    reader_.reset();
-    read_buffer_ = nullptr;
-    read_info_buffer_ = nullptr;
-    writer_.reset();
-    write_buffer_ = nullptr;
-    write_info_buffer_ = nullptr;
-    storage_delegate_.reset();
-    service_.reset();
-
-    DCHECK(!job_factory_->has_job());
-    empty_context_.reset();
-    job_factory_.reset();
-    url_request_delegate_.reset();
-  }
-
-  void TestFinished() {
-    // We unwind the stack prior to finishing up to let stack
-    // based objects get deleted.
-    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(&AppCacheURLRequestJobTest::TestFinishedUnwound,
-                       base::Unretained(this)));
-  }
-
-  void TestFinishedUnwound() {
-    TearDownTest();
-    test_finished_event_->Signal();
-  }
-
-  void PushNextTask(base::OnceClosure task) {
-    task_stack_.push(
-        std::pair<base::OnceClosure, bool>(std::move(task), false));
-  }
-
-  void PushNextTaskAsImmediate(base::OnceClosure task) {
-    task_stack_.push(std::pair<base::OnceClosure, bool>(std::move(task), true));
-  }
-
-  void ScheduleNextTask() {
-    DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
-    if (task_stack_.empty()) {
-      TestFinished();
-      return;
-    }
-    base::OnceClosure task = std::move(task_stack_.top().first);
-    bool immediate = task_stack_.top().second;
-    task_stack_.pop();
-    if (immediate)
-      std::move(task).Run();
-    else
-      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(task));
-  }
-
-  // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
-
-  void WriteBasicResponse() {
-    scoped_refptr<IOBuffer> body =
-        base::MakeRefCounted<WrappedIOBuffer>(kHttpBasicBody);
-    std::string raw_headers(kHttpBasicHeaders, base::size(kHttpBasicHeaders));
-    WriteResponse(
-        MakeHttpResponseInfo(raw_headers), body.get(), strlen(kHttpBasicBody));
-  }
-
-  void WriteResponse(std::unique_ptr<net::HttpResponseInfo> head,
-                     IOBuffer* body,
-                     int body_len) {
-    DCHECK(body);
-    scoped_refptr<IOBuffer> body_ref(body);
-    PushNextTask(base::BindOnce(&AppCacheURLRequestJobTest::WriteResponseBody,
-                                base::Unretained(this), body_ref, body_len));
-    WriteResponseHead(std::move(head));
-  }
-
-  void WriteResponseHead(std::unique_ptr<net::HttpResponseInfo> head) {
-    EXPECT_FALSE(writer_->IsWritePending());
-    expected_write_result_ = GetHttpResponseInfoSize(*head);
-    write_info_buffer_ =
-        base::MakeRefCounted<HttpResponseInfoIOBuffer>(std::move(head));
-    writer_->WriteInfo(
-        write_info_buffer_.get(),
-        base::BindOnce(&AppCacheURLRequestJobTest::OnWriteInfoComplete,
-                       base::Unretained(this)));
-  }
-
-  void WriteResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
-    EXPECT_FALSE(writer_->IsWritePending());
-    write_buffer_ = io_buffer;
-    expected_write_result_ = buf_len;
-    writer_->WriteData(
-        write_buffer_.get(), buf_len,
-        base::BindOnce(&AppCacheURLRequestJobTest::OnWriteComplete,
-                       base::Unretained(this)));
-  }
-
-  void ReadResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
-    EXPECT_FALSE(reader_->IsReadPending());
-    read_buffer_ = io_buffer;
-    expected_read_result_ = buf_len;
-    reader_->ReadData(read_buffer_.get(), buf_len,
-                      base::BindOnce(&AppCacheURLRequestJobTest::OnReadComplete,
-                                     base::Unretained(this)));
-  }
-
-  // AppCacheResponseReader / Writer completion callbacks
-
-  void OnWriteInfoComplete(int result) {
-    EXPECT_FALSE(writer_->IsWritePending());
-    EXPECT_EQ(expected_write_result_, result);
-    ScheduleNextTask();
-  }
-
-  void OnWriteComplete(int result) {
-    EXPECT_FALSE(writer_->IsWritePending());
-    EXPECT_EQ(expected_write_result_, result);
-    ScheduleNextTask();
-  }
-
-  void OnReadInfoComplete(int result) {
-    EXPECT_FALSE(reader_->IsReadPending());
-    EXPECT_EQ(expected_read_result_, result);
-    ScheduleNextTask();
-  }
-
-  void OnReadComplete(int result) {
-    EXPECT_FALSE(reader_->IsReadPending());
-    EXPECT_EQ(expected_read_result_, result);
-    ScheduleNextTask();
-  }
-
-  // Helpers to work with HttpResponseInfo objects
-
-  std::unique_ptr<net::HttpResponseInfo> MakeHttpResponseInfo(
-      const std::string& raw_headers) {
-    std::unique_ptr<net::HttpResponseInfo> info =
-        std::make_unique<net::HttpResponseInfo>();
-    info->request_time = base::Time::Now();
-    info->response_time = base::Time::Now();
-    info->was_cached = false;
-    info->headers = base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers);
-    return info;
-  }
-
-  int GetHttpResponseInfoSize(const net::HttpResponseInfo& info) {
-    base::Pickle pickle = PickleHttpResonseInfo(info);
-    return pickle.size();
-  }
-
-  bool CompareHttpResponseInfos(const net::HttpResponseInfo& info1,
-                                const net::HttpResponseInfo& info2) {
-    base::Pickle pickle1 = PickleHttpResonseInfo(info1);
-    base::Pickle pickle2 = PickleHttpResonseInfo(info2);
-    return (pickle1.size() == pickle2.size()) &&
-           (0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size()));
-  }
-
-  base::Pickle PickleHttpResonseInfo(const net::HttpResponseInfo& info) {
-    const bool kSkipTransientHeaders = true;
-    const bool kTruncated = false;
-    base::Pickle pickle;
-    info.Persist(&pickle, kSkipTransientHeaders, kTruncated);
-    return pickle;
-  }
-
-  // Helpers to fill and verify blocks of memory with a value
-
-  void FillData(char value, char* data, int data_len) {
-    memset(data, value, data_len);
-  }
-
-  bool CheckData(char value, const char* data, int data_len) {
-    for (int i = 0; i < data_len; ++i, ++data) {
-      if (*data != value)
-        return false;
-    }
-    return true;
-  }
-
-  // Individual Tests ---------------------------------------------------------
-  // Some of the individual tests involve multiple async steps. Each test
-  // is delineated with a section header.
-
-  // Basic -------------------------------------------------------------------
-  void Basic() {
-    AppCacheStorage* storage = service_->storage();
-    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
-                                             net::DEFAULT_PRIORITY, nullptr,
-                                             TRAFFIC_ANNOTATION_FOR_TESTS);
-
-    // Create an instance and see that it looks as expected.
-
-    auto job = std::make_unique<AppCacheURLRequestJob>(
-        request_.get(), nullptr, storage, nullptr, false,
-        base::BindOnce(&ExpectNotRestarted));
-    EXPECT_TRUE(job->IsWaiting());
-    EXPECT_FALSE(job->IsDeliveringAppCacheResponse());
-    EXPECT_FALSE(job->IsDeliveringNetworkResponse());
-    EXPECT_FALSE(job->IsDeliveringErrorResponse());
-    EXPECT_FALSE(job->IsStarted());
-    EXPECT_FALSE(job->has_been_killed());
-    EXPECT_EQ(GURL(), job->manifest_url());
-    EXPECT_EQ(blink::mojom::kAppCacheNoCacheId, job->cache_id());
-    EXPECT_FALSE(job->entry().has_response_id());
-
-    TestFinished();
-  }
-
-  // DeliveryOrders -----------------------------------------------------
-  void DeliveryOrders() {
-    AppCacheStorage* storage = service_->storage();
-    std::unique_ptr<net::URLRequest> request(empty_context_->CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, nullptr,
-        TRAFFIC_ANNOTATION_FOR_TESTS));
-
-    // Create an instance, give it a delivery order and see that
-    // it looks as expected.
-
-    auto job = std::make_unique<AppCacheURLRequestJob>(
-        request.get(), nullptr, storage, nullptr, false,
-        base::BindOnce(&ExpectNotRestarted));
-    job->DeliverErrorResponse();
-    EXPECT_TRUE(job->IsDeliveringErrorResponse());
-    EXPECT_FALSE(job->IsStarted());
-
-    job = std::make_unique<AppCacheURLRequestJob>(
-        request.get(), nullptr, storage, nullptr, false,
-        base::BindOnce(&ExpectNotRestarted));
-    job->DeliverNetworkResponse();
-    EXPECT_TRUE(job->IsDeliveringNetworkResponse());
-    EXPECT_FALSE(job->IsStarted());
-
-    job = std::make_unique<AppCacheURLRequestJob>(
-        request.get(), nullptr, storage, nullptr, false,
-        base::BindOnce(&ExpectNotRestarted));
-    const GURL kManifestUrl("http://blah/");
-    const int64_t kCacheId(1);
-    const AppCacheEntry kEntry(AppCacheEntry::EXPLICIT, 1);
-    job->DeliverAppCachedResponse(kManifestUrl, kCacheId, kEntry, false);
-    EXPECT_FALSE(job->IsWaiting());
-    EXPECT_TRUE(job->IsDeliveringAppCacheResponse());
-    EXPECT_FALSE(job->IsStarted());
-    EXPECT_EQ(kManifestUrl, job->manifest_url());
-    EXPECT_EQ(kCacheId, job->cache_id());
-    EXPECT_EQ(kEntry.types(), job->entry().types());
-    EXPECT_EQ(kEntry.response_id(), job->entry().response_id());
-
-    TestFinished();
-  }
-
-  // DeliverNetworkResponse --------------------------------------------------
-
-  void DeliverNetworkResponse() {
-    // This test has async steps.
-    PushNextTask(
-        base::BindOnce(&AppCacheURLRequestJobTest::VerifyDeliverNetworkResponse,
-                       base::Unretained(this)));
-
-    AppCacheStorage* storage = service_->storage();
-    request_ = empty_context_->CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY,
-        url_request_delegate_.get(), TRAFFIC_ANNOTATION_FOR_TESTS);
-
-    // Set up to create an AppCacheURLRequestJob with orders to deliver
-    // a network response.
-    auto mock_job = std::make_unique<AppCacheURLRequestJob>(
-        request_.get(), nullptr, storage, nullptr, false,
-        base::BindOnce(&SetIfCalled, &restart_callback_invoked_));
-    mock_job->DeliverNetworkResponse();
-    EXPECT_TRUE(mock_job->IsDeliveringNetworkResponse());
-    EXPECT_FALSE(mock_job->IsStarted());
-    job_factory_->SetJob(std::move(mock_job));
-
-    // Start the request.
-    request_->Start();
-
-    // The job should have been picked up.
-    EXPECT_FALSE(job_factory_->has_job());
-    // Completion is async.
-  }
-
-  void VerifyDeliverNetworkResponse() {
-    EXPECT_EQ(net::ERR_INTERNET_DISCONNECTED,
-              url_request_delegate_->request_status());
-    EXPECT_TRUE(restart_callback_invoked_);
-    TestFinished();
-  }
-
-  // DeliverErrorResponse --------------------------------------------------
-
-  void DeliverErrorResponse() {
-    // This test has async steps.
-    PushNextTask(
-        base::BindOnce(&AppCacheURLRequestJobTest::VerifyDeliverErrorResponse,
-                       base::Unretained(this)));
-
-    AppCacheStorage* storage = service_->storage();
-    request_ = empty_context_->CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY,
-        url_request_delegate_.get(), TRAFFIC_ANNOTATION_FOR_TESTS);
-
-    // Setup to create an AppCacheURLRequestJob with orders to deliver
-    // a network response.
-    auto mock_job = std::make_unique<AppCacheURLRequestJob>(
-        request_.get(), nullptr, storage, nullptr, false,
-        base::BindOnce(&ExpectNotRestarted));
-    mock_job->DeliverErrorResponse();
-    EXPECT_TRUE(mock_job->IsDeliveringErrorResponse());
-    EXPECT_FALSE(mock_job->IsStarted());
-    job_factory_->SetJob(std::move(mock_job));
-
-    // Start the request.
-    request_->Start();
-
-    // The job should have been picked up.
-    EXPECT_FALSE(job_factory_->has_job());
-    // Completion is async.
-  }
-
-  void VerifyDeliverErrorResponse() {
-    EXPECT_EQ(net::ERR_FAILED, url_request_delegate_->request_status());
-    TestFinished();
-  }
-
-  // DeliverSmallAppCachedResponse --------------------------------------
-  // "Small" being small enough to read completely in a single
-  // request->Read call.
-
-  void DeliverSmallAppCachedResponse() {
-    // This test has several async steps.
-    // 1. Write a small response to response storage.
-    // 2. Use net::URLRequest to retrieve it.
-    // 3. Verify we received what we expected to receive.
-
-    PushNextTask(base::BindOnce(
-        &AppCacheURLRequestJobTest::VerifyDeliverSmallAppCachedResponse,
-        base::Unretained(this)));
-    PushNextTask(
-        base::BindOnce(&AppCacheURLRequestJobTest::RequestAppCachedResource,
-                       base::Unretained(this), false));
-
-    writer_ = service_->storage()->CreateResponseWriter(GURL());
-    written_response_id_ = writer_->response_id();
-    WriteBasicResponse();
-    // Continues async
-  }
-
-  void RequestAppCachedResource(bool start_after_delivery_orders) {
-    AppCacheStorage* storage = service_->storage();
-    request_ = empty_context_->CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY,
-        url_request_delegate_.get(), TRAFFIC_ANNOTATION_FOR_TESTS);
-
-    // Setup to create an AppCacheURLRequestJob with orders to deliver
-    // a network response.
-    auto job = std::make_unique<AppCacheURLRequestJob>(
-        request_.get(), nullptr, storage, nullptr, false,
-        base::BindOnce(&ExpectNotRestarted));
-
-    if (start_after_delivery_orders) {
-      job->DeliverAppCachedResponse(
-          GURL(), 111,
-          AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_), false);
-      EXPECT_TRUE(job->IsDeliveringAppCacheResponse());
-    }
-
-    // Start the request.
-    EXPECT_FALSE(job->IsStarted());
-    base::WeakPtr<AppCacheJob> weak_job = job->GetWeakPtr();
-    job_factory_->SetJob(std::move(job));
-    request_->Start();
-    EXPECT_FALSE(job_factory_->has_job());
-    ASSERT_TRUE(weak_job);
-    EXPECT_TRUE(weak_job->IsStarted());
-
-    if (!start_after_delivery_orders) {
-      weak_job->DeliverAppCachedResponse(
-          GURL(), 111,
-          AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_), false);
-      ASSERT_TRUE(weak_job);
-      EXPECT_TRUE(weak_job->IsDeliveringAppCacheResponse());
-    }
-
-    // Completion is async.
-  }
-
-  void VerifyDeliverSmallAppCachedResponse() {
-    EXPECT_EQ(net::OK, url_request_delegate_->request_status());
-    EXPECT_TRUE(CompareHttpResponseInfos(
-        *write_info_buffer_->http_info, url_request_delegate_->received_info_));
-    EXPECT_EQ(5, url_request_delegate_->amount_received_);
-    EXPECT_EQ(0, memcmp(kHttpBasicBody,
-                        url_request_delegate_->received_data_->data(),
-                        strlen(kHttpBasicBody)));
-    TestFinished();
-  }
-
-  // DeliverLargeAppCachedResponse --------------------------------------
-  // "Large" enough to require multiple calls to request->Read to complete.
-
-  void DeliverLargeAppCachedResponse() {
-    // This test has several async steps.
-    // 1. Write a large response to response storage.
-    // 2. Use net::URLRequest to retrieve it.
-    // 3. Verify we received what we expected to receive.
-
-    PushNextTask(base::BindOnce(
-        &AppCacheURLRequestJobTest::VerifyDeliverLargeAppCachedResponse,
-        base::Unretained(this)));
-    PushNextTask(
-        base::BindOnce(&AppCacheURLRequestJobTest::RequestAppCachedResource,
-                       base::Unretained(this), true));
-
-    writer_ = service_->storage()->CreateResponseWriter(GURL());
-    written_response_id_ = writer_->response_id();
-    WriteLargeResponse();
-    // Continues async
-  }
-
-  void WriteLargeResponse() {
-    // 3, 1k blocks
-    static const char kHttpHeaders[] =
-        "HTTP/1.0 200 OK\0Content-Length: 3072\0\0";
-    scoped_refptr<IOBuffer> body =
-        base::MakeRefCounted<IOBuffer>(kBlockSize * 3);
-    char* p = body->data();
-    for (int i = 0; i < 3; ++i, p += kBlockSize)
-      FillData(i + 1, p, kBlockSize);
-    std::string raw_headers(kHttpHeaders, base::size(kHttpHeaders));
-    WriteResponse(
-        MakeHttpResponseInfo(raw_headers), body.get(), kBlockSize * 3);
-  }
-
-  void VerifyDeliverLargeAppCachedResponse() {
-    EXPECT_EQ(net::OK, url_request_delegate_->request_status());
-    EXPECT_TRUE(CompareHttpResponseInfos(
-        *write_info_buffer_->http_info, url_request_delegate_->received_info_));
-    EXPECT_EQ(3072, url_request_delegate_->amount_received_);
-    char* p = url_request_delegate_->received_data_->data();
-    for (int i = 0; i < 3; ++i, p += kBlockSize)
-      EXPECT_TRUE(CheckData(i + 1, p, kBlockSize));
-    TestFinished();
-  }
-
-  // DeliverPartialResponse --------------------------------------
-
-  void DeliverPartialResponse() {
-    // This test has several async steps.
-    // 1. Write a small response to response storage.
-    // 2. Use net::URLRequest to retrieve it a subset using a range request
-    // 3. Verify we received what we expected to receive.
-    PushNextTask(
-        base::BindOnce(&AppCacheURLRequestJobTest::VerifyDeliverPartialResponse,
-                       base::Unretained(this)));
-    PushNextTask(base::BindOnce(&AppCacheURLRequestJobTest::MakeRangeRequest,
-                                base::Unretained(this)));
-    writer_ = service_->storage()->CreateResponseWriter(GURL());
-    written_response_id_ = writer_->response_id();
-    WriteBasicResponse();
-    // Continues async
-  }
-
-  void MakeRangeRequest() {
-    AppCacheStorage* storage = service_->storage();
-    request_ = empty_context_->CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY,
-        url_request_delegate_.get(), TRAFFIC_ANNOTATION_FOR_TESTS);
-
-    // Request a range, the 3 middle chars out of 'Hello'
-    net::HttpRequestHeaders extra_headers;
-    extra_headers.SetHeader("Range", "bytes= 1-3");
-    request_->SetExtraRequestHeaders(extra_headers);
-
-    // Create job with orders to deliver an appcached entry.
-    auto job = std::make_unique<AppCacheURLRequestJob>(
-        request_.get(), nullptr, storage, nullptr, false,
-        base::BindOnce(&ExpectNotRestarted));
-    job->DeliverAppCachedResponse(
-        GURL(), 111,
-        AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_), false);
-    EXPECT_TRUE(job->IsDeliveringAppCacheResponse());
-
-    // Start the request.
-    EXPECT_FALSE(job->IsStarted());
-    job_factory_->SetJob(std::move(job));
-    request_->Start();
-    EXPECT_FALSE(job_factory_->has_job());
-    // Completion is async.
-  }
-
-  void VerifyDeliverPartialResponse() {
-    EXPECT_EQ(net::OK, url_request_delegate_->request_status());
-    EXPECT_EQ(3, url_request_delegate_->amount_received_);
-    EXPECT_EQ(0, memcmp(kHttpBasicBody + 1,
-                        url_request_delegate_->received_data_->data(),
-                        3));
-    net::HttpResponseHeaders* headers =
-        url_request_delegate_->received_info_.headers.get();
-    EXPECT_EQ(206, headers->response_code());
-    EXPECT_EQ(3, headers->GetContentLength());
-    int64_t range_start, range_end, object_size;
-    EXPECT_TRUE(
-        headers->GetContentRangeFor206(&range_start, &range_end, &object_size));
-    EXPECT_EQ(1, range_start);
-    EXPECT_EQ(3, range_end);
-    EXPECT_EQ(5, object_size);
-    TestFinished();
-  }
-
-  // CancelRequest --------------------------------------
-
-  void CancelRequest() {
-    // This test has several async steps.
-    // 1. Write a large response to response storage.
-    // 2. Use net::URLRequest to retrieve it.
-    // 3. Cancel the request after data starts coming in.
-
-    PushNextTask(base::BindOnce(&AppCacheURLRequestJobTest::VerifyCancel,
-                                base::Unretained(this)));
-    PushNextTask(
-        base::BindOnce(&AppCacheURLRequestJobTest::RequestAppCachedResource,
-                       base::Unretained(this), true));
-
-    writer_ = service_->storage()->CreateResponseWriter(GURL());
-    written_response_id_ = writer_->response_id();
-    WriteLargeResponse();
-
-    url_request_delegate_->kill_after_amount_received_ = kBlockSize;
-    url_request_delegate_->kill_with_io_pending_ = false;
-    // Continues async
-  }
-
-  void VerifyCancel() {
-    EXPECT_EQ(net::ERR_ABORTED, url_request_delegate_->request_status());
-    TestFinished();
-  }
-
-  // CancelRequestWithIOPending --------------------------------------
-
-  void CancelRequestWithIOPending() {
-    // This test has several async steps.
-    // 1. Write a large response to response storage.
-    // 2. Use net::URLRequest to retrieve it.
-    // 3. Cancel the request after data starts coming in.
-
-    PushNextTask(base::BindOnce(&AppCacheURLRequestJobTest::VerifyCancel,
-                                base::Unretained(this)));
-    PushNextTask(
-        base::BindOnce(&AppCacheURLRequestJobTest::RequestAppCachedResource,
-                       base::Unretained(this), true));
-
-    writer_ = service_->storage()->CreateResponseWriter(GURL());
-    written_response_id_ = writer_->response_id();
-    WriteLargeResponse();
-
-    url_request_delegate_->kill_after_amount_received_ = kBlockSize;
-    url_request_delegate_->kill_with_io_pending_ = true;
-    // Continues async
-  }
-
-
-  // Data members --------------------------------------------------------
-
-  std::unique_ptr<base::WaitableEvent> test_finished_event_;
-  std::unique_ptr<MockStorageDelegate> storage_delegate_;
-  std::unique_ptr<MockAppCacheService> service_;
-  base::stack<std::pair<base::OnceClosure, bool>> task_stack_;
-
-  std::unique_ptr<AppCacheResponseReader> reader_;
-  scoped_refptr<HttpResponseInfoIOBuffer> read_info_buffer_;
-  scoped_refptr<IOBuffer> read_buffer_;
-  int expected_read_result_;
-  int reader_deletion_count_down_;
-
-  int64_t written_response_id_;
-  std::unique_ptr<AppCacheResponseWriter> writer_;
-  scoped_refptr<HttpResponseInfoIOBuffer> write_info_buffer_;
-  scoped_refptr<IOBuffer> write_buffer_;
-  int expected_write_result_;
-  int writer_deletion_count_down_;
-
-  bool restart_callback_invoked_;
-
-  std::unique_ptr<MockURLRequestJobFactory> job_factory_;
-  std::unique_ptr<net::URLRequestContext> empty_context_;
-  std::unique_ptr<net::URLRequest> request_;
-  std::unique_ptr<MockURLRequestDelegate> url_request_delegate_;
-
-  static std::unique_ptr<base::Thread> io_thread_;
-  static std::unique_ptr<base::test::ScopedTaskEnvironment>
-      scoped_task_environment_;
-};
-
-// static
-std::unique_ptr<base::Thread> AppCacheURLRequestJobTest::io_thread_;
-std::unique_ptr<base::test::ScopedTaskEnvironment>
-    AppCacheURLRequestJobTest::scoped_task_environment_;
-
-TEST_F(AppCacheURLRequestJobTest, Basic) {
-  RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic);
-}
-
-TEST_F(AppCacheURLRequestJobTest, DeliveryOrders) {
-  RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliveryOrders);
-}
-
-TEST_F(AppCacheURLRequestJobTest, DeliverNetworkResponse) {
-  RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverNetworkResponse);
-}
-
-TEST_F(AppCacheURLRequestJobTest, DeliverErrorResponse) {
-  RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverErrorResponse);
-}
-
-TEST_F(AppCacheURLRequestJobTest, DeliverSmallAppCachedResponse) {
-  RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverSmallAppCachedResponse);
-}
-
-TEST_F(AppCacheURLRequestJobTest, DeliverLargeAppCachedResponse) {
-  RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverLargeAppCachedResponse);
-}
-
-TEST_F(AppCacheURLRequestJobTest, DeliverPartialResponse) {
-  RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverPartialResponse);
-}
-
-TEST_F(AppCacheURLRequestJobTest, CancelRequest) {
-  RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequest);
-}
-
-TEST_F(AppCacheURLRequestJobTest, CancelRequestWithIOPending) {
-  RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending);
-}
-
-}  // namespace appcache_url_request_job_unittest
-}  // namespace content
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc
index 6b46e94..33ad0ed3 100644
--- a/content/browser/background_fetch/background_fetch_context.cc
+++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -145,7 +145,7 @@
     const SkBitmap& icon,
     blink::mojom::BackgroundFetchUkmDataPtr ukm_data,
     int render_frame_tree_node_id,
-    const ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const WebContents::Getter& wc_getter,
     blink::mojom::BackgroundFetchService::FetchCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
diff --git a/content/browser/background_fetch/background_fetch_context.h b/content/browser/background_fetch/background_fetch_context.h
index 00990a2..47645912a 100644
--- a/content/browser/background_fetch/background_fetch_context.h
+++ b/content/browser/background_fetch/background_fetch_context.h
@@ -84,7 +84,7 @@
                   const SkBitmap& icon,
                   blink::mojom::BackgroundFetchUkmDataPtr ukm_data,
                   int render_frame_tree_node_id,
-                  const ResourceRequestInfo::WebContentsGetter& wc_getter,
+                  const WebContents::Getter& wc_getter,
                   blink::mojom::BackgroundFetchService::FetchCallback callback);
 
   // Gets display size for the icon for Background Fetch UI.
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.cc b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
index 6383d5b..ffc12a53 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.cc
@@ -51,7 +51,7 @@
 
   void GetPermissionForOrigin(
       const url::Origin& origin,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const WebContents::Getter& wc_getter,
       BackgroundFetchDelegate::GetPermissionForOriginCallback callback) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -343,7 +343,7 @@
 
 void BackgroundFetchDelegateProxy::GetPermissionForOrigin(
     const url::Origin& origin,
-    const ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const WebContents::Getter& wc_getter,
     BackgroundFetchDelegate::GetPermissionForOriginCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   base::PostTaskWithTraits(
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy.h b/content/browser/background_fetch/background_fetch_delegate_proxy.h
index 8fb029b..55c7ef8 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy.h
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy.h
@@ -83,7 +83,7 @@
   // Checks if the provided origin has permission to start a Background Fetch.
   void GetPermissionForOrigin(
       const url::Origin& origin,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const WebContents::Getter& wc_getter,
       BackgroundFetchDelegate::GetPermissionForOriginCallback callback);
 
   // Creates a new download grouping described by |fetch_description|. Further
diff --git a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
index 2a7095f..e1d686a 100644
--- a/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_delegate_proxy_unittest.cc
@@ -40,7 +40,7 @@
   }
   void GetPermissionForOrigin(
       const url::Origin& origin,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const WebContents::Getter& wc_getter,
       GetPermissionForOriginCallback callback) override {
     std::move(callback).Run(BackgroundFetchPermission::ALLOWED);
   }
diff --git a/content/browser/background_fetch/background_fetch_service_impl.cc b/content/browser/background_fetch/background_fetch_service_impl.cc
index 6f0a7fd..c18c580 100644
--- a/content/browser/background_fetch/background_fetch_service_impl.cc
+++ b/content/browser/background_fetch/background_fetch_service_impl.cc
@@ -63,7 +63,7 @@
       RenderFrameHost::FromID(render_process_host->GetID(), render_frame_id);
   DCHECK(render_frame_host);
 
-  ResourceRequestInfo::WebContentsGetter wc_getter = base::NullCallback();
+  WebContents::Getter wc_getter = base::NullCallback();
 
   // Permissions need to go through the DownloadRequestLimiter if the fetch
   // is started from a top-level frame.
@@ -89,7 +89,7 @@
     scoped_refptr<BackgroundFetchContext> background_fetch_context,
     url::Origin origin,
     int render_frame_tree_node_id,
-    ResourceRequestInfo::WebContentsGetter wc_getter,
+    WebContents::Getter wc_getter,
     blink::mojom::BackgroundFetchServiceRequest request) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
@@ -104,7 +104,7 @@
     scoped_refptr<BackgroundFetchContext> background_fetch_context,
     url::Origin origin,
     int render_frame_tree_node_id,
-    ResourceRequestInfo::WebContentsGetter wc_getter)
+    WebContents::Getter wc_getter)
     : background_fetch_context_(std::move(background_fetch_context)),
       origin_(std::move(origin)),
       render_frame_tree_node_id_(render_frame_tree_node_id),
diff --git a/content/browser/background_fetch/background_fetch_service_impl.h b/content/browser/background_fetch/background_fetch_service_impl.h
index 9bb21216..42aa62f 100644
--- a/content/browser/background_fetch/background_fetch_service_impl.h
+++ b/content/browser/background_fetch/background_fetch_service_impl.h
@@ -29,7 +29,7 @@
       scoped_refptr<BackgroundFetchContext> background_fetch_context,
       url::Origin origin,
       int render_frame_tree_node_id,
-      ResourceRequestInfo::WebContentsGetter wc_getter);
+      WebContents::Getter wc_getter);
   ~BackgroundFetchServiceImpl() override;
 
   static void CreateForWorker(
@@ -62,7 +62,7 @@
       scoped_refptr<BackgroundFetchContext> background_fetch_context,
       url::Origin origin,
       int render_frame_tree_node_id,
-      ResourceRequestInfo::WebContentsGetter wc_getter,
+      WebContents::Getter wc_getter,
       blink::mojom::BackgroundFetchServiceRequest request);
 
   // Validates and returns whether the |developer_id|, |unique_id|, |requests|
@@ -79,7 +79,7 @@
   const url::Origin origin_;
 
   int render_frame_tree_node_id_;
-  ResourceRequestInfo::WebContentsGetter wc_getter_;
+  WebContents::Getter wc_getter_;
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundFetchServiceImpl);
 };
diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.cc b/content/browser/background_fetch/mock_background_fetch_delegate.cc
index ec3cc38..c8a4aac 100644
--- a/content/browser/background_fetch/mock_background_fetch_delegate.cc
+++ b/content/browser/background_fetch/mock_background_fetch_delegate.cc
@@ -67,7 +67,7 @@
 
 void MockBackgroundFetchDelegate::GetPermissionForOrigin(
     const url::Origin& origin,
-    const ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const WebContents::Getter& wc_getter,
     GetPermissionForOriginCallback callback) {
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
diff --git a/content/browser/background_fetch/mock_background_fetch_delegate.h b/content/browser/background_fetch/mock_background_fetch_delegate.h
index 18f22aa0..499bca6 100644
--- a/content/browser/background_fetch/mock_background_fetch_delegate.h
+++ b/content/browser/background_fetch/mock_background_fetch_delegate.h
@@ -68,10 +68,9 @@
   ~MockBackgroundFetchDelegate() override;
 
   // BackgroundFetchDelegate implementation:
-  void GetPermissionForOrigin(
-      const url::Origin& origin,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
-      GetPermissionForOriginCallback callback) override;
+  void GetPermissionForOrigin(const url::Origin& origin,
+                              const WebContents::Getter& wc_getter,
+                              GetPermissionForOriginCallback callback) override;
   void GetIconDisplaySize(
       BackgroundFetchDelegate::GetIconDisplaySizeCallback callback) override;
   void CreateDownloadJob(
diff --git a/content/browser/browsing_data/clear_site_data_handler_unittest.cc b/content/browser/browsing_data/clear_site_data_handler_unittest.cc
index 5ac0de1..468bfbe 100644
--- a/content/browser/browsing_data/clear_site_data_handler_unittest.cc
+++ b/content/browser/browsing_data/clear_site_data_handler_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_command_line.h"
 #include "base/test/scoped_task_environment.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
diff --git a/content/browser/client_hints/client_hints.cc b/content/browser/client_hints/client_hints.cc
index ddd8ae5..5b326627 100644
--- a/content/browser/client_hints/client_hints.cc
+++ b/content/browser/client_hints/client_hints.cc
@@ -378,8 +378,9 @@
 void AddNavigationRequestClientHintsHeaders(
     const GURL& url,
     net::HttpRequestHeaders* headers,
-    content::BrowserContext* context,
-    content::ClientHintsControllerDelegate* delegate) {
+    BrowserContext* context,
+    bool javascript_enabled,
+    ClientHintsControllerDelegate* delegate) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK_EQ(blink::kWebEffectiveConnectionTypeMappingCount,
             net::EFFECTIVE_CONNECTION_TYPE_4G + 1u);
@@ -390,9 +391,14 @@
   if (!IsValidURLForClientHints(url))
     return;
 
-  if (!delegate->IsJavaScriptAllowed(url)) {
+  // Client hints should only be enabled when JavaScript is enabled. Platforms
+  // which enable/disable JavaScript on a per-origin basis should implement
+  // IsJavaScriptAllowed to check a given origin. Other platforms (Android
+  // WebView) enable/disable JavaScript on a per-View basis, using the
+  // WebPreferences setting.
+  if (!delegate->IsJavaScriptAllowed(url) || !javascript_enabled)
     return;
-  }
+
   blink::WebEnabledClientHints web_client_hints;
   delegate->GetAllowedClientHintsFromSource(url, &web_client_hints);
 
diff --git a/content/browser/client_hints/client_hints.h b/content/browser/client_hints/client_hints.h
index 12bb6ee..90e83ab64 100644
--- a/content/browser/client_hints/client_hints.h
+++ b/content/browser/client_hints/client_hints.h
@@ -31,8 +31,9 @@
 CONTENT_EXPORT void AddNavigationRequestClientHintsHeaders(
     const GURL& url,
     net::HttpRequestHeaders* headers,
-    content::BrowserContext* context,
-    content::ClientHintsControllerDelegate* delegate);
+    BrowserContext* context,
+    bool javascript_enabled,
+    ClientHintsControllerDelegate* delegate);
 
 }  // namespace content
 
diff --git a/content/browser/devtools/devtools_interceptor_controller.h b/content/browser/devtools/devtools_interceptor_controller.h
index 5911017..dcd7cd2 100644
--- a/content/browser/devtools/devtools_interceptor_controller.h
+++ b/content/browser/devtools/devtools_interceptor_controller.h
@@ -12,7 +12,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/supports_user_data.h"
 #include "base/unguessable_token.h"
-#include "content/browser/devtools/devtools_url_request_interceptor.h"
+#include "content/browser/devtools/devtools_network_interceptor.h"
+#include "content/browser/devtools/devtools_target_registry.h"
 
 namespace content {
 
@@ -55,8 +56,6 @@
   ~DevToolsInterceptorController() override;
 
  private:
-  friend class DevToolsURLRequestInterceptor;
-
   DevToolsInterceptorController(
       base::WeakPtr<DevToolsNetworkInterceptor> interceptor,
       std::unique_ptr<DevToolsTargetRegistry> target_registry,
diff --git a/content/browser/devtools/devtools_url_interceptor_request_job.cc b/content/browser/devtools/devtools_url_interceptor_request_job.cc
deleted file mode 100644
index 394f791..0000000
--- a/content/browser/devtools/devtools_url_interceptor_request_job.cc
+++ /dev/null
@@ -1,1194 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/devtools/devtools_url_interceptor_request_job.h"
-
-#include "base/base64.h"
-#include "base/bind.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/post_task.h"
-#include "content/browser/devtools/protocol/network_handler.h"
-#include "content/browser/devtools/protocol/page.h"
-#include "content/browser/loader/download_utils_impl.h"
-#include "content/browser/loader/resource_request_info_impl.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "ipc/ipc_channel.h"
-#include "net/base/completion_once_callback.h"
-#include "net/base/elements_upload_data_stream.h"
-#include "net/base/io_buffer.h"
-#include "net/base/load_flags.h"
-#include "net/base/upload_bytes_element_reader.h"
-#include "net/base/upload_element_reader.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/cookies/cookie_options.h"
-#include "net/cookies/cookie_store.h"
-#include "net/cookies/cookie_util.h"
-#include "net/http/http_response_headers.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_request_context.h"
-#include "third_party/blink/public/platform/resource_request_blocked_reason.h"
-
-namespace {
-static const int kInitialBufferSize = 4096;
-static const int kMaxBufferSize = IPC::Channel::kMaximumMessageSize / 4;
-}  // namespace
-
-namespace content {
-
-// DevToolsURLInterceptorRequestJob::SubRequest ---------------------
-
-// If the request was either allowed or modified, a SubRequest will be used to
-// perform the fetch and the results proxied to the original request. This
-// gives us the flexibility to pretend redirects didn't happen if the user
-// chooses to mock the response.  Note this SubRequest is ignored by the
-// interceptor.
-class DevToolsURLInterceptorRequestJob::SubRequest
-    : public net::URLRequest::Delegate {
- public:
-  SubRequest(DevToolsURLInterceptorRequestJob::RequestDetails& request_details,
-             DevToolsURLInterceptorRequestJob* devtools_interceptor_request_job,
-             DevToolsURLRequestInterceptor* interceptor);
-  ~SubRequest() override;
-
-  // net::URLRequest::Delegate methods:
-  void OnAuthRequired(net::URLRequest* request,
-                      const net::AuthChallengeInfo& auth_info) override;
-  void OnCertificateRequested(
-      net::URLRequest* request,
-      net::SSLCertRequestInfo* cert_request_info) override;
-  void OnSSLCertificateError(net::URLRequest* request,
-                             int net_error,
-                             const net::SSLInfo& ssl_info,
-                             bool fatal) override;
-  void OnResponseStarted(net::URLRequest* request, int net_error) override;
-  void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
-  void OnReceivedRedirect(net::URLRequest* request,
-                          const net::RedirectInfo& redirect_info,
-                          bool* defer_redirect) override;
-
-  virtual int Read(net::IOBuffer* buf, int buf_size);
-  void Cancel();
-
-  net::URLRequest* request() const { return request_.get(); }
-
- protected:
-  std::unique_ptr<net::URLRequest> request_;
-
-  DevToolsURLInterceptorRequestJob*
-      devtools_interceptor_request_job_;  // NOT OWNED.
-
-  DevToolsURLRequestInterceptor* const interceptor_;
-  bool was_cancelled_;
-};
-
-DevToolsURLInterceptorRequestJob::SubRequest::SubRequest(
-    DevToolsURLInterceptorRequestJob::RequestDetails& request_details,
-    DevToolsURLInterceptorRequestJob* devtools_interceptor_request_job,
-    DevToolsURLRequestInterceptor* interceptor)
-    : devtools_interceptor_request_job_(devtools_interceptor_request_job),
-      interceptor_(interceptor),
-      was_cancelled_(false) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("devtools_interceptor", R"(
-        semantics {
-          sender: "Developer Tools"
-          description:
-            "When user is debugging a page, all actions resulting in a network "
-            "request are intercepted to enrich the debugging experience."
-          trigger:
-            "User triggers an action that requires network request (like "
-            "navigation, download, etc.) while debugging the page."
-          data:
-            "Any data that user action sends."
-          destination: WEBSITE
-        }
-        policy {
-          cookies_allowed: YES
-          cookies_store: "user"
-          setting:
-            "This feature cannot be disabled in settings, however it happens "
-            "only when user is debugging a page."
-          chrome_policy {
-            DeveloperToolsAvailability {
-              DeveloperToolsAvailability: 2
-            }
-          }
-        })");
-  request_ = request_details.url_request_context->CreateRequest(
-      request_details.url, request_details.priority, this, traffic_annotation);
-  request_->set_method(request_details.method);
-  request_->SetExtraRequestHeaders(request_details.extra_request_headers);
-  request_->SetReferrer(request_details.referrer);
-  request_->set_referrer_policy(request_details.referrer_policy);
-  request_->SetRequestHeadersCallback(
-      devtools_interceptor_request_job->request_headers_callback_);
-  request_->SetResponseHeadersCallback(
-      devtools_interceptor_request_job->response_headers_callback_);
-
-  net::URLRequest* original_request =
-      devtools_interceptor_request_job_->request();
-  request_->set_attach_same_site_cookies(
-      original_request->attach_same_site_cookies());
-  request_->set_site_for_cookies(original_request->site_for_cookies());
-  request_->set_initiator(original_request->initiator());
-
-  // Mimic the ResourceRequestInfoImpl of the original request.
-  ResourceRequestInfoImpl* resource_request_info =
-      static_cast<ResourceRequestInfoImpl*>(ResourceRequestInfo::ForRequest(
-          devtools_interceptor_request_job->request()));
-  ResourceRequestInfoImpl* extra_data = new ResourceRequestInfoImpl(
-      resource_request_info->requester_info(),
-      resource_request_info->GetRouteID(),
-      resource_request_info->GetFrameTreeNodeId(),
-      resource_request_info->GetPluginChildID(),
-      resource_request_info->GetRequestID(),
-      resource_request_info->GetRenderFrameID(),
-      resource_request_info->IsMainFrame(),
-      resource_request_info->fetch_window_id(),
-      resource_request_info->GetResourceType(),
-      resource_request_info->GetPageTransition(),
-      resource_request_info->IsDownload(),
-      resource_request_info->resource_intercept_policy(),
-      resource_request_info->HasUserGesture(),
-      resource_request_info->is_load_timing_enabled(),
-      resource_request_info->is_upload_progress_enabled(),
-      resource_request_info->do_not_prompt_for_login(),
-      resource_request_info->keepalive(),
-      resource_request_info->GetReferrerPolicy(),
-      resource_request_info->IsPrerendering(),
-      resource_request_info->GetContext(),
-      resource_request_info->ShouldReportRawHeaders(),
-      resource_request_info->ShouldReportSecurityInfo(),
-      resource_request_info->IsAsync(),
-      resource_request_info->GetPreviewsState(), resource_request_info->body(),
-      resource_request_info->initiated_in_secure_context());
-  extra_data->AssociateWithRequest(request_.get());
-
-  if (request_details.post_data)
-    request_->set_upload(std::move(request_details.post_data));
-
-  interceptor_->RegisterSubRequest(request_.get());
-  request_->Start();
-}
-
-DevToolsURLInterceptorRequestJob::SubRequest::~SubRequest() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  interceptor_->UnregisterSubRequest(request_.get());
-}
-
-void DevToolsURLInterceptorRequestJob::SubRequest::Cancel() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (was_cancelled_)
-    return;
-
-  was_cancelled_ = true;
-  request_->Cancel();
-}
-
-void DevToolsURLInterceptorRequestJob::SubRequest::OnAuthRequired(
-    net::URLRequest* request,
-    const net::AuthChallengeInfo& auth_info) {
-  devtools_interceptor_request_job_->OnSubRequestAuthRequired(auth_info);
-}
-
-void DevToolsURLInterceptorRequestJob::SubRequest::OnCertificateRequested(
-    net::URLRequest* request,
-    net::SSLCertRequestInfo* cert_request_info) {
-  devtools_interceptor_request_job_->NotifyCertificateRequested(
-      cert_request_info);
-}
-
-void DevToolsURLInterceptorRequestJob::SubRequest::OnSSLCertificateError(
-    net::URLRequest* request,
-    int net_error,
-    const net::SSLInfo& ssl_info,
-    bool fatal) {
-  devtools_interceptor_request_job_->NotifySSLCertificateError(net_error,
-                                                               ssl_info, fatal);
-}
-
-void DevToolsURLInterceptorRequestJob::SubRequest::OnResponseStarted(
-    net::URLRequest* request,
-    int net_error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK_NE(net::ERR_IO_PENDING, net_error);
-  devtools_interceptor_request_job_->OnSubRequestResponseStarted(
-      static_cast<net::Error>(net_error));
-}
-
-void DevToolsURLInterceptorRequestJob::SubRequest::OnReadCompleted(
-    net::URLRequest* request,
-    int bytes_read) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK_NE(bytes_read, net::ERR_IO_PENDING);
-  // OnReadCompleted may get called while canceling the subrequest, in that
-  // event theres no need to call ReadRawDataComplete.
-  if (!was_cancelled_)
-    devtools_interceptor_request_job_->ReadRawDataComplete(bytes_read);
-}
-
-void DevToolsURLInterceptorRequestJob::SubRequest::OnReceivedRedirect(
-    net::URLRequest* request,
-    const net::RedirectInfo& redirectinfo,
-    bool* defer_redirect) {
-  devtools_interceptor_request_job_->OnSubRequestRedirectReceived(
-      *request, redirectinfo, defer_redirect);
-}
-
-int DevToolsURLInterceptorRequestJob::SubRequest::Read(net::IOBuffer* buf,
-                                                       int buf_size) {
-  return request_->Read(buf, buf_size);
-}
-
-// DevToolsURLInterceptorRequestJob::InterceptedRequest ---------------------
-
-class DevToolsURLInterceptorRequestJob::InterceptedRequest
-    : public DevToolsURLInterceptorRequestJob::SubRequest {
- public:
-  InterceptedRequest(
-      DevToolsURLInterceptorRequestJob::RequestDetails& request_details,
-      DevToolsURLInterceptorRequestJob* devtools_interceptor_request_job,
-      DevToolsURLRequestInterceptor* interceptor);
-  ~InterceptedRequest() override {}
-
-  // net::URLRequest::Delegate methods.
-  void OnResponseStarted(net::URLRequest* request, int net_error) override;
-  void OnReadCompleted(net::URLRequest* request, int bytes_read) override;
-
-  int Read(net::IOBuffer* buf, int buf_size) override;
-
-  // Can only call FetchResponseBody() after OnInterceptedRequestResponseStarted
-  // has been fired and before call to Read().
-  void FetchResponseBody();
-
- private:
-  // |this| may be deleted if this method returns false.
-  bool ProcessChunkRead(int result);
-  void ReadIntoBuffer();
-
-  scoped_refptr<net::GrowableIOBuffer> response_buffer_;
-  int read_response_result_;
-  bool read_started_;
-};
-
-DevToolsURLInterceptorRequestJob::InterceptedRequest::InterceptedRequest(
-    DevToolsURLInterceptorRequestJob::RequestDetails& request_details,
-    DevToolsURLInterceptorRequestJob* devtools_interceptor_request_job,
-    DevToolsURLRequestInterceptor* interceptor)
-    : SubRequest(request_details,
-                 devtools_interceptor_request_job,
-                 interceptor),
-      response_buffer_(base::MakeRefCounted<net::GrowableIOBuffer>()),
-      read_response_result_(0),
-      read_started_(false) {}
-
-void DevToolsURLInterceptorRequestJob::InterceptedRequest::OnResponseStarted(
-    net::URLRequest* request,
-    int net_error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK_NE(net::ERR_IO_PENDING, net_error);
-
-  if (net_error != net::OK) {
-    // If we have an error here, we cannot read the body, so we
-    // flag it here as already read and set the result.
-    DCHECK_EQ(read_response_result_, 0);
-    read_started_ = true;
-    read_response_result_ = net_error;
-  }
-  response_buffer_->SetCapacity(kInitialBufferSize);
-
-  devtools_interceptor_request_job_->OnInterceptedRequestResponseStarted(
-      static_cast<net::Error>(net_error));
-}
-
-void DevToolsURLInterceptorRequestJob::InterceptedRequest::OnReadCompleted(
-    net::URLRequest* request,
-    int result) {
-  // OnReadComplete may be called while request is being cancelled, in this
-  // event the result should be |net::ERR_ABORTED| which should complete any
-  // |pending_body_requests_|.
-  if (ProcessChunkRead(result))
-    ReadIntoBuffer();
-}
-
-bool DevToolsURLInterceptorRequestJob::InterceptedRequest::ProcessChunkRead(
-    int result) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK_NE(result, net::ERR_IO_PENDING);
-  if (result == 0) {
-    read_response_result_ = response_buffer_->offset();
-    // Response is done so, reset buffer to zero so it can be read from the
-    // beginning as an IOBuffer.
-    response_buffer_->set_offset(0);
-  } else if (result < 0) {
-    read_response_result_ = result;
-  } else {
-    response_buffer_->set_offset(response_buffer_->offset() + result);
-  }
-
-  if (response_buffer_->offset() > kMaxBufferSize) {
-    response_buffer_->SetCapacity(0);
-    read_response_result_ = net::ERR_FILE_TOO_BIG;
-  }
-  if (read_response_result_ != net::ERR_IO_PENDING) {
-    devtools_interceptor_request_job_->OnInterceptedRequestResponseReady(
-        *response_buffer_.get(), read_response_result_);
-    return false;
-  }
-  return true;
-}
-
-int DevToolsURLInterceptorRequestJob::InterceptedRequest::Read(
-    net::IOBuffer* buf,
-    int buf_size) {
-  DCHECK(read_started_);
-  DCHECK_NE(read_response_result_, net::ERR_IO_PENDING);
-  if (read_response_result_ <= 0)
-    return read_response_result_;
-  int read_size = std::min(buf_size, read_response_result_);
-  std::memcpy(buf->data(), response_buffer_->data(), read_size);
-  response_buffer_->set_offset(response_buffer_->offset() + read_size);
-  read_response_result_ -= read_size;
-  return read_size;
-}
-
-void DevToolsURLInterceptorRequestJob::InterceptedRequest::FetchResponseBody() {
-  if (read_started_) {
-    if (read_response_result_ != net::ERR_IO_PENDING) {
-      devtools_interceptor_request_job_->OnInterceptedRequestResponseReady(
-          *response_buffer_.get(), read_response_result_);
-    }
-    return;
-  }
-  if (was_cancelled_) {
-    // Cannot request body on cancelled request.
-    devtools_interceptor_request_job_->OnInterceptedRequestResponseReady(
-        *response_buffer_.get(), net::ERR_ABORTED);
-    return;
-  }
-  read_started_ = true;
-  read_response_result_ = net::ERR_IO_PENDING;
-  ReadIntoBuffer();
-}
-
-void DevToolsURLInterceptorRequestJob::InterceptedRequest::ReadIntoBuffer() {
-  // OnReadCompleted may get called while canceling the subrequest, in that
-  // event we cannot call URLRequest::Read().
-  DCHECK(!was_cancelled_);
-  int result;
-  do {
-    if (response_buffer_->RemainingCapacity() == 0)
-      response_buffer_->SetCapacity(response_buffer_->capacity() * 2);
-    result = request_->Read(response_buffer_.get(),
-                            response_buffer_->RemainingCapacity());
-  } while (result != net::ERR_IO_PENDING && ProcessChunkRead(result));
-}
-
-class DevToolsURLInterceptorRequestJob::MockResponseDetails {
- public:
-  MockResponseDetails(scoped_refptr<net::HttpResponseHeaders> response_headers,
-                      scoped_refptr<base::RefCountedMemory> response_bytes,
-                      size_t response_bytes_offset);
-
-  ~MockResponseDetails();
-
-  scoped_refptr<net::HttpResponseHeaders>& response_headers() {
-    return response_headers_;
-  }
-
-  base::TimeTicks response_time() const { return response_time_; }
-
-  int ReadRawData(net::IOBuffer* buf, int buf_size);
-
- private:
-  scoped_refptr<net::HttpResponseHeaders> response_headers_;
-  scoped_refptr<base::RefCountedMemory> response_bytes_;
-  size_t read_offset_;
-  base::TimeTicks response_time_;
-};
-
-DevToolsURLInterceptorRequestJob::MockResponseDetails::MockResponseDetails(
-    scoped_refptr<net::HttpResponseHeaders> response_headers,
-    scoped_refptr<base::RefCountedMemory> response_bytes,
-    size_t repsonse_bytes_offset)
-    : response_headers_(std::move(response_headers)),
-      response_bytes_(std::move(response_bytes)),
-      read_offset_(repsonse_bytes_offset),
-      response_time_(base::TimeTicks::Now()) {
-  if (!response_headers) {
-    static const char kDummyHeaders[] = "HTTP/1.1 200 OK\0\0";
-    response_headers =
-        base::MakeRefCounted<net::HttpResponseHeaders>(kDummyHeaders);
-  }
-}
-
-DevToolsURLInterceptorRequestJob::MockResponseDetails::~MockResponseDetails() {}
-
-int DevToolsURLInterceptorRequestJob::MockResponseDetails::ReadRawData(
-    net::IOBuffer* buf,
-    int buf_size) {
-  if (!response_bytes_)
-    return 0;
-  size_t bytes_available = response_bytes_->size() - read_offset_;
-  size_t bytes_to_copy =
-      std::min(static_cast<size_t>(buf_size), bytes_available);
-  if (bytes_to_copy > 0) {
-    std::memcpy(buf->data(), response_bytes_->front() + read_offset_,
-                bytes_to_copy);
-    read_offset_ += bytes_to_copy;
-  }
-  return bytes_to_copy;
-}
-
-namespace {
-
-void SendPendingBodyRequestsOnUiThread(
-    std::vector<std::unique_ptr<
-        protocol::Network::Backend::GetResponseBodyForInterceptionCallback>>
-        callbacks,
-    std::string content) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  std::string encoded_response;
-  base::Base64Encode(content, &encoded_response);
-  for (auto&& callback : callbacks)
-    callback->sendSuccess(encoded_response, true);
-}
-
-void SendPendingBodyRequestsWithErrorOnUiThread(
-    std::vector<std::unique_ptr<
-        protocol::Network::Backend::GetResponseBodyForInterceptionCallback>>
-        callbacks,
-    protocol::DispatchResponse error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  for (auto&& callback : callbacks)
-    callback->sendFailure(error);
-}
-
-class ProxyUploadElementReader : public net::UploadElementReader {
- public:
-  explicit ProxyUploadElementReader(net::UploadElementReader* reader)
-      : reader_(reader) {}
-
-  ~ProxyUploadElementReader() override {}
-
-  // net::UploadElementReader overrides:
-  int Init(net::CompletionOnceCallback callback) override {
-    return reader_->Init(std::move(callback));
-  }
-
-  uint64_t GetContentLength() const override {
-    return reader_->GetContentLength();
-  }
-
-  uint64_t BytesRemaining() const override { return reader_->BytesRemaining(); }
-
-  bool IsInMemory() const override { return reader_->IsInMemory(); }
-
-  int Read(net::IOBuffer* buf,
-           int buf_length,
-           net::CompletionOnceCallback callback) override {
-    return reader_->Read(buf, buf_length, std::move(callback));
-  }
-
- private:
-  net::UploadElementReader* reader_;  // NOT OWNED
-
-  DISALLOW_COPY_AND_ASSIGN(ProxyUploadElementReader);
-};
-
-std::unique_ptr<net::UploadDataStream> GetUploadData(net::URLRequest* request) {
-  if (!request->has_upload())
-    return nullptr;
-
-  const net::UploadDataStream* stream = request->get_upload();
-  auto* readers = stream->GetElementReaders();
-  if (!readers || readers->empty())
-    return nullptr;
-
-  std::vector<std::unique_ptr<net::UploadElementReader>> proxy_readers;
-  proxy_readers.reserve(readers->size());
-  for (auto& reader : *readers) {
-    proxy_readers.push_back(
-        std::make_unique<ProxyUploadElementReader>(reader.get()));
-  }
-
-  return std::make_unique<net::ElementsUploadDataStream>(
-      std::move(proxy_readers), 0);
-}
-
-bool IsDownload(net::URLRequest* orig_request, net::URLRequest* subrequest) {
-  auto* req_info = ResourceRequestInfoImpl::ForRequest(orig_request);
-  // Only happens to downloads that are initiated by the download manager.
-  if (req_info->IsDownload())
-    return true;
-
-  // Note this will not correctly identify a download for the MIME types
-  // inferred with content sniffing. The new interception implementation
-  // should not have this problem, as it's on top of MIME sniffer.
-  std::string mime_type;
-  subrequest->GetMimeType(&mime_type);
-  return req_info->resource_intercept_policy() ==
-             ResourceInterceptPolicy::kAllowAll &&
-         download_utils::IsDownload(orig_request->url(),
-                                    subrequest->response_headers(), mime_type);
-}
-
-}  // namespace
-
-DevToolsURLInterceptorRequestJob::DevToolsURLInterceptorRequestJob(
-    DevToolsURLRequestInterceptor* interceptor,
-    const std::string& interception_id,
-    intptr_t owning_entry_id,
-    net::URLRequest* original_request,
-    net::NetworkDelegate* original_network_delegate,
-    const base::UnguessableToken& devtools_token,
-    DevToolsNetworkInterceptor::RequestInterceptedCallback callback,
-    ResourceType resource_type,
-    InterceptionStage stage_to_intercept)
-    : net::URLRequestJob(original_request, original_network_delegate),
-      interceptor_(interceptor),
-      request_details_(original_request->url(),
-                       original_request->site_for_cookies(),
-                       original_request->initiator(),
-                       original_request->method(),
-                       GetUploadData(original_request),
-                       original_request->extra_request_headers(),
-                       original_request->referrer(),
-                       original_request->referrer_policy(),
-                       original_request->priority(),
-                       original_request->context()),
-      waiting_for_user_response_(WaitingForUserResponse::NOT_WAITING),
-      interception_id_(interception_id),
-      owning_entry_id_(owning_entry_id),
-      devtools_token_(devtools_token),
-      callback_(callback),
-      resource_type_(resource_type),
-      stage_to_intercept_(stage_to_intercept) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-}
-
-DevToolsURLInterceptorRequestJob::~DevToolsURLInterceptorRequestJob() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  interceptor_->JobFinished(
-      interception_id_,
-      DevToolsURLRequestInterceptor::IsNavigationRequest(resource_type_));
-}
-
-// net::URLRequestJob implementation:
-void DevToolsURLInterceptorRequestJob::SetExtraRequestHeaders(
-    const net::HttpRequestHeaders& headers) {
-  request_details_.extra_request_headers = headers;
-}
-
-void DevToolsURLInterceptorRequestJob::Start() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  auto* store = request_details_.url_request_context->cookie_store();
-  if (!store || (request()->load_flags() & net::LOAD_DO_NOT_SEND_COOKIES)) {
-    StartWithCookies(net::CookieList(), net::CookieStatusList());
-    return;
-  }
-
-  // Matches what URLRequestHttpJob would use.
-  net::CookieOptions options;
-  options.set_include_httponly();
-  options.set_same_site_cookie_context(
-      net::cookie_util::ComputeSameSiteContextForRequest(
-          request()->method(), request()->url(), request()->site_for_cookies(),
-          request()->initiator(), request()->attach_same_site_cookies()));
-
-  store->GetCookieListWithOptionsAsync(
-      request_details_.url, options,
-      base::BindOnce(&DevToolsURLInterceptorRequestJob::StartWithCookies,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void DevToolsURLInterceptorRequestJob::StartWithCookies(
-    const net::CookieList& cookie_list,
-    const net::CookieStatusList& excluded_cookies) {
-  request_details_.cookie_line =
-      net::CanonicalCookie::BuildCookieLine(cookie_list);
-
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (stage_to_intercept_ == InterceptionStage::DONT_INTERCEPT) {
-    sub_request_.reset(new SubRequest(request_details_, this, interceptor_));
-    return;
-  }
-
-  if (stage_to_intercept_ == InterceptionStage::RESPONSE) {
-    // We are only a response interception, we go right to dispatching the
-    // request.
-    sub_request_.reset(
-        new InterceptedRequest(request_details_, this, interceptor_));
-    return;
-  }
-
-  DCHECK(stage_to_intercept_ == InterceptionStage::REQUEST ||
-         stage_to_intercept_ == InterceptionStage::BOTH);
-  waiting_for_user_response_ = WaitingForUserResponse::WAITING_FOR_REQUEST_ACK;
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                           base::BindOnce(callback_, BuildRequestInfo()));
-}
-
-void DevToolsURLInterceptorRequestJob::Kill() {
-  sub_request_.reset();
-  URLRequestJob::Kill();
-}
-
-int DevToolsURLInterceptorRequestJob::ReadRawData(net::IOBuffer* buf,
-                                                  int buf_size) {
-  if (mock_response_details_)
-    return mock_response_details_->ReadRawData(buf, buf_size);
-
-  CHECK(sub_request_);
-  return sub_request_->Read(buf, buf_size);
-}
-
-int DevToolsURLInterceptorRequestJob::GetResponseCode() const {
-  if (sub_request_) {
-    return sub_request_->request()->GetResponseCode();
-  } else {
-    CHECK(mock_response_details_);
-    return mock_response_details_->response_headers()->response_code();
-  }
-}
-
-void DevToolsURLInterceptorRequestJob::GetResponseInfo(
-    net::HttpResponseInfo* info) {
-  // NOTE this can get called during URLRequestJob::NotifyStartError in which
-  // case we might not have either a sub request or a mock response.
-  if (sub_request_) {
-    *info = sub_request_->request()->response_info();
-  } else if (mock_response_details_) {
-    info->headers = mock_response_details_->response_headers();
-  }
-}
-
-const net::HttpResponseHeaders*
-DevToolsURLInterceptorRequestJob::GetHttpResponseHeaders() const {
-  if (sub_request_) {
-    net::URLRequest* request = sub_request_->request();
-    return request->response_info().headers.get();
-  }
-  CHECK(mock_response_details_);
-  return mock_response_details_->response_headers().get();
-}
-
-bool DevToolsURLInterceptorRequestJob::GetMimeType(
-    std::string* mime_type) const {
-  if (sub_request_) {
-    sub_request_->request()->GetMimeType(mime_type);
-    return true;
-  }
-  const net::HttpResponseHeaders* response_headers = GetHttpResponseHeaders();
-  if (response_headers)
-    return response_headers->GetMimeType(mime_type);
-  return false;
-}
-
-bool DevToolsURLInterceptorRequestJob::GetCharset(std::string* charset) {
-  const net::HttpResponseHeaders* response_headers = GetHttpResponseHeaders();
-  if (!response_headers)
-    return false;
-  return response_headers->GetCharset(charset);
-}
-
-void DevToolsURLInterceptorRequestJob::GetLoadTimingInfo(
-    net::LoadTimingInfo* load_timing_info) const {
-  if (sub_request_) {
-    sub_request_->request()->GetLoadTimingInfo(load_timing_info);
-  } else {
-    CHECK(mock_response_details_);
-    // Since this request is mocked most of the fields are irrelevant.
-    load_timing_info->receive_headers_end =
-        mock_response_details_->response_time();
-  }
-}
-
-bool DevToolsURLInterceptorRequestJob::NeedsAuth() {
-  return !!auth_info_;
-}
-
-std::unique_ptr<net::AuthChallengeInfo>
-DevToolsURLInterceptorRequestJob::GetAuthChallengeInfo() {
-  DCHECK(auth_info_);
-  return std::make_unique<net::AuthChallengeInfo>(*auth_info_);
-}
-
-void DevToolsURLInterceptorRequestJob::SetAuth(
-    const net::AuthCredentials& credentials) {
-  sub_request_->request()->SetAuth(credentials);
-  auth_info_ = nullptr;
-}
-
-void DevToolsURLInterceptorRequestJob::CancelAuth() {
-  sub_request_->request()->CancelAuth();
-  auth_info_ = nullptr;
-}
-
-void DevToolsURLInterceptorRequestJob::OnSubRequestAuthRequired(
-    const net::AuthChallengeInfo& auth_info) {
-  auth_info_ = std::make_unique<net::AuthChallengeInfo>(auth_info);
-
-  if (stage_to_intercept_ == InterceptionStage::DONT_INTERCEPT) {
-    // This should trigger default auth behavior.
-    // See comment in ProcessAuthResponse.
-    NotifyHeadersComplete();
-    return;
-  }
-
-  // This notification came from the sub requests URLRequest::Delegate and
-  // depending on what the protocol user wants us to do we must either cancel
-  // the auth, provide the credentials or proxy it the original
-  // URLRequest::Delegate.
-
-  waiting_for_user_response_ = WaitingForUserResponse::WAITING_FOR_AUTH_ACK;
-
-  std::unique_ptr<InterceptedRequestInfo> request_info = BuildRequestInfo();
-  request_info->auth_challenge =
-      std::make_unique<net::AuthChallengeInfo>(auth_info);
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                           base::BindOnce(callback_, std::move(request_info)));
-}
-
-void DevToolsURLInterceptorRequestJob::OnSubRequestResponseStarted(
-    const net::Error& net_error) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (net_error != net::OK) {
-    sub_request_->Cancel();
-    NotifyStartError(
-        net::URLRequestStatus(net::URLRequestStatus::FAILED, net_error));
-    return;
-  }
-
-  NotifyHeadersComplete();
-}
-
-void DevToolsURLInterceptorRequestJob::OnSubRequestRedirectReceived(
-    const net::URLRequest& request,
-    const net::RedirectInfo& redirectinfo,
-    bool* defer_redirect) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(sub_request_);
-
-  // If we're not intercepting results or are a response then cancel this
-  // redirect and tell the parent request it was redirected through |redirect_|.
-  if (!(stage_to_intercept_ & InterceptionStage::RESPONSE)) {
-    *defer_redirect = false;
-    ProcessRedirect(redirectinfo.status_code, redirectinfo.new_url.spec());
-    redirect_.reset();
-    sub_request_.reset();
-    return;
-  }
-
-  // Otherwise we will need to ask what to do via DevTools protocol.
-  *defer_redirect = true;
-
-  redirect_.reset(new net::RedirectInfo(redirectinfo));
-
-  waiting_for_user_response_ = WaitingForUserResponse::WAITING_FOR_REQUEST_ACK;
-
-  std::unique_ptr<InterceptedRequestInfo> request_info = BuildRequestInfo();
-  request_info->response_headers = request.response_headers();
-  request_info->redirect_url = redirectinfo.new_url.spec();
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                           base::BindOnce(callback_, std::move(request_info)));
-  sub_request_.reset();
-}
-
-void DevToolsURLInterceptorRequestJob::OnInterceptedRequestResponseStarted(
-    const net::Error& net_error) {
-  DCHECK_NE(waiting_for_user_response_,
-            WaitingForUserResponse::WAITING_FOR_RESPONSE_ACK);
-  if (stage_to_intercept_ == InterceptionStage::DONT_INTERCEPT) {
-    static_cast<InterceptedRequest*>(sub_request_.get())->FetchResponseBody();
-    return;
-  }
-  waiting_for_user_response_ = WaitingForUserResponse::WAITING_FOR_RESPONSE_ACK;
-
-  std::unique_ptr<InterceptedRequestInfo> request_info = BuildRequestInfo();
-  if (net_error < 0) {
-    request_info->response_error_code = net_error;
-  } else {
-    std::unique_ptr<protocol::DictionaryValue> headers_dict(
-        protocol::DictionaryValue::create());
-    request_info->response_headers =
-        sub_request_->request()->response_headers();
-    request_info->is_download = IsDownload(request(), sub_request_->request());
-  }
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                           base::BindOnce(callback_, std::move(request_info)));
-}
-
-// If result is < 0 it means error.
-void DevToolsURLInterceptorRequestJob::OnInterceptedRequestResponseReady(
-    const net::IOBuffer& buf,
-    int result) {
-  DCHECK(sub_request_);
-  if (result < 0) {
-    sub_request_->Cancel();
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(
-            &SendPendingBodyRequestsWithErrorOnUiThread,
-            std::move(pending_body_requests_),
-            protocol::Response::Error(base::StringPrintf(
-                "Could not get response body because of error code: %d",
-                result))));
-  } else {
-    base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                             base::BindOnce(&SendPendingBodyRequestsOnUiThread,
-                                            std::move(pending_body_requests_),
-                                            std::string(buf.data(), result)));
-  }
-  if (request_->status().status() == net::URLRequestStatus::CANCELED ||
-      waiting_for_user_response_ != WaitingForUserResponse::NOT_WAITING) {
-    return;
-  }
-  if (result < 0) {
-    NotifyStartError(net::URLRequestStatus::FromError(result));
-  } else {
-    // This call may consume the buffer.
-    NotifyHeadersComplete();
-  }
-}
-
-void DevToolsURLInterceptorRequestJob::StopIntercepting() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  stage_to_intercept_ = InterceptionStage::DONT_INTERCEPT;
-  callback_.Reset();
-
-  // Allow the request to continue if we're waiting for user input.
-  switch (waiting_for_user_response_) {
-    case WaitingForUserResponse::NOT_WAITING:
-      return;
-
-    case WaitingForUserResponse::WAITING_FOR_RESPONSE_ACK:
-    // Fallthough.
-    case WaitingForUserResponse::WAITING_FOR_REQUEST_ACK:
-      ProcessInterceptionResponse(
-          std::make_unique<DevToolsNetworkInterceptor::Modifications>());
-      return;
-    case WaitingForUserResponse::WAITING_FOR_AUTH_ACK:
-      ProcessAuthResponse(DevToolsNetworkInterceptor::AuthChallengeResponse(
-          DevToolsNetworkInterceptor::AuthChallengeResponse::kDefault));
-      return;
-
-    default:
-      NOTREACHED();
-      return;
-  }
-}
-
-void DevToolsURLInterceptorRequestJob::ContinueInterceptedRequest(
-    std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modifications,
-    std::unique_ptr<ContinueInterceptedRequestCallback> callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  switch (waiting_for_user_response_) {
-    case WaitingForUserResponse::NOT_WAITING:
-      base::PostTaskWithTraits(
-          FROM_HERE, {BrowserThread::UI},
-          base::BindOnce(&ContinueInterceptedRequestCallback::sendFailure,
-                         std::move(callback),
-                         protocol::Response::InvalidParams(
-                             "Response already processed.")));
-      break;
-
-    case WaitingForUserResponse::WAITING_FOR_RESPONSE_ACK:
-    // Fallthough.
-    case WaitingForUserResponse::WAITING_FOR_REQUEST_ACK:
-      if (modifications->auth_challenge_response) {
-        base::PostTaskWithTraits(
-            FROM_HERE, {BrowserThread::UI},
-            base::BindOnce(&ContinueInterceptedRequestCallback::sendFailure,
-                           std::move(callback),
-                           protocol::Response::InvalidParams(
-                               "authChallengeResponse not expected.")));
-        break;
-      }
-      ProcessInterceptionResponse(std::move(modifications));
-      base::PostTaskWithTraits(
-          FROM_HERE, {BrowserThread::UI},
-          base::BindOnce(&ContinueInterceptedRequestCallback::sendSuccess,
-                         std::move(callback)));
-      break;
-
-    case WaitingForUserResponse::WAITING_FOR_AUTH_ACK:
-      if (!modifications->auth_challenge_response) {
-        base::PostTaskWithTraits(
-            FROM_HERE, {BrowserThread::UI},
-            base::BindOnce(&ContinueInterceptedRequestCallback::sendFailure,
-                           std::move(callback),
-                           protocol::Response::InvalidParams(
-                               "authChallengeResponse required.")));
-        break;
-      }
-      ProcessAuthResponse(*modifications->auth_challenge_response);
-      base::PostTaskWithTraits(
-          FROM_HERE, {BrowserThread::UI},
-          base::BindOnce(&ContinueInterceptedRequestCallback::sendSuccess,
-                         std::move(callback)));
-      break;
-
-    default:
-      NOTREACHED();
-      break;
-  }
-}
-
-void DevToolsURLInterceptorRequestJob::ProcessRedirect(
-    int status_code,
-    const std::string& new_url) {
-  // NOTE we don't append the text form of the status code because
-  // net::HttpResponseHeaders doesn't need that.
-  std::string raw_headers = base::StringPrintf("HTTP/1.1 %d", status_code);
-  raw_headers.append(1, '\0');
-  raw_headers.append("Location: ");
-  raw_headers.append(new_url);
-  raw_headers.append(2, '\0');
-  mock_response_details_ = std::make_unique<MockResponseDetails>(
-      base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers),
-      nullptr /* response_bytes */, 0 /* response_bytes_offset */);
-
-  NotifyHeadersComplete();
-}
-
-void DevToolsURLInterceptorRequestJob::GetResponseBody(
-    std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  std::string error_reason;
-  if (stage_to_intercept_ == InterceptionStage::REQUEST) {
-    error_reason =
-        "Can only get response body on HeadersReceived pattern matched "
-        "requests.";
-  } else if (waiting_for_user_response_ !=
-             WaitingForUserResponse::WAITING_FOR_RESPONSE_ACK) {
-    error_reason =
-        "Can only get response body on requests captured after headers "
-        "received.";
-  }
-  if (error_reason.size()) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(
-            &GetResponseBodyForInterceptionCallback::sendFailure,
-            std::move(callback),
-            protocol::Response::InvalidParams(std::move(error_reason))));
-    return;
-  }
-  DCHECK(sub_request_);
-  pending_body_requests_.push_back(std::move(callback));
-  static_cast<InterceptedRequest*>(sub_request_.get())->FetchResponseBody();
-}
-
-std::unique_ptr<InterceptedRequestInfo>
-DevToolsURLInterceptorRequestJob::BuildRequestInfo() {
-  auto result = std::make_unique<InterceptedRequestInfo>();
-  result->interception_id = interception_id_;
-  result->network_request =
-      protocol::NetworkHandler::CreateRequestFromURLRequest(
-          request(), request_details_.cookie_line);
-  result->frame_id = devtools_token_;
-  result->resource_type = resource_type_;
-  result->is_navigation =
-      DevToolsURLRequestInterceptor::IsNavigationRequest(resource_type_);
-  return result;
-}
-
-void DevToolsURLInterceptorRequestJob::ProcessInterceptionResponse(
-    std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modifications) {
-  bool is_response_ack = waiting_for_user_response_ ==
-                         WaitingForUserResponse::WAITING_FOR_RESPONSE_ACK;
-  waiting_for_user_response_ = WaitingForUserResponse::NOT_WAITING;
-
-  if (modifications->error_reason) {
-    if (sub_request_) {
-      sub_request_->Cancel();
-      sub_request_.reset();
-    }
-    if (modifications->error_reason == net::ERR_BLOCKED_BY_CLIENT) {
-      // So we know that these modifications originated from devtools
-      // (also known as inspector), and can therefore annotate the
-      // request. We only do this for one specific error code thus
-      // far, to minimize risk of breaking other usages.
-      ResourceRequestInfoImpl* resource_request_info =
-          ResourceRequestInfoImpl::ForRequest(request());
-      resource_request_info->SetResourceRequestBlockedReason(
-          blink::ResourceRequestBlockedReason::kInspector);
-    }
-    NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
-                                           *modifications->error_reason));
-    return;
-  }
-
-  if (modifications->response_headers || modifications->response_body) {
-    mock_response_details_ = std::make_unique<MockResponseDetails>(
-        std::move(modifications->response_headers),
-        std::move(modifications->response_body), modifications->body_offset);
-
-    // Set cookies in the network stack.
-    net::CookieOptions options;
-    options.set_include_httponly();
-    options.set_same_site_cookie_context(
-        net::cookie_util::ComputeSameSiteContextForResponse(
-            request_details_.url, request_details_.site_for_cookies,
-            request_details_.initiator));
-
-    base::Time response_date;
-    if (!mock_response_details_->response_headers()->GetDateValue(
-            &response_date)) {
-      response_date = base::Time();
-    }
-    options.set_server_time(response_date);
-
-    const base::StringPiece name("Set-Cookie");
-    std::string cookie_line;
-    size_t iter = 0;
-    while (mock_response_details_->response_headers()->EnumerateHeader(
-        &iter, name, &cookie_line)) {
-      std::unique_ptr<net::CanonicalCookie> cookie =
-          net::CanonicalCookie::Create(request_details_.url, cookie_line,
-                                       base::Time::Now(), options);
-      if (!cookie)
-        continue;
-
-      auto* store = request_details_.url_request_context->cookie_store();
-      store->SetCanonicalCookieAsync(std::move(cookie),
-                                     request_details_.url.scheme(), options,
-                                     net::CookieStore::SetCookiesCallback());
-    }
-
-    if (sub_request_) {
-      sub_request_->Cancel();
-      sub_request_.reset();
-    }
-    if (response_headers_callback_) {
-      response_headers_callback_.Run(
-          mock_response_details_->response_headers());
-    }
-    NotifyHeadersComplete();
-    return;
-  }
-
-  if (redirect_) {
-    DCHECK(!is_response_ack);
-    ProcessRedirect(
-        redirect_->status_code,
-        modifications->modified_url.fromMaybe(redirect_->new_url.spec()));
-    redirect_.reset();
-  } else if (is_response_ack) {
-    DCHECK(sub_request_);
-    // If we are continuing the request without change we fetch the body.
-    // If the body is already ready we will get a
-    // OnInterceptedRequestResponseReady event which will begin the read.
-    static_cast<InterceptedRequest*>(sub_request_.get())->FetchResponseBody();
-  } else {
-    // Note this redirect is not visible to the caller by design. If they want a
-    // visible redirect they can mock a response with a 302.
-    if (modifications->modified_url.isJust())
-      request_details_.url = GURL(modifications->modified_url.fromJust());
-
-    if (modifications->modified_method.isJust())
-      request_details_.method = modifications->modified_method.fromJust();
-
-    if (modifications->modified_post_data.isJust()) {
-      const std::string& post_data =
-          modifications->modified_post_data.fromJust();
-      std::vector<char> data(post_data.begin(), post_data.end());
-      request_details_.post_data =
-          net::ElementsUploadDataStream::CreateWithReader(
-              std::make_unique<net::UploadOwnedBytesElementReader>(&data), 0);
-    }
-
-    if (modifications->modified_headers) {
-      request_details_.extra_request_headers.Clear();
-      for (const auto& entry : *modifications->modified_headers) {
-        if (base::EqualsCaseInsensitiveASCII(
-                entry.first, net::HttpRequestHeaders::kReferer)) {
-          request_details_.referrer = entry.second;
-          request_details_.referrer_policy =
-              net::URLRequest::NEVER_CLEAR_REFERRER;
-        } else {
-          request_details_.extra_request_headers.SetHeader(entry.first,
-                                                           entry.second);
-        }
-      }
-    }
-
-    // The reason we start a sub request is because we are in full control of it
-    // and can choose to ignore it if, for example, the fetch encounters a
-    // redirect that the user chooses to replace with a mock response.
-    DCHECK(stage_to_intercept_ != InterceptionStage::RESPONSE);
-    if (stage_to_intercept_ == InterceptionStage::BOTH) {
-      sub_request_.reset(
-          new InterceptedRequest(request_details_, this, interceptor_));
-    } else {
-      sub_request_.reset(new SubRequest(request_details_, this, interceptor_));
-    }
-  }
-}
-
-void DevToolsURLInterceptorRequestJob::ProcessAuthResponse(
-    const DevToolsNetworkInterceptor::AuthChallengeResponse& response) {
-  waiting_for_user_response_ = WaitingForUserResponse::NOT_WAITING;
-
-  switch (response.response_type) {
-    case DevToolsNetworkInterceptor::AuthChallengeResponse::kDefault:
-      // The user wants the default behavior, we must proxy the auth request to
-      // the original URLRequest::Delegate.  We can't do that directly but by
-      // implementing NeedsAuth and calling NotifyHeadersComplete we trigger it.
-      // To close the loop we also need to implement GetAuthChallengeInfo,
-      // SetAuth and CancelAuth.
-      NotifyHeadersComplete();
-      break;
-    case DevToolsNetworkInterceptor::AuthChallengeResponse::kCancelAuth:
-      CancelAuth();
-      break;
-    case DevToolsNetworkInterceptor::AuthChallengeResponse::kProvideCredentials:
-      SetAuth(response.credentials);
-      break;
-  }
-}
-
-void DevToolsURLInterceptorRequestJob::SetRequestHeadersCallback(
-    net::RequestHeadersCallback callback) {
-  request_headers_callback_ = std::move(callback);
-}
-
-void DevToolsURLInterceptorRequestJob::SetResponseHeadersCallback(
-    net::ResponseHeadersCallback callback) {
-  response_headers_callback_ = std::move(callback);
-}
-
-void DevToolsURLInterceptorRequestJob::ContinueDespiteLastError() {
-  if (sub_request_)
-    sub_request_->request()->ContinueDespiteLastError();
-}
-
-DevToolsURLInterceptorRequestJob::RequestDetails::RequestDetails(
-    const GURL& url,
-    const GURL& site_for_cookies,
-    base::Optional<url::Origin> initiator,
-    const std::string& method,
-    std::unique_ptr<net::UploadDataStream> post_data,
-    const net::HttpRequestHeaders& extra_request_headers,
-    const std::string& referrer,
-    net::URLRequest::ReferrerPolicy referrer_policy,
-    const net::RequestPriority& priority,
-    const net::URLRequestContext* url_request_context)
-    : url(url),
-      site_for_cookies(site_for_cookies),
-      initiator(std::move(initiator)),
-      method(method),
-      post_data(std::move(post_data)),
-      extra_request_headers(extra_request_headers),
-      referrer(referrer),
-      referrer_policy(referrer_policy),
-      priority(priority),
-      url_request_context(url_request_context) {}
-
-DevToolsURLInterceptorRequestJob::RequestDetails::~RequestDetails() {}
-
-}  // namespace content
diff --git a/content/browser/devtools/devtools_url_interceptor_request_job.h b/content/browser/devtools/devtools_url_interceptor_request_job.h
deleted file mode 100644
index af6135c..0000000
--- a/content/browser/devtools/devtools_url_interceptor_request_job.h
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_INTERCEPTOR_REQUEST_JOB_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_INTERCEPTOR_REQUEST_JOB_H_
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/unguessable_token.h"
-#include "content/browser/devtools/devtools_url_request_interceptor.h"
-#include "content/browser/devtools/protocol/network.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/resource_type.h"
-#include "net/cookies/canonical_cookie.h"
-#include "net/http/http_raw_request_headers.h"
-#include "net/http/http_response_headers.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_job.h"
-
-namespace net {
-class AuthChallengeInfo;
-class UploadDataStream;
-}
-
-namespace content {
-
-// A URLRequestJob that allows programmatic request blocking / modification or
-// response mocking.  This class should only be accessed on the IO thread.
-class DevToolsURLInterceptorRequestJob : public net::URLRequestJob {
- public:
-  DevToolsURLInterceptorRequestJob(
-      DevToolsURLRequestInterceptor* interceptor,
-      const std::string& interception_id,
-      intptr_t owning_entry_id,
-      net::URLRequest* original_request,
-      net::NetworkDelegate* original_network_delegate,
-      const base::UnguessableToken& devtools_token,
-      DevToolsNetworkInterceptor::RequestInterceptedCallback callback,
-      ResourceType resource_type,
-      DevToolsNetworkInterceptor::InterceptionStage stage_to_intercept);
-
-  ~DevToolsURLInterceptorRequestJob() override;
-
-  // net::URLRequestJob implementation:
-  void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
-  void Start() override;
-  void Kill() override;
-  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
-  int GetResponseCode() const override;
-  void GetResponseInfo(net::HttpResponseInfo* info) override;
-  bool GetMimeType(std::string* mime_type) const override;
-  bool GetCharset(std::string* charset) override;
-  void GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override;
-  bool NeedsAuth() override;
-  std::unique_ptr<net::AuthChallengeInfo> GetAuthChallengeInfo() override;
-
-  void SetAuth(const net::AuthCredentials& credentials) override;
-  void CancelAuth() override;
-  void SetRequestHeadersCallback(net::RequestHeadersCallback callback) override;
-  void SetResponseHeadersCallback(
-      net::ResponseHeadersCallback callback) override;
-  void ContinueDespiteLastError() override;
-
-  // Must be called on IO thread.
-  void StopIntercepting();
-
-  using ContinueInterceptedRequestCallback =
-      protocol::Network::Backend::ContinueInterceptedRequestCallback;
-  using GetResponseBodyForInterceptionCallback =
-      protocol::Network::Backend::GetResponseBodyForInterceptionCallback;
-  using InterceptionStage = DevToolsNetworkInterceptor::InterceptionStage;
-
-  // Must be called only once per interception. Must be called on IO thread.
-  void ContinueInterceptedRequest(
-      std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modifications,
-      std::unique_ptr<ContinueInterceptedRequestCallback> callback);
-  void GetResponseBody(
-      std::unique_ptr<GetResponseBodyForInterceptionCallback> callback);
-
-  intptr_t owning_entry_id() const { return owning_entry_id_; }
-
- private:
-  std::unique_ptr<InterceptedRequestInfo> BuildRequestInfo();
-
-  class SubRequest;
-  class InterceptedRequest;
-  class MockResponseDetails;
-
-  // We keep a copy of the original request details to facilitate the
-  // Network.modifyRequest command which could potentially change any of these
-  // fields.
-  struct RequestDetails {
-    RequestDetails(const GURL& url,
-                   const GURL& site_for_cookies,
-                   base::Optional<url::Origin> initiator,
-                   const std::string& method,
-                   std::unique_ptr<net::UploadDataStream> post_data,
-                   const net::HttpRequestHeaders& extra_request_headers,
-                   const std::string& referrer,
-                   net::URLRequest::ReferrerPolicy referrer_policy,
-                   const net::RequestPriority& priority,
-                   const net::URLRequestContext* url_request_context);
-    ~RequestDetails();
-
-    GURL url;
-    GURL site_for_cookies;
-    base::Optional<url::Origin> initiator;
-    std::string method;
-    std::unique_ptr<net::UploadDataStream> post_data;
-    std::string cookie_line;
-    net::HttpRequestHeaders extra_request_headers;
-    std::string referrer;
-    net::URLRequest::ReferrerPolicy referrer_policy;
-    net::RequestPriority priority;
-    const net::URLRequestContext* url_request_context;
-  };
-
-  void StartWithCookies(const net::CookieList& cookies,
-                        const net::CookieStatusList& excluded_cookies);
-
-  // Callbacks from SubRequest.
-  void OnSubRequestAuthRequired(const net::AuthChallengeInfo& auth_info);
-  void OnSubRequestRedirectReceived(const net::URLRequest& request,
-                                    const net::RedirectInfo& redirectinfo,
-                                    bool* defer_redirect);
-  void OnSubRequestResponseStarted(const net::Error& net_error);
-  void OnSubRequestHeadersReceived(const net::Error& net_error);
-
-  // Callbacks from InterceptedRequest.
-  void OnInterceptedRequestResponseStarted(const net::Error& net_error);
-  void OnInterceptedRequestResponseReady(const net::IOBuffer& buf, int result);
-
-  // Retrieves the response headers from either the |sub_request_| or the
-  // |mock_response_|.  In some cases (e.g. file access) this may be null.
-  const net::HttpResponseHeaders* GetHttpResponseHeaders() const;
-
-  void ProcessRedirect(int status_code, const std::string& new_url);
-  void ProcessInterceptionResponse(
-      std::unique_ptr<DevToolsNetworkInterceptor::Modifications> modification);
-
-  void ProcessAuthResponse(
-      const DevToolsNetworkInterceptor::AuthChallengeResponse& response);
-
-  enum class WaitingForUserResponse {
-    NOT_WAITING,
-    WAITING_FOR_REQUEST_ACK,
-    WAITING_FOR_RESPONSE_ACK,
-    WAITING_FOR_AUTH_ACK,
-  };
-
-  DevToolsURLRequestInterceptor* const interceptor_;
-  RequestDetails request_details_;
-  std::unique_ptr<SubRequest> sub_request_;
-  std::unique_ptr<MockResponseDetails> mock_response_details_;
-  std::unique_ptr<net::RedirectInfo> redirect_;
-  WaitingForUserResponse waiting_for_user_response_;
-  std::unique_ptr<net::AuthChallengeInfo> auth_info_;
-
-  const std::string interception_id_;
-  const intptr_t owning_entry_id_;
-  const base::UnguessableToken devtools_token_;
-  DevToolsNetworkInterceptor::RequestInterceptedCallback callback_;
-  const ResourceType resource_type_;
-  InterceptionStage stage_to_intercept_;
-  std::vector<std::unique_ptr<GetResponseBodyForInterceptionCallback>>
-      pending_body_requests_;
-
-  net::RequestHeadersCallback request_headers_callback_;
-  net::ResponseHeadersCallback response_headers_callback_;
-  base::WeakPtrFactory<DevToolsURLInterceptorRequestJob> weak_ptr_factory_{
-      this};
-
-  DISALLOW_COPY_AND_ASSIGN(DevToolsURLInterceptorRequestJob);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_INTERCEPTOR_REQUEST_JOB_H_
diff --git a/content/browser/devtools/devtools_url_request_interceptor.cc b/content/browser/devtools/devtools_url_request_interceptor.cc
deleted file mode 100644
index f5531d495..0000000
--- a/content/browser/devtools/devtools_url_request_interceptor.cc
+++ /dev/null
@@ -1,305 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/devtools/devtools_url_request_interceptor.h"
-
-#include "base/bind.h"
-#include "base/strings/pattern.h"
-#include "base/strings/stringprintf.h"
-#include "base/task/post_task.h"
-#include "content/browser/devtools/devtools_interceptor_controller.h"
-#include "content/browser/devtools/devtools_url_interceptor_request_job.h"
-#include "content/browser/devtools/protocol/network_handler.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_request_info.h"
-#include "net/url_request/url_request.h"
-#include "services/network/public/cpp/features.h"
-
-namespace content {
-
-// static
-std::unique_ptr<DevToolsURLRequestInterceptor>
-DevToolsURLRequestInterceptor::MaybeCreate(BrowserContext* browser_context) {
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    return nullptr;
-
-  // TODO(caseq): Technically, this is wrong -- we currently maintain one
-  // interception controller per browser context, while in reality it is
-  // created per StoragePartition.
-  // So we only support interception for the first StoragePartition, which
-  // results in extensions not being supported. Luckily, this implementation
-  // of the interception is going away when network service is enabled.
-  if (DevToolsInterceptorController::FromBrowserContext(browser_context))
-    return nullptr;
-  return std::make_unique<DevToolsURLRequestInterceptor>(browser_context);
-}
-
-// static
-bool DevToolsURLRequestInterceptor::IsNavigationRequest(
-    ResourceType resource_type) {
-  return resource_type == ResourceType::kMainFrame ||
-         resource_type == ResourceType::kSubFrame;
-}
-
-DevToolsURLRequestInterceptor::DevToolsURLRequestInterceptor(
-    BrowserContext* browser_context)
-    : next_id_(0) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  auto target_registry = std::make_unique<DevToolsTargetRegistry>(
-      base::CreateSingleThreadTaskRunnerWithTraits(
-          {content::BrowserThread::IO}));
-  target_resolver_ = target_registry->CreateResolver();
-  // Controller lifetime is managed by the browser context.
-  auto* controller = new DevToolsInterceptorController(
-      weak_factory_.GetWeakPtr(), std::move(target_registry), browser_context);
-  controller_ = controller->weak_factory_.GetWeakPtr();
-}
-
-DevToolsURLRequestInterceptor::~DevToolsURLRequestInterceptor() {
-  // The BrowserContext owns us, so we don't need to unregister
-  // DevToolsURLRequestInterceptorUserData explicitly.
-}
-
-const DevToolsTargetRegistry::TargetInfo*
-DevToolsURLRequestInterceptor::TargetInfoForRequestInfo(
-    ResourceRequestInfo* request_info) const {
-  int frame_node_id = request_info->GetFrameTreeNodeId();
-  if (frame_node_id != -1)
-    return target_resolver_->GetInfoByFrameTreeNodeId(frame_node_id);
-  return target_resolver_->GetInfoByRenderFramePair(
-      request_info->GetChildID(), request_info->GetRenderFrameID());
-}
-
-void DevToolsURLRequestInterceptor::ContinueInterceptedRequest(
-    std::string interception_id,
-    std::unique_ptr<Modifications> modifications,
-    std::unique_ptr<ContinueInterceptedRequestCallback> callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DevToolsURLInterceptorRequestJob* job = GetJob(interception_id);
-  if (!job) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(
-            &ContinueInterceptedRequestCallback::sendFailure,
-            std::move(callback),
-            protocol::Response::InvalidParams("Invalid InterceptionId.")));
-    return;
-  }
-
-  job->ContinueInterceptedRequest(std::move(modifications),
-                                  std::move(callback));
-}
-
-net::URLRequestJob* DevToolsURLRequestInterceptor::MaybeInterceptRequest(
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate) const {
-  return const_cast<DevToolsURLRequestInterceptor*>(this)
-      ->InnerMaybeInterceptRequest(request, network_delegate);
-}
-
-net::URLRequestJob* DevToolsURLRequestInterceptor::MaybeInterceptRedirect(
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate,
-    const GURL& location) const {
-  return nullptr;
-}
-
-net::URLRequestJob* DevToolsURLRequestInterceptor::MaybeInterceptResponse(
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate) const {
-  return nullptr;
-}
-
-void DevToolsURLRequestInterceptor::GetResponseBody(
-    std::string interception_id,
-    std::unique_ptr<GetResponseBodyForInterceptionCallback> callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DevToolsURLInterceptorRequestJob* job = GetJob(interception_id);
-  if (!job) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(
-            &GetResponseBodyForInterceptionCallback::sendFailure,
-            std::move(callback),
-            protocol::Response::InvalidParams("Invalid InterceptionId.")));
-    return;
-  }
-
-  job->GetResponseBody(std::move(callback));
-}
-
-net::URLRequestJob* DevToolsURLRequestInterceptor::InnerMaybeInterceptRequest(
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  // Bail out if we're not intercepting anything.
-  if (target_id_to_entries_.empty())
-    return nullptr;
-  // Don't try to intercept blob resources.
-  if (request->url().SchemeIsBlob())
-    return nullptr;
-  ResourceRequestInfo* resource_request_info =
-      ResourceRequestInfo::ForRequest(request);
-  if (!resource_request_info)
-    return nullptr;
-  const DevToolsTargetRegistry::TargetInfo* target_info =
-      TargetInfoForRequestInfo(resource_request_info);
-  if (!target_info)
-    return nullptr;
-
-  // We don't want to intercept our own sub requests.
-  if (sub_requests_.find(request) != sub_requests_.end())
-    return nullptr;
-
-  ResourceType resource_type = resource_request_info->GetResourceType();
-  InterceptionStage interception_stage;
-  FilterEntry* entry =
-      FilterEntryForRequest(target_info->devtools_target_id, request->url(),
-                            resource_type, &interception_stage);
-  if (!entry)
-    return nullptr;
-  DCHECK(interception_stage != DONT_INTERCEPT);
-
-  std::string interception_id = base::StringPrintf("id-%zu", ++next_id_);
-
-  if (IsNavigationRequest(resource_type)) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(&DevToolsInterceptorController::NavigationStarted,
-                       controller_, interception_id,
-                       resource_request_info->GetGlobalRequestID()));
-  }
-
-  DevToolsURLInterceptorRequestJob* job = new DevToolsURLInterceptorRequestJob(
-      this, interception_id, reinterpret_cast<intptr_t>(entry), request,
-      network_delegate, target_info->devtools_token, entry->callback,
-      resource_request_info->GetResourceType(), interception_stage);
-  interception_id_to_job_map_[interception_id] = job;
-  return job;
-}
-
-void DevToolsURLRequestInterceptor::AddFilterEntry(
-    std::unique_ptr<FilterEntry> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  const base::UnguessableToken& target_id = entry->target_id;
-  auto it = target_id_to_entries_.find(target_id);
-  if (it == target_id_to_entries_.end()) {
-    it = target_id_to_entries_
-             .emplace(target_id, std::vector<std::unique_ptr<FilterEntry>>())
-             .first;
-  }
-  it->second.push_back(std::move(entry));
-}
-
-void DevToolsURLRequestInterceptor::RemoveFilterEntry(
-    const FilterEntry* entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  // NOTE: Calling DevToolsURLInterceptorRequestJob::StopIntercepting can
-  // destruct the jobs which can remove entries in
-  // |interception_id_to_job_map_|, so we make a copy.
-  base::flat_map<std::string, DevToolsURLInterceptorRequestJob*> jobs(
-      interception_id_to_job_map_);
-  for (const auto pair : jobs) {
-    if (pair.second->owning_entry_id() == reinterpret_cast<intptr_t>(entry))
-      pair.second->StopIntercepting();
-  }
-
-  auto it = target_id_to_entries_.find(entry->target_id);
-  if (it == target_id_to_entries_.end())
-    return;
-  base::EraseIf(it->second, [entry](const std::unique_ptr<FilterEntry>& e) {
-    return e.get() == entry;
-  });
-  if (it->second.empty())
-    target_id_to_entries_.erase(it);
-}
-
-void DevToolsURLRequestInterceptor::UpdatePatterns(
-    FilterEntry* entry,
-    std::vector<Pattern> patterns) {
-  entry->patterns = std::move(patterns);
-}
-
-DevToolsURLRequestInterceptor::FilterEntry*
-DevToolsURLRequestInterceptor::FilterEntryForRequest(
-    const base::UnguessableToken target_id,
-    const GURL& url,
-    ResourceType resource_type,
-    InterceptionStage* stage) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  *stage = DONT_INTERCEPT;
-
-  auto it = target_id_to_entries_.find(target_id);
-  if (it == target_id_to_entries_.end())
-    return nullptr;
-
-  const std::vector<std::unique_ptr<FilterEntry>>& entries = it->second;
-  std::string unused;
-  const std::string url_str =
-      protocol::NetworkHandler::ExtractFragment(url, &unused);
-  for (const auto& entry : entries) {
-    for (const Pattern& pattern : entry->patterns) {
-      if (!pattern.resource_types.empty() &&
-          pattern.resource_types.find(resource_type) ==
-              pattern.resource_types.end()) {
-        continue;
-      }
-      if (base::MatchPattern(url_str, pattern.url_pattern)) {
-        if (pattern.interception_stage == REQUEST && *stage == RESPONSE) {
-          *stage = BOTH;
-          break;
-        } else if (pattern.interception_stage == RESPONSE &&
-                   *stage == REQUEST) {
-          *stage = BOTH;
-          break;
-        }
-        *stage = pattern.interception_stage;
-      }
-    }
-    if (*stage != DONT_INTERCEPT)
-      return entry.get();
-  }
-  return nullptr;
-}
-
-void DevToolsURLRequestInterceptor::RegisterSubRequest(
-    const net::URLRequest* sub_request) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(sub_requests_.find(sub_request) == sub_requests_.end());
-  sub_requests_.insert(sub_request);
-}
-
-void DevToolsURLRequestInterceptor::UnregisterSubRequest(
-    const net::URLRequest* sub_request) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(sub_requests_.find(sub_request) != sub_requests_.end());
-  sub_requests_.erase(sub_request);
-}
-
-DevToolsURLInterceptorRequestJob* DevToolsURLRequestInterceptor::GetJob(
-    const std::string& interception_id) const {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  const auto it = interception_id_to_job_map_.find(interception_id);
-  if (it == interception_id_to_job_map_.end())
-    return nullptr;
-  return it->second;
-}
-
-void DevToolsURLRequestInterceptor::JobFinished(
-    const std::string& interception_id,
-    bool is_navigation) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  interception_id_to_job_map_.erase(interception_id);
-  if (!is_navigation)
-    return;
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(&DevToolsInterceptorController::NavigationFinished,
-                     controller_, interception_id));
-}
-
-}  // namespace content
diff --git a/content/browser/devtools/devtools_url_request_interceptor.h b/content/browser/devtools/devtools_url_request_interceptor.h
deleted file mode 100644
index f855d85..0000000
--- a/content/browser/devtools/devtools_url_request_interceptor.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_REQUEST_INTERCEPTOR_H_
-#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_REQUEST_INTERCEPTOR_H_
-
-#include "base/containers/flat_map.h"
-#include "base/containers/flat_set.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
-#include "base/unguessable_token.h"
-#include "content/browser/devtools/devtools_network_interceptor.h"
-#include "content/browser/devtools/devtools_target_registry.h"
-#include "content/public/common/resource_type.h"
-#include "net/url_request/url_request_interceptor.h"
-
-namespace content {
-
-class BrowserContext;
-class DevToolsInterceptorController;
-class DevToolsTargetRegistry;
-class DevToolsURLInterceptorRequestJob;
-class ResourceRequestInfo;
-
-// An interceptor that creates DevToolsURLInterceptorRequestJobs for requests
-// from pages where interception has been enabled via
-// Network.setRequestInterceptionEnabled.
-// This class is constructed on the UI thread but only accessed on IO thread.
-class DevToolsURLRequestInterceptor : public net::URLRequestInterceptor,
-                                      public DevToolsNetworkInterceptor {
- public:
-  static std::unique_ptr<DevToolsURLRequestInterceptor> MaybeCreate(
-      BrowserContext* browser_context);
-
-  static bool IsNavigationRequest(ResourceType resource_type);
-
-  explicit DevToolsURLRequestInterceptor(BrowserContext* browser_context);
-  ~DevToolsURLRequestInterceptor() override;
-
-  // DevToolsNetworkInterceptor implementation.
-  void AddFilterEntry(std::unique_ptr<FilterEntry> entry) override;
-  void RemoveFilterEntry(const FilterEntry* entry) override;
-  void UpdatePatterns(FilterEntry* entry,
-                      std::vector<Pattern> patterns) override;
-  void GetResponseBody(std::string interception_id,
-                       std::unique_ptr<GetResponseBodyForInterceptionCallback>
-                           callback) override;
-  void ContinueInterceptedRequest(
-      std::string interception_id,
-      std::unique_ptr<Modifications> modifications,
-      std::unique_ptr<ContinueInterceptedRequestCallback> callback) override;
-
-  // net::URLRequestInterceptor implementation.
-  net::URLRequestJob* MaybeInterceptRequest(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override;
-
-  net::URLRequestJob* MaybeInterceptRedirect(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate,
-      const GURL& location) const override;
-
-  net::URLRequestJob* MaybeInterceptResponse(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override;
-
-  // Registers a |sub_request| that should not be intercepted.
-  void RegisterSubRequest(const net::URLRequest* sub_request);
-  void UnregisterSubRequest(const net::URLRequest* sub_request);
-  void JobFinished(const std::string& interception_id, bool is_navigation);
-
- private:
-  net::URLRequestJob* InnerMaybeInterceptRequest(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate);
-
-  FilterEntry* FilterEntryForRequest(base::UnguessableToken target_id,
-                                     const GURL& url,
-                                     ResourceType resource_type,
-                                     InterceptionStage* stage);
-
-  const DevToolsTargetRegistry::TargetInfo* TargetInfoForRequestInfo(
-      ResourceRequestInfo* request_info) const;
-
-  // Returns a WeakPtr to the DevToolsURLInterceptorRequestJob corresponding
-  // to |interception_id|.
-  DevToolsURLInterceptorRequestJob* GetJob(
-      const std::string& interception_id) const;
-
-  std::unique_ptr<DevToolsTargetRegistry::Resolver> target_resolver_;
-  base::WeakPtr<DevToolsInterceptorController> controller_;
-
-  base::flat_map<base::UnguessableToken,
-                 std::vector<std::unique_ptr<FilterEntry>>>
-      target_id_to_entries_;
-
-  base::flat_map<std::string, DevToolsURLInterceptorRequestJob*>
-      interception_id_to_job_map_;
-
-  // The DevToolsURLInterceptorRequestJob proxies a sub request to actually
-  // fetch the bytes from the network. We don't want to intercept those
-  // requests.
-  base::flat_set<const net::URLRequest*> sub_requests_;
-
-  size_t next_id_;
-
-  base::WeakPtrFactory<DevToolsURLRequestInterceptor> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(DevToolsURLRequestInterceptor);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_URL_REQUEST_INTERCEPTOR_H_
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 53004d7b..961b12c 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -815,7 +815,7 @@
   base::Optional<url::Origin> request_initiator =
       resource_request->request_initiator;
 
-  ResourceRequestInfo::WebContentsGetter web_contents_getter =
+  WebContents::Getter web_contents_getter =
       base::BindRepeating(WebContents::FromFrameTreeNodeId, frame_tree_node_id);
 
   base::OnceCallback<void(bool /* download allowed */)>
@@ -1174,7 +1174,7 @@
 }
 
 void DownloadManagerImpl::InterceptNavigationOnChecksComplete(
-    ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    WebContents::Getter web_contents_getter,
     std::unique_ptr<network::ResourceRequest> resource_request,
     std::vector<GURL> url_chain,
     net::CertStatus cert_status,
@@ -1339,9 +1339,8 @@
   bool content_initiated = params->content_initiated();
   // If it's from the web, we don't trust it, so we push the throttle on.
   if (rfh && content_initiated) {
-    ResourceRequestInfo::WebContentsGetter web_contents_getter =
-        base::BindRepeating(WebContents::FromFrameTreeNodeId,
-                            rfh->GetFrameTreeNodeId());
+    WebContents::Getter web_contents_getter = base::BindRepeating(
+        WebContents::FromFrameTreeNodeId, rfh->GetFrameTreeNodeId());
     const GURL& url = params->url();
     const std::string& method = params->method();
 
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index afd4b835..ad26dd7 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -264,7 +264,7 @@
       const GURL& site_url);
 
   void InterceptNavigationOnChecksComplete(
-      ResourceRequestInfo::WebContentsGetter web_contents_getter,
+      WebContents::Getter web_contents_getter,
       std::unique_ptr<network::ResourceRequest> resource_request,
       std::vector<GURL> url_chain,
       net::CertStatus cert_status,
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 512c3d9..976ac19 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -755,9 +755,13 @@
         browser_context->GetClientHintsControllerDelegate();
     if (client_hints_delegate) {
       net::HttpRequestHeaders client_hints_headers;
+      RenderViewHost* render_view_host =
+          frame_tree_node->current_frame_host()->GetRenderViewHost();
+      const bool javascript_enabled =
+          render_view_host->GetWebkitPreferences().javascript_enabled;
       AddNavigationRequestClientHintsHeaders(
           common_params_->url, &client_hints_headers, browser_context,
-          client_hints_delegate);
+          javascript_enabled, client_hints_delegate);
       headers.MergeFrom(client_hints_headers);
     }
 
@@ -1828,9 +1832,13 @@
       browser_context->GetClientHintsControllerDelegate();
   if (client_hints_delegate) {
     net::HttpRequestHeaders client_hints_extra_headers;
+    RenderViewHost* render_view_host =
+        frame_tree_node_->current_frame_host()->GetRenderViewHost();
+    const bool javascript_enabled =
+        render_view_host->GetWebkitPreferences().javascript_enabled;
     AddNavigationRequestClientHintsHeaders(
         common_params_->url, &client_hints_extra_headers, browser_context,
-        client_hints_delegate);
+        javascript_enabled, client_hints_delegate);
     modified_headers.MergeFrom(client_hints_extra_headers);
   }
 
diff --git a/content/browser/loader/loader_browsertest.cc b/content/browser/loader/loader_browsertest.cc
index e3ffe22e5..4fd3d38 100644
--- a/content/browser/loader/loader_browsertest.cc
+++ b/content/browser/loader/loader_browsertest.cc
@@ -24,7 +24,6 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/network_service_util.h"
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc
index 55ec61e4..5c4fd01 100644
--- a/content/browser/loader/resource_request_info_impl.cc
+++ b/content/browser/loader/resource_request_info_impl.cc
@@ -186,8 +186,7 @@
 ResourceRequestInfoImpl::~ResourceRequestInfoImpl() {
 }
 
-ResourceRequestInfo::WebContentsGetter
-ResourceRequestInfoImpl::GetWebContentsGetterForRequest() {
+WebContents::Getter ResourceRequestInfoImpl::GetWebContentsGetterForRequest() {
   // If we have a window id, try to use that.
   if (fetch_window_id_) {
     if (auto getter =
diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h
index cbdd3c2..92985b6 100644
--- a/content/browser/loader/resource_request_info_impl.h
+++ b/content/browser/loader/resource_request_info_impl.h
@@ -71,7 +71,7 @@
   ~ResourceRequestInfoImpl() override;
 
   // ResourceRequestInfo implementation:
-  WebContentsGetter GetWebContentsGetterForRequest() override;
+  WebContents::Getter GetWebContentsGetterForRequest() override;
   FrameTreeNodeIdGetter GetFrameTreeNodeIdGetterForRequest() override;
   ResourceContext* GetContext() override;
   int GetChildID() override;
diff --git a/content/browser/native_file_system/file_system_chooser_browsertest.cc b/content/browser/native_file_system/file_system_chooser_browsertest.cc
index 6ddca2e..057142d 100644
--- a/content/browser/native_file_system/file_system_chooser_browsertest.cc
+++ b/content/browser/native_file_system/file_system_chooser_browsertest.cc
@@ -140,6 +140,7 @@
                    JsReplace("(async () => {"
                              "  const w = await self.entry.createWriter();"
                              "  await w.write(0, new Blob([$1]));"
+                             "  await w.close();"
                              "  return (await self.entry.getFile()).size; })()",
                              file_contents)));
   {
diff --git a/content/browser/native_file_system/native_file_system_file_handle_impl.cc b/content/browser/native_file_system/native_file_system_file_handle_impl.cc
index 822d0532..8d71b72 100644
--- a/content/browser/native_file_system/native_file_system_file_handle_impl.cc
+++ b/content/browser/native_file_system/native_file_system_file_handle_impl.cc
@@ -5,6 +5,8 @@
 #include "content/browser/native_file_system/native_file_system_file_handle_impl.h"
 
 #include "base/guid.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
 #include "net/base/mime_util.h"
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_impl.h"
@@ -68,12 +70,13 @@
 }
 
 void NativeFileSystemFileHandleImpl::CreateFileWriter(
+    bool keep_existing_data,
     CreateFileWriterCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   RunWithWritePermission(
       base::BindOnce(&NativeFileSystemFileHandleImpl::CreateFileWriterImpl,
-                     weak_factory_.GetWeakPtr()),
+                     weak_factory_.GetWeakPtr(), keep_existing_data),
       base::BindOnce([](CreateFileWriterCallback callback) {
         std::move(callback).Run(
             NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
@@ -138,14 +141,122 @@
 }
 
 void NativeFileSystemFileHandleImpl::CreateFileWriterImpl(
+    bool keep_existing_data,
     CreateFileWriterCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_EQ(GetWritePermissionStatus(),
             blink::mojom::PermissionStatus::GRANTED);
 
+  // We first attempt to create the swap file, even if we might do a subsequent
+  // operation to copy a file to the same path if keep_existing_data is set.
+  // This file creation has to be `exclusive`, meaning, it will fail if a file
+  // already exists. Using the filesystem for synchronization, a successful
+  // creation of the file ensures that this File Writer creation request owns
+  // the file and eliminates possible race conditions.
+  auto base_swap_path =
+      base::FilePath(url().path()).AddExtensionASCII(".crswap");
+  CreateSwapFile(
+      /*count=*/0, base_swap_path, keep_existing_data, std::move(callback));
+}
+
+void NativeFileSystemFileHandleImpl::CreateSwapFile(
+    int count,
+    const base::FilePath& base_swap_path,
+    bool keep_existing_data,
+    CreateFileWriterCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(count >= 0);
+  DCHECK(max_swap_files_ >= 0);
+
+  if (GetWritePermissionStatus() != blink::mojom::PermissionStatus::GRANTED) {
+    std::move(callback).Run(
+        NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
+        nullptr);
+    return;
+  }
+
+  if (count >= max_swap_files_) {
+    DLOG(ERROR) << "Error Creating Swap File, count: " << count
+                << " exceeds max unique files of: " << max_swap_files_
+                << " base path: " << base_swap_path;
+    std::move(callback).Run(
+        NativeFileSystemError::New(base::File::FILE_ERROR_MAX), nullptr);
+    return;
+  }
+
+  auto swap_path = base_swap_path;
+  if (count > 0) {
+    swap_path = base_swap_path.InsertBeforeExtensionASCII(
+        base::StringPrintf(".%d", count));
+  }
+
+  storage::FileSystemURL swap_url =
+      manager()->context()->CreateCrackedFileSystemURL(url().origin().GetURL(),
+                                                       url().type(), swap_path);
+
+  operation_runner()->CreateFile(
+      swap_url,
+      /*exclusive=*/true,
+      base::BindOnce(&NativeFileSystemFileHandleImpl::DidCreateSwapFile,
+                     weak_factory_.GetWeakPtr(), count, base_swap_path,
+                     swap_url, keep_existing_data, std::move(callback)));
+}
+
+void NativeFileSystemFileHandleImpl::DidCreateSwapFile(
+    int count,
+    const base::FilePath& base_swap_path,
+    const storage::FileSystemURL& swap_url,
+    bool keep_existing_data,
+    CreateFileWriterCallback callback,
+    base::File::Error result) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (result == base::File::FILE_ERROR_EXISTS) {
+    // Creation attempt failed. We need to find an unused filename.
+    CreateSwapFile(count + 1, base_swap_path, keep_existing_data,
+                   std::move(callback));
+    return;
+  }
+
+  if (result != base::File::FILE_OK) {
+    DLOG(ERROR) << "Error Creating Swap File, status: "
+                << base::File::ErrorToString(result)
+                << " path: " << swap_url.path();
+    std::move(callback).Run(NativeFileSystemError::New(result), nullptr);
+    return;
+  }
+
+  if (!keep_existing_data) {
+    std::move(callback).Run(NativeFileSystemError::New(base::File::FILE_OK),
+                            manager()->CreateFileWriter(
+                                context(), url(), swap_url, handle_state()));
+    return;
+  }
+
+  operation_runner()->Copy(
+      url(), swap_url,
+      storage::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED,
+      storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT,
+      storage::FileSystemOperation::CopyProgressCallback(),
+      base::BindOnce(&NativeFileSystemFileHandleImpl::DidCopySwapFile,
+                     weak_factory_.GetWeakPtr(), swap_url,
+                     std::move(callback)));
+}
+
+void NativeFileSystemFileHandleImpl::DidCopySwapFile(
+    const storage::FileSystemURL& swap_url,
+    CreateFileWriterCallback callback,
+    base::File::Error result) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (result != base::File::FILE_OK) {
+    DLOG(ERROR) << "Error Creating Swap File, status: "
+                << base::File::ErrorToString(result)
+                << " path: " << swap_url.path();
+    std::move(callback).Run(NativeFileSystemError::New(result), nullptr);
+    return;
+  }
   std::move(callback).Run(
       NativeFileSystemError::New(base::File::FILE_OK),
-      manager()->CreateFileWriter(context(), url(), handle_state()));
+      manager()->CreateFileWriter(context(), url(), swap_url, handle_state()));
 }
 
 base::WeakPtr<NativeFileSystemHandleBase>
diff --git a/content/browser/native_file_system/native_file_system_file_handle_impl.h b/content/browser/native_file_system/native_file_system_file_handle_impl.h
index 72d0cc3..a2edb0e 100644
--- a/content/browser/native_file_system/native_file_system_file_handle_impl.h
+++ b/content/browser/native_file_system/native_file_system_file_handle_impl.h
@@ -43,16 +43,39 @@
   void RequestPermission(bool writable,
                          RequestPermissionCallback callback) override;
   void AsBlob(AsBlobCallback callback) override;
-  void CreateFileWriter(CreateFileWriterCallback callback) override;
+  void CreateFileWriter(bool keep_existing_data,
+                        CreateFileWriterCallback callback) override;
   void Transfer(
       blink::mojom::NativeFileSystemTransferTokenRequest token) override;
 
+  void set_max_swap_files_for_testing(int max) { max_swap_files_ = max; }
+
  private:
   void DidGetMetaDataForBlob(AsBlobCallback callback,
                              base::File::Error result,
                              const base::File::Info& info);
 
-  void CreateFileWriterImpl(CreateFileWriterCallback callback);
+  void CreateFileWriterImpl(bool keep_existing_data,
+                            CreateFileWriterCallback callback);
+  void CreateSwapFile(int count,
+                      const base::FilePath& base_swap_path,
+                      bool keep_existing_data,
+                      CreateFileWriterCallback callback);
+  void DidCreateSwapFile(int count,
+                         const base::FilePath& base_swap_path,
+                         const storage::FileSystemURL& swap_url,
+                         bool keep_existing_data,
+                         CreateFileWriterCallback callback,
+                         base::File::Error result);
+  void DidCopySwapFile(const storage::FileSystemURL& swap_url,
+                       CreateFileWriterCallback callback,
+                       base::File::Error result);
+
+  // A FileWriter will write to a "swap" file until the `Close()` operation is
+  // called to swap the file into the target path. For each writer, a new swap
+  // file is created. This sets the limit on the number of swap files per
+  // handle.
+  int max_swap_files_ = 100;
 
   base::WeakPtr<NativeFileSystemHandleBase> AsWeakPtr() override;
 
diff --git a/content/browser/native_file_system/native_file_system_file_handle_impl_unittest.cc b/content/browser/native_file_system/native_file_system_file_handle_impl_unittest.cc
new file mode 100644
index 0000000..fbc471e
--- /dev/null
+++ b/content/browser/native_file_system/native_file_system_file_handle_impl_unittest.cc
@@ -0,0 +1,157 @@
+// 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 "content/browser/native_file_system/native_file_system_file_handle_impl.h"
+
+#include <limits>
+#include "base/bind.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
+#include "content/browser/native_file_system/fixed_native_file_system_permission_grant.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/fileapi/file_stream_reader.h"
+#include "storage/browser/test/async_file_test_helper.h"
+#include "storage/browser/test/test_file_system_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
+
+using storage::FileSystemURL;
+
+namespace content {
+
+using blink::mojom::PermissionStatus;
+using storage::FileSystemURL;
+
+class NativeFileSystemFileHandleImplTest : public testing::Test {
+ public:
+  NativeFileSystemFileHandleImplTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::IO) {
+    scoped_feature_list_.InitAndEnableFeature(
+        blink::features::kNativeFileSystemAPI);
+  }
+
+  void SetUp() override {
+    ASSERT_TRUE(dir_.CreateUniqueTempDir());
+    file_system_context_ = CreateFileSystemContextForTesting(
+        /*quota_manager_proxy=*/nullptr, dir_.GetPath());
+
+    test_url_ = file_system_context_->CreateCrackedFileSystemURL(
+        GURL("http://example.com"), storage::kFileSystemTypeTest,
+        base::FilePath::FromUTF8Unsafe("test"));
+
+    ASSERT_EQ(base::File::FILE_OK, AsyncFileTestHelper::CreateFile(
+                                       file_system_context_.get(), test_url_));
+
+    chrome_blob_context_ = base::MakeRefCounted<ChromeBlobStorageContext>();
+    chrome_blob_context_->InitializeOnIOThread(base::FilePath(), nullptr);
+
+    manager_ = base::MakeRefCounted<NativeFileSystemManagerImpl>(
+        file_system_context_, chrome_blob_context_,
+        /*permission_context=*/nullptr);
+
+    handle_ = std::make_unique<NativeFileSystemFileHandleImpl>(
+        manager_.get(),
+        NativeFileSystemManagerImpl::BindingContext(
+            test_url_.origin(), /*process_id=*/1,
+            /*frame_id=*/MSG_ROUTING_NONE),
+        test_url_,
+        NativeFileSystemManagerImpl::SharedHandleState(
+            allow_grant_, allow_grant_, /*file_system=*/{}));
+  }
+
+  std::string ReadFile(const FileSystemURL& url) {
+    std::unique_ptr<storage::FileStreamReader> reader =
+        file_system_context_->CreateFileStreamReader(
+            url, 0, std::numeric_limits<int64_t>::max(), base::Time());
+    std::string result;
+    while (true) {
+      auto buf = base::MakeRefCounted<net::IOBufferWithSize>(4096);
+      net::TestCompletionCallback callback;
+      int rv = reader->Read(buf.get(), buf->size(), callback.callback());
+      if (rv == net::ERR_IO_PENDING)
+        rv = callback.WaitForResult();
+      EXPECT_GE(rv, 0);
+      if (rv < 0)
+        return "(read failure)";
+      if (rv == 0)
+        return result;
+      result.append(buf->data(), rv);
+    }
+  }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  TestBrowserThreadBundle scoped_task_environment_;
+
+  base::ScopedTempDir dir_;
+  scoped_refptr<storage::FileSystemContext> file_system_context_;
+  scoped_refptr<ChromeBlobStorageContext> chrome_blob_context_;
+  scoped_refptr<NativeFileSystemManagerImpl> manager_;
+
+  FileSystemURL test_url_;
+
+  scoped_refptr<FixedNativeFileSystemPermissionGrant> allow_grant_ =
+      base::MakeRefCounted<FixedNativeFileSystemPermissionGrant>(
+          FixedNativeFileSystemPermissionGrant::PermissionStatus::GRANTED);
+  std::unique_ptr<NativeFileSystemFileHandleImpl> handle_;
+};
+
+TEST_F(NativeFileSystemFileHandleImplTest, CreateFileWriterOverLimitNotOK) {
+  int max_files = 5;
+  handle_->set_max_swap_files_for_testing(max_files);
+
+  const FileSystemURL base_swap_url =
+      file_system_context_->CreateCrackedFileSystemURL(
+          GURL("http://example.com"), storage::kFileSystemTypeTest,
+          base::FilePath::FromUTF8Unsafe("test.crswap"));
+
+  std::vector<blink::mojom::NativeFileSystemFileWriterPtr> writers;
+  for (int i = 0; i < max_files; i++) {
+    FileSystemURL swap_url;
+    if (i == 0) {
+      swap_url = base_swap_url;
+    } else {
+      swap_url = file_system_context_->CreateCrackedFileSystemURL(
+          GURL("http://example.com"), storage::kFileSystemTypeTest,
+          base::FilePath::FromUTF8Unsafe(
+              base::StringPrintf("test.%d.crswap", i)));
+    }
+
+    base::RunLoop loop;
+    handle_->CreateFileWriter(
+        /*keepExistingData=*/false,
+        base::BindLambdaForTesting(
+            [&](blink::mojom::NativeFileSystemErrorPtr result,
+                blink::mojom::NativeFileSystemFileWriterPtr writer_ptr) {
+              EXPECT_EQ(base::File::FILE_OK, result->error_code);
+              EXPECT_EQ("", ReadFile(swap_url));
+              writers.push_back(std::move(writer_ptr));
+              loop.Quit();
+            }));
+    loop.Run();
+  }
+
+  base::RunLoop loop;
+  handle_->CreateFileWriter(
+      /*keepExistingData=*/false,
+      base::BindLambdaForTesting(
+          [&](blink::mojom::NativeFileSystemErrorPtr result,
+              blink::mojom::NativeFileSystemFileWriterPtr writer_ptr) {
+            EXPECT_EQ(base::File::FILE_ERROR_MAX, result->error_code);
+            loop.Quit();
+          }));
+  loop.Run();
+}
+
+}  // namespace content
diff --git a/content/browser/native_file_system/native_file_system_file_writer_impl.cc b/content/browser/native_file_system/native_file_system_file_writer_impl.cc
index fb0bddfa..50218af6 100644
--- a/content/browser/native_file_system/native_file_system_file_writer_impl.cc
+++ b/content/browser/native_file_system/native_file_system_file_writer_impl.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "content/browser/native_file_system/native_file_system_file_writer_impl.h"
+#include "base/logging.h"
 #include "content/browser/native_file_system/native_file_system_manager_impl.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/fileapi/file_system_operation_runner.h"
@@ -24,14 +25,30 @@
     NativeFileSystemManagerImpl* manager,
     const BindingContext& context,
     const storage::FileSystemURL& url,
+    const storage::FileSystemURL& swap_url,
     const SharedHandleState& handle_state)
     : NativeFileSystemHandleBase(manager,
                                  context,
                                  url,
                                  handle_state,
-                                 /*is_directory=*/false) {}
+                                 /*is_directory=*/false),
+      swap_url_(swap_url) {}
 
-NativeFileSystemFileWriterImpl::~NativeFileSystemFileWriterImpl() = default;
+NativeFileSystemFileWriterImpl::~NativeFileSystemFileWriterImpl() {
+  if (can_purge()) {
+    manager()->operation_runner()->RemoveFile(
+        swap_url(), base::BindOnce(
+                        [](const storage::FileSystemURL& swap_url,
+                           base::File::Error result) {
+                          if (result != base::File::FILE_OK) {
+                            DLOG(ERROR) << "Error Deleting Swap File, status: "
+                                        << base::File::ErrorToString(result)
+                                        << " path: " << swap_url.path();
+                          }
+                        },
+                        swap_url()));
+  }
+}
 
 void NativeFileSystemFileWriterImpl::Write(uint64_t offset,
                                            blink::mojom::BlobPtr data,
@@ -44,7 +61,7 @@
       base::BindOnce([](WriteCallback callback) {
         std::move(callback).Run(
             NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
-            0);
+            /*bytes_written=*/0);
       }),
       std::move(callback));
 }
@@ -61,7 +78,7 @@
       base::BindOnce([](WriteStreamCallback callback) {
         std::move(callback).Run(
             NativeFileSystemError::New(base::File::FILE_ERROR_ACCESS_DENIED),
-            0);
+            /*bytes_written=*/0);
       }),
       std::move(callback));
 }
@@ -100,6 +117,13 @@
   DCHECK_EQ(GetWritePermissionStatus(),
             blink::mojom::PermissionStatus::GRANTED);
 
+  if (is_closed()) {
+    std::move(callback).Run(
+        NativeFileSystemError::New(base::File::FILE_ERROR_INVALID_OPERATION),
+        /*bytes_written=*/0);
+    return;
+  }
+
   blob_context()->GetBlobDataFromBlobPtr(
       std::move(data),
       base::BindOnce(&NativeFileSystemFileWriterImpl::DoWriteBlob,
@@ -114,12 +138,13 @@
 
   if (!blob) {
     std::move(callback).Run(
-        NativeFileSystemError::New(base::File::FILE_ERROR_FAILED), 0);
+        NativeFileSystemError::New(base::File::FILE_ERROR_FAILED),
+        /*bytes_written=*/0);
     return;
   }
 
   operation_runner()->Write(
-      url(), std::move(blob), position,
+      swap_url(), std::move(blob), position,
       base::BindRepeating(&NativeFileSystemFileWriterImpl::DidWrite,
                           weak_factory_.GetWeakPtr(),
                           base::Owned(new WriteState{std::move(callback)})));
@@ -133,8 +158,15 @@
   DCHECK_EQ(GetWritePermissionStatus(),
             blink::mojom::PermissionStatus::GRANTED);
 
+  if (is_closed()) {
+    std::move(callback).Run(
+        NativeFileSystemError::New(base::File::FILE_ERROR_INVALID_OPERATION),
+        /*bytes_written=*/0);
+    return;
+  }
+
   operation_runner()->Write(
-      url(), std::move(stream), offset,
+      swap_url(), std::move(stream), offset,
       base::BindRepeating(&NativeFileSystemFileWriterImpl::DidWrite,
                           weak_factory_.GetWeakPtr(),
                           base::Owned(new WriteState{std::move(callback)})));
@@ -160,8 +192,14 @@
   DCHECK_EQ(GetWritePermissionStatus(),
             blink::mojom::PermissionStatus::GRANTED);
 
+  if (is_closed()) {
+    std::move(callback).Run(
+        NativeFileSystemError::New(base::File::FILE_ERROR_INVALID_OPERATION));
+    return;
+  }
+
   operation_runner()->Truncate(
-      url(), length,
+      swap_url(), length,
       base::BindOnce(
           [](TruncateCallback callback, base::File::Error result) {
             std::move(callback).Run(NativeFileSystemError::New(result));
@@ -173,7 +211,41 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_EQ(GetWritePermissionStatus(),
             blink::mojom::PermissionStatus::GRANTED);
-  std::move(callback).Run(NativeFileSystemError::New(base::File::FILE_OK));
+  if (is_closed()) {
+    std::move(callback).Run(
+        NativeFileSystemError::New(base::File::FILE_ERROR_INVALID_OPERATION));
+    return;
+  }
+
+  // Should the writer be destructed at this point, we want to allow the
+  // close operation to run its course, so we should not purge the swap file.
+  state_ = State::kClosePending;
+
+  // If the move operation succeeds, the path pointing to the swap file
+  // will not exist anymore.
+  // In case of error, the swap file URL will point to a valid filesystem
+  // location. The file at this URL will be deleted when the mojo pipe closes.
+  // TODO(https://crbug.com/968556): Hook safebrowsing here, before the move.
+  operation_runner()->Move(
+      swap_url(), url(),
+      storage::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED,
+      base::BindOnce(&NativeFileSystemFileWriterImpl::DidSwapFileBeforeClose,
+                     weak_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void NativeFileSystemFileWriterImpl::DidSwapFileBeforeClose(
+    CloseCallback callback,
+    base::File::Error result) {
+  if (result != base::File::FILE_OK) {
+    state_ = State::kCloseError;
+    DLOG(ERROR) << "Swap file move operation failed source: "
+                << swap_url().path() << " dest: " << url().path()
+                << " error: " << base::File::ErrorToString(result);
+  } else {
+    state_ = State::kClosed;
+  }
+
+  std::move(callback).Run(NativeFileSystemError::New(result));
 }
 
 base::WeakPtr<NativeFileSystemHandleBase>
diff --git a/content/browser/native_file_system/native_file_system_file_writer_impl.h b/content/browser/native_file_system/native_file_system_file_writer_impl.h
index 0ce1b4e..679f54ab 100644
--- a/content/browser/native_file_system/native_file_system_file_writer_impl.h
+++ b/content/browser/native_file_system/native_file_system_file_writer_impl.h
@@ -31,11 +31,19 @@
     : public NativeFileSystemHandleBase,
       public blink::mojom::NativeFileSystemFileWriter {
  public:
+  // Creates a FileWriter that writes in a swap file URL and
+  // materializes the changes in the target file URL only after `Close`
+  // is invoked and successfully completes. Assumes that swap_url represents a
+  // file, and is valid.
   NativeFileSystemFileWriterImpl(NativeFileSystemManagerImpl* manager,
                                  const BindingContext& context,
                                  const storage::FileSystemURL& url,
+                                 const storage::FileSystemURL& swap_url,
                                  const SharedHandleState& handle_state);
   ~NativeFileSystemFileWriterImpl() override;
+
+  const storage::FileSystemURL& swap_url() const { return swap_url_; }
+
   void Write(uint64_t offset,
              blink::mojom::BlobPtr data,
              WriteCallback callback) override;
@@ -66,6 +74,33 @@
                 bool complete);
   void TruncateImpl(uint64_t length, TruncateCallback callback);
   void CloseImpl(CloseCallback callback);
+  void DidSwapFileBeforeClose(CloseCallback callback, base::File::Error result);
+
+  enum class State {
+    // The writer accepts write operations.
+    kOpen,
+    // The writer does not accept write operations and is in the process of
+    // closing.
+    kClosePending,
+    // The writer does not accept write operations and has entered an error
+    // state.
+    kCloseError,
+    // The writer does not accept write operations and has closed successfully.
+    kClosed,
+  };
+  bool is_closed() const { return state_ != State::kOpen; }
+  // Returns whether the File Writer is in a state where any files can be
+  // deleted. We do not want to delete the files if there are clean-up
+  // operations in-flight.
+  bool can_purge() const {
+    return state_ == State::kOpen || state_ == State::kCloseError;
+  }
+
+  // We write using this file URL. When `Close()` is invoked, we
+  // execute a move operation from the swap URL to the target URL at `url_`. In
+  // most filesystems, this move operation is atomic.
+  storage::FileSystemURL swap_url_;
+  State state_ = State::kOpen;
 
   base::WeakPtr<NativeFileSystemHandleBase> AsWeakPtr() override;
 
diff --git a/content/browser/native_file_system/native_file_system_file_writer_impl_browsertest.cc b/content/browser/native_file_system/native_file_system_file_writer_impl_browsertest.cc
new file mode 100644
index 0000000..0212381
--- /dev/null
+++ b/content/browser/native_file_system/native_file_system_file_writer_impl_browsertest.cc
@@ -0,0 +1,269 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/browser/native_file_system/file_system_chooser_test_helpers.h"
+#include "content/browser/native_file_system/native_file_system_manager_impl.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "third_party/blink/public/common/features.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+#include "ui/shell_dialogs/select_file_dialog_factory.h"
+#include "ui/shell_dialogs/select_file_policy.h"
+
+namespace content {
+
+// This browser test implements end-to-end tests for
+// NativeFileSystemFileWriterImpl.
+class NativeFileSystemFileWriterBrowserTest : public ContentBrowserTest {
+ public:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    scoped_feature_list_.InitAndEnableFeature(
+        blink::features::kNativeFileSystemAPI);
+
+    ASSERT_TRUE(embedded_test_server()->Start());
+
+    ContentBrowserTest::SetUp();
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // Enable experimental web platform features to enable write access.
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
+  }
+
+  void TearDown() override {
+    ContentBrowserTest::TearDown();
+    ASSERT_TRUE(temp_dir_.Delete());
+    ui::SelectFileDialog::SetFactory(nullptr);
+  }
+
+  std::pair<base::FilePath, base::FilePath> CreateTestFilesAndEntry(
+      const std::string& contents) {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    base::FilePath test_file;
+    EXPECT_TRUE(
+        base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &test_file));
+    EXPECT_EQ(int{contents.size()},
+              base::WriteFile(test_file, contents.data(), contents.size()));
+
+    ui::SelectFileDialog::SetFactory(
+        new FakeSelectFileDialogFactory({test_file}));
+    EXPECT_TRUE(
+        NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
+    EXPECT_EQ(
+        test_file.BaseName().AsUTF8Unsafe(),
+        EvalJs(
+            shell(),
+            "(async () => {"
+            "  let e = await self.chooseFileSystemEntries({type: 'openFile'});"
+            "  self.entry = e;"
+            "  self.writers = [];"
+            "  return e.name; })()"));
+
+    const base::FilePath swap_file =
+        base::FilePath(test_file).AddExtensionASCII(".crswap");
+    return std::make_pair(test_file, swap_file);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  base::ScopedTempDir temp_dir_;
+};
+
+IN_PROC_BROWSER_TEST_F(NativeFileSystemFileWriterBrowserTest,
+                       ContentsWrittenToSwapFileFirst) {
+  base::FilePath test_file, swap_file;
+  std::tie(test_file, swap_file) = CreateTestFilesAndEntry("");
+  const std::string file_contents = "file contents to write";
+
+  EXPECT_EQ(0,
+            EvalJs(shell(),
+                   JsReplace("(async () => {"
+                             "  const w = await self.entry.createWriter();"
+                             "  await w.write(0, new Blob([$1]));"
+                             "  self.writer = w;"
+                             "  return (await self.entry.getFile()).size; })()",
+                             file_contents)));
+  {
+    // Destination file should be empty, contents written in the swap file.
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    std::string read_contents;
+    EXPECT_TRUE(base::ReadFileToString(test_file, &read_contents));
+    EXPECT_EQ("", read_contents);
+    std::string swap_contents;
+    EXPECT_TRUE(base::ReadFileToString(swap_file, &swap_contents));
+    EXPECT_EQ(file_contents, swap_contents);
+  }
+
+  // Contents now in destination file.
+  EXPECT_EQ(int{file_contents.size()},
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  await self.writer.close();"
+                   "  return (await self.entry.getFile()).size; })()"));
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    std::string read_contents;
+    EXPECT_TRUE(base::ReadFileToString(test_file, &read_contents));
+    EXPECT_EQ(file_contents, read_contents);
+
+    EXPECT_FALSE(base::PathExists(swap_file));
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(NativeFileSystemFileWriterBrowserTest,
+                       KeepExistingDataHasPreviousContent) {
+  const std::string initial_contents = "fooks";
+  const std::string expected_contents = "barks";
+  base::FilePath test_file, swap_file;
+  std::tie(test_file, swap_file) = CreateTestFilesAndEntry(initial_contents);
+
+  EXPECT_EQ(true, EvalJs(shell(),
+                         "(async () => {"
+                         "  try {"
+                         "    const w = await self.entry.createWriter({"
+                         "      keepExistingData: true });"
+                         "    self.writer = w;"
+                         "    return true;"
+                         "  } catch (e) { return false; }"
+                         "})()"));
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    EXPECT_TRUE(base::PathExists(swap_file));
+    std::string swap_contents;
+    EXPECT_TRUE(base::ReadFileToString(swap_file, &swap_contents));
+    EXPECT_EQ(initial_contents, swap_contents);
+  }
+
+  EXPECT_EQ(int{expected_contents.size()},
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  await self.writer.write(0, new Blob(['bar']));"
+                   "  await self.writer.close();"
+                   "  return (await self.entry.getFile()).size; })()"));
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    std::string read_contents;
+    EXPECT_TRUE(base::ReadFileToString(test_file, &read_contents));
+    EXPECT_EQ(expected_contents, read_contents);
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(NativeFileSystemFileWriterBrowserTest,
+                       CreateWriterNoKeepExistingWithEmptyFile) {
+  const std::string initial_contents = "very long string";
+  const std::string expected_contents = "bar";
+  base::FilePath test_file, swap_file;
+  std::tie(test_file, swap_file) = CreateTestFilesAndEntry(initial_contents);
+
+  EXPECT_EQ(true, EvalJs(shell(),
+                         "(async () => {"
+                         "  try {"
+                         "    const w = await self.entry.createWriter({"
+                         "      keepExistingData: false });"
+                         "    self.writer = w;"
+                         "    return true;"
+                         "  } catch (e) { return false; }"
+                         "})()"));
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    EXPECT_TRUE(base::PathExists(swap_file));
+    std::string swap_contents;
+    EXPECT_TRUE(base::ReadFileToString(swap_file, &swap_contents));
+    EXPECT_EQ("", swap_contents);
+  }
+
+  EXPECT_EQ(int{expected_contents.size()},
+            EvalJs(shell(),
+                   "(async () => {"
+                   "  await self.writer.write(0, new Blob(['bar']));"
+                   "  await self.writer.close();"
+                   "  return (await self.entry.getFile()).size; })()"));
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    std::string read_contents;
+    EXPECT_TRUE(base::ReadFileToString(test_file, &read_contents));
+    EXPECT_EQ(expected_contents, read_contents);
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(NativeFileSystemFileWriterBrowserTest,
+                       EachWriterHasUniqueSwapFile) {
+  base::FilePath test_file, base_swap_file;
+  std::tie(test_file, base_swap_file) = CreateTestFilesAndEntry("");
+
+  int num_writers = 5;
+  for (int index = 0; index < num_writers; index++) {
+    EXPECT_EQ(true, EvalJs(shell(),
+                           "(async () => {"
+                           "  try {"
+                           "    const w = await self.entry.createWriter();"
+                           "    self.writers.push(w);"
+                           "    return true;"
+                           "  } catch (e) { return false; }"
+                           "})()"));
+  }
+
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    for (int index = 0; index < num_writers; index++) {
+      base::FilePath swap_file = base_swap_file;
+      if (index != 0) {
+        swap_file = base::FilePath(test_file).AddExtensionASCII(
+            base::StringPrintf(".%d.crswap", index));
+      }
+      EXPECT_TRUE(base::PathExists(swap_file));
+    }
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(NativeFileSystemFileWriterBrowserTest,
+                       EachWriterHasUniqueSwapFileRacy) {
+  base::FilePath test_file, base_swap_file;
+  std::tie(test_file, base_swap_file) = CreateTestFilesAndEntry("");
+
+  int num_writers = 5;
+  for (int index = 0; index < num_writers; index++) {
+    EXPECT_EQ(
+        true,
+        EvalJs(shell(),
+               JsReplace("(async () => {"
+                         "  try {"
+                         "    for(let i = 0; i < $1; i++ ) {"
+                         "      self.writers.push(self.entry.createWriter());"
+                         "    }"
+                         "    await Promise.all(self.writers);"
+                         "    return true;"
+                         "  } catch (e) { return false; }"
+                         "})()",
+                         num_writers)));
+  }
+
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    for (int index = 0; index < num_writers; index++) {
+      base::FilePath swap_file = base_swap_file;
+      if (index != 0) {
+        swap_file = base::FilePath(test_file).AddExtensionASCII(
+            base::StringPrintf(".%d.crswap", index));
+      }
+      EXPECT_TRUE(base::PathExists(swap_file));
+    }
+  }
+}
+
+}  // namespace content
diff --git a/content/browser/native_file_system/native_file_system_file_writer_impl_unittest.cc b/content/browser/native_file_system/native_file_system_file_writer_impl_unittest.cc
index fa6b50f..03d01e6 100644
--- a/content/browser/native_file_system/native_file_system_file_writer_impl_unittest.cc
+++ b/content/browser/native_file_system/native_file_system_file_writer_impl_unittest.cc
@@ -50,9 +50,17 @@
         GURL("http://example.com"), storage::kFileSystemTypeTest,
         base::FilePath::FromUTF8Unsafe("test"));
 
+    test_swap_url_ = file_system_context_->CreateCrackedFileSystemURL(
+        GURL("http://example.com"), storage::kFileSystemTypeTest,
+        base::FilePath::FromUTF8Unsafe("test.crswap"));
+
     ASSERT_EQ(base::File::FILE_OK, AsyncFileTestHelper::CreateFile(
                                        file_system_context_.get(), test_url_));
 
+    ASSERT_EQ(base::File::FILE_OK,
+              AsyncFileTestHelper::CreateFile(file_system_context_.get(),
+                                              test_swap_url_));
+
     chrome_blob_context_ = base::MakeRefCounted<ChromeBlobStorageContext>();
     chrome_blob_context_->InitializeOnIOThread(base::FilePath(), nullptr);
     blob_context_ = chrome_blob_context_->context();
@@ -66,7 +74,7 @@
         NativeFileSystemManagerImpl::BindingContext(
             test_url_.origin(), /*process_id=*/1,
             /*frame_id=*/MSG_ROUTING_NONE),
-        test_url_,
+        test_url_, test_swap_url_,
         NativeFileSystemManagerImpl::SharedHandleState(
             permission_grant_, permission_grant_, /*file_system=*/{}));
   }
@@ -208,6 +216,7 @@
   scoped_refptr<NativeFileSystemManagerImpl> manager_;
 
   FileSystemURL test_url_;
+  FileSystemURL test_swap_url_;
 
   scoped_refptr<FixedNativeFileSystemPermissionGrant> permission_grant_ =
       base::MakeRefCounted<FixedNativeFileSystemPermissionGrant>(
@@ -235,6 +244,9 @@
   EXPECT_EQ(result, base::File::FILE_ERROR_FAILED);
   EXPECT_EQ(bytes_written, 0u);
 
+  result = CloseSync();
+  EXPECT_EQ(result, base::File::FILE_OK);
+
   EXPECT_EQ("", ReadFile(test_url_));
 }
 
@@ -244,6 +256,9 @@
   EXPECT_EQ(result, base::File::FILE_OK);
   EXPECT_EQ(bytes_written, 0u);
 
+  result = CloseSync();
+  EXPECT_EQ(result, base::File::FILE_OK);
+
   EXPECT_EQ("", ReadFile(test_url_));
 }
 
@@ -254,6 +269,9 @@
   EXPECT_EQ(result, base::File::FILE_OK);
   EXPECT_EQ(bytes_written, test_data.size());
 
+  result = CloseSync();
+  EXPECT_EQ(result, base::File::FILE_OK);
+
   EXPECT_EQ(test_data, ReadFile(test_url_));
 }
 
@@ -269,6 +287,9 @@
   EXPECT_EQ(result, base::File::FILE_OK);
   EXPECT_EQ(bytes_written, 3u);
 
+  result = CloseSync();
+  EXPECT_EQ(result, base::File::FILE_OK);
+
   EXPECT_EQ("1234abc890", ReadFile(test_url_));
 }
 
@@ -278,18 +299,10 @@
   EXPECT_EQ(result, base::File::FILE_ERROR_FAILED);
   EXPECT_EQ(bytes_written, 0u);
 
-  EXPECT_EQ("", ReadFile(test_url_));
-}
-
-TEST_F(NativeFileSystemFileWriterImplTest, CloseOK) {
-  uint64_t bytes_written;
-  base::File::Error result = WriteSync(0, "abc", &bytes_written);
-  EXPECT_EQ(result, base::File::FILE_OK);
-  EXPECT_EQ(bytes_written, 3u);
   result = CloseSync();
   EXPECT_EQ(result, base::File::FILE_OK);
 
-  EXPECT_EQ("abc", ReadFile(test_url_));
+  EXPECT_EQ("", ReadFile(test_url_));
 }
 
 TEST_F(NativeFileSystemFileWriterImplTest, TruncateShrink) {
@@ -303,6 +316,9 @@
   result = TruncateSync(5);
   EXPECT_EQ(result, base::File::FILE_OK);
 
+  result = CloseSync();
+  EXPECT_EQ(result, base::File::FILE_OK);
+
   EXPECT_EQ("12345", ReadFile(test_url_));
 }
 
@@ -317,9 +333,50 @@
   result = TruncateSync(5);
   EXPECT_EQ(result, base::File::FILE_OK);
 
+  result = CloseSync();
+  EXPECT_EQ(result, base::File::FILE_OK);
+
   EXPECT_EQ(std::string("abc\0\0", 5), ReadFile(test_url_));
 }
 
+TEST_F(NativeFileSystemFileWriterImplTest, CloseAfterCloseNotOK) {
+  uint64_t bytes_written;
+  base::File::Error result = WriteSync(0, "abc", &bytes_written);
+  EXPECT_EQ(result, base::File::FILE_OK);
+  EXPECT_EQ(bytes_written, 3u);
+
+  result = CloseSync();
+  EXPECT_EQ(result, base::File::FILE_OK);
+  result = CloseSync();
+  EXPECT_EQ(result, base::File::FILE_ERROR_INVALID_OPERATION);
+}
+
+TEST_F(NativeFileSystemFileWriterImplTest, TruncateAfterCloseNotOK) {
+  uint64_t bytes_written;
+  base::File::Error result = WriteSync(0, "abc", &bytes_written);
+  EXPECT_EQ(result, base::File::FILE_OK);
+  EXPECT_EQ(bytes_written, 3u);
+
+  result = CloseSync();
+  EXPECT_EQ(result, base::File::FILE_OK);
+
+  result = TruncateSync(0);
+  EXPECT_EQ(result, base::File::FILE_ERROR_INVALID_OPERATION);
+}
+
+TEST_P(NativeFileSystemFileWriterImplWriteTest, WriteAfterCloseNotOK) {
+  uint64_t bytes_written;
+  base::File::Error result = WriteSync(0, "abc", &bytes_written);
+  EXPECT_EQ(result, base::File::FILE_OK);
+  EXPECT_EQ(bytes_written, 3u);
+
+  result = CloseSync();
+  EXPECT_EQ(result, base::File::FILE_OK);
+
+  result = WriteSync(0, "bcd", &bytes_written);
+  EXPECT_EQ(result, base::File::FILE_ERROR_INVALID_OPERATION);
+}
+
 // TODO(mek): More tests, particularly for error conditions.
 
 }  // namespace content
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.cc b/content/browser/native_file_system/native_file_system_manager_impl.cc
index a4a104f..1b166c4d3 100644
--- a/content/browser/native_file_system/native_file_system_manager_impl.cc
+++ b/content/browser/native_file_system/native_file_system_manager_impl.cc
@@ -5,6 +5,7 @@
 #include "content/browser/native_file_system/native_file_system_manager_impl.h"
 
 #include "base/files/file_path.h"
+#include "base/logging.h"
 #include "base/task/post_task.h"
 #include "content/browser/native_file_system/file_system_chooser.h"
 #include "content/browser/native_file_system/fixed_native_file_system_permission_grant.h"
@@ -291,13 +292,16 @@
 NativeFileSystemManagerImpl::CreateFileWriter(
     const BindingContext& binding_context,
     const storage::FileSystemURL& url,
+    const storage::FileSystemURL& swap_url,
     const SharedHandleState& handle_state) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   blink::mojom::NativeFileSystemFileWriterPtr result;
-  writer_bindings_.AddBinding(std::make_unique<NativeFileSystemFileWriterImpl>(
-                                  this, binding_context, url, handle_state),
-                              mojo::MakeRequest(&result));
+  writer_bindings_.AddBinding(
+      std::make_unique<NativeFileSystemFileWriterImpl>(
+          this, binding_context, url, swap_url, handle_state),
+      mojo::MakeRequest(&result));
+
   return result;
 }
 
diff --git a/content/browser/native_file_system/native_file_system_manager_impl.h b/content/browser/native_file_system/native_file_system_manager_impl.h
index 3389b085..477e92e 100644
--- a/content/browser/native_file_system/native_file_system_manager_impl.h
+++ b/content/browser/native_file_system/native_file_system_manager_impl.h
@@ -121,11 +121,12 @@
       const storage::FileSystemURL& url,
       const SharedHandleState& handle_state);
 
-  // Creates a new NativeFileSystemFileWriterImpl for a given url. Assumes the
-  // passed in URL is valid and represents a file.
+  // Creates a new NativeFileSystemFileWriterImpl for a given target and
+  // swap file URLs. Assumes the passed in URLs are valid and represent files.
   blink::mojom::NativeFileSystemFileWriterPtr CreateFileWriter(
       const BindingContext& binding_context,
       const storage::FileSystemURL& url,
+      const storage::FileSystemURL& swap_url,
       const SharedHandleState& handle_state);
 
   // Create a transfer token for a specific file or directory.
diff --git a/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc b/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc
index b74c657d..7f844a3 100644
--- a/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc
+++ b/content/browser/native_file_system/native_file_system_manager_impl_unittest.cc
@@ -5,6 +5,7 @@
 #include "content/browser/native_file_system/native_file_system_manager_impl.h"
 
 #include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/test/scoped_feature_list.h"
@@ -13,6 +14,7 @@
 #include "content/browser/native_file_system/mock_native_file_system_permission_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/test/async_file_test_helper.h"
 #include "storage/browser/test/test_file_system_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
@@ -185,4 +187,76 @@
             GetPermissionStatusSync(/*writable=*/true, handle.get()));
 }
 
+TEST_F(NativeFileSystemManagerImplTest,
+       FileWriterSwapDeletedOnConnectionClose) {
+  auto test_url = file_system_context_->CreateCrackedFileSystemURL(
+      kTestOrigin.GetURL(), storage::kFileSystemTypeTest,
+      base::FilePath::FromUTF8Unsafe("test"));
+
+  auto test_swap_url = file_system_context_->CreateCrackedFileSystemURL(
+      kTestOrigin.GetURL(), storage::kFileSystemTypeTest,
+      base::FilePath::FromUTF8Unsafe("test.crswap"));
+
+  ASSERT_EQ(base::File::FILE_OK, AsyncFileTestHelper::CreateFile(
+                                     file_system_context_.get(), test_url));
+
+  ASSERT_EQ(base::File::FILE_OK,
+            AsyncFileTestHelper::CreateFile(file_system_context_.get(),
+                                            test_swap_url));
+
+  auto writer_ptr =
+      manager_->CreateFileWriter(kBindingContext, test_url, test_swap_url,
+                                 NativeFileSystemManagerImpl::SharedHandleState(
+                                     allow_grant_, allow_grant_, {}));
+
+  ASSERT_TRUE(writer_ptr.is_bound());
+  ASSERT_TRUE(
+      AsyncFileTestHelper::FileExists(file_system_context_.get(), test_swap_url,
+                                      AsyncFileTestHelper::kDontCheckSize));
+
+  // Severs the mojo pipe, causing the writer to be destroyed.
+  writer_ptr.reset();
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_FALSE(
+      AsyncFileTestHelper::FileExists(file_system_context_.get(), test_swap_url,
+                                      AsyncFileTestHelper::kDontCheckSize));
+}
+
+TEST_F(NativeFileSystemManagerImplTest,
+       FileWriterCloseAllowedToCompleteOnDestruct) {
+  auto test_url = file_system_context_->CreateCrackedFileSystemURL(
+      kTestOrigin.GetURL(), storage::kFileSystemTypeTest,
+      base::FilePath::FromUTF8Unsafe("test"));
+
+  auto test_swap_url = file_system_context_->CreateCrackedFileSystemURL(
+      kTestOrigin.GetURL(), storage::kFileSystemTypeTest,
+      base::FilePath::FromUTF8Unsafe("test.crswap"));
+
+  ASSERT_EQ(base::File::FILE_OK,
+            AsyncFileTestHelper::CreateFileWithData(file_system_context_.get(),
+                                                    test_swap_url, "foo", 3));
+
+  auto writer_ptr =
+      manager_->CreateFileWriter(kBindingContext, test_url, test_swap_url,
+                                 NativeFileSystemManagerImpl::SharedHandleState(
+                                     allow_grant_, allow_grant_, {}));
+
+  ASSERT_TRUE(writer_ptr.is_bound());
+  ASSERT_FALSE(
+      AsyncFileTestHelper::FileExists(file_system_context_.get(), test_url,
+                                      AsyncFileTestHelper::kDontCheckSize));
+  writer_ptr->Close(base::DoNothing());
+
+  // Severs the mojo pipe, causing the writer to be destroyed.
+  writer_ptr.reset();
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_FALSE(
+      AsyncFileTestHelper::FileExists(file_system_context_.get(), test_swap_url,
+                                      AsyncFileTestHelper::kDontCheckSize));
+  ASSERT_TRUE(
+      AsyncFileTestHelper::FileExists(file_system_context_.get(), test_url, 3));
+}
+
 }  // namespace content
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index 0c7d33d70..1d644df9b 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -83,7 +83,7 @@
 
   void StartDataRequest(
       const std::string& path,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const WebContents::Getter& wc_getter,
       const URLDataSource::GotDataCallback& callback) override {
     std::string dummy_html = "<html><body>Foo</body></html>";
     scoped_refptr<base::RefCountedString> response =
diff --git a/content/browser/network_service_client.cc b/content/browser/network_service_client.cc
index ae35021..03c12f9 100644
--- a/content/browser/network_service_client.cc
+++ b/content/browser/network_service_client.cc
@@ -30,7 +30,6 @@
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/login_delegate.h"
 #include "content/public/browser/network_service_instance.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/network_service_util.h"
 #include "content/public/common/resource_type.h"
@@ -78,12 +77,11 @@
 // a mojo connection error occurs).
 class SSLClientAuthDelegate : public SSLClientAuthHandler::Delegate {
  public:
-  SSLClientAuthDelegate(
-      network::mojom::ClientCertificateResponderPtrInfo
-          client_cert_responder_info,
-      content::ResourceContext* resource_context,
-      ResourceRequestInfo::WebContentsGetter web_contents_getter,
-      const scoped_refptr<net::SSLCertRequestInfo>& cert_info)
+  SSLClientAuthDelegate(network::mojom::ClientCertificateResponderPtrInfo
+                            client_cert_responder_info,
+                        content::ResourceContext* resource_context,
+                        WebContents::Getter web_contents_getter,
+                        const scoped_refptr<net::SSLCertRequestInfo>& cert_info)
       : client_cert_responder_(std::move(client_cert_responder_info)),
         ssl_client_auth_handler_(std::make_unique<SSLClientAuthHandler>(
             GetContentClient()->browser()->CreateClientCertStore(
@@ -143,7 +141,7 @@
  public:
   LoginHandlerDelegate(
       network::mojom::AuthChallengeResponderPtr auth_challenge_responder,
-      ResourceRequestInfo::WebContentsGetter web_contents_getter,
+      WebContents::Getter web_contents_getter,
       const net::AuthChallengeInfo& auth_info,
       bool is_request_for_main_frame,
       uint32_t process_id,
@@ -245,7 +243,7 @@
   GURL url_;
   const scoped_refptr<net::HttpResponseHeaders> response_headers_;
   bool first_auth_attempt_;
-  ResourceRequestInfo::WebContentsGetter web_contents_getter_;
+  WebContents::Getter web_contents_getter_;
   std::unique_ptr<LoginDelegate> login_delegate_;
   base::WeakPtrFactory<LoginHandlerDelegate> weak_factory_{this};
 };
@@ -378,7 +376,7 @@
     network::mojom::ClientCertificateResponderPtrInfo
         client_cert_responder_info,
     content::ResourceContext* resource_context,
-    ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    WebContents::Getter web_contents_getter,
     scoped_refptr<net::SSLCertRequestInfo> cert_info) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   new SSLClientAuthDelegate(std::move(client_cert_responder_info),
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index 78900e0..62f76a83f 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -20,7 +20,6 @@
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_client.h"
 #include "net/base/load_flags.h"
diff --git a/content/browser/ssl/ssl_client_auth_handler.cc b/content/browser/ssl/ssl_client_auth_handler.cc
index 54e5d60..92be63ba 100644
--- a/content/browser/ssl/ssl_client_auth_handler.cc
+++ b/content/browser/ssl/ssl_client_auth_handler.cc
@@ -14,7 +14,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/client_certificate_delegate.h"
 #include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/resource_request_info.h"
 #include "net/ssl/client_cert_store.h"
 #include "net/ssl/ssl_private_key.h"
 #include "net/url_request/url_request.h"
@@ -73,7 +72,7 @@
 }
 
 void SelectCertificateOnUIThread(
-    const ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const WebContents::Getter& wc_getter,
     net::SSLCertRequestInfo* cert_request_info,
     net::ClientCertIdentityList client_certs,
     const base::WeakPtr<SSLClientAuthHandler>& handler) {
@@ -148,7 +147,7 @@
 
 SSLClientAuthHandler::SSLClientAuthHandler(
     std::unique_ptr<net::ClientCertStore> client_cert_store,
-    ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    WebContents::Getter web_contents_getter,
     net::SSLCertRequestInfo* cert_request_info,
     Delegate* delegate)
     : web_contents_getter_(web_contents_getter),
diff --git a/content/browser/ssl/ssl_client_auth_handler.h b/content/browser/ssl/ssl_client_auth_handler.h
index 541ae67..d98dca43 100644
--- a/content/browser/ssl/ssl_client_auth_handler.h
+++ b/content/browser/ssl/ssl_client_auth_handler.h
@@ -13,7 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
 #include "net/ssl/client_cert_identity.h"
 #include "net/ssl/ssl_cert_request_info.h"
 
@@ -54,11 +54,10 @@
 
   // Creates a new SSLClientAuthHandler. The caller ensures that the handler
   // does not outlive |delegate|.
-  SSLClientAuthHandler(
-      std::unique_ptr<net::ClientCertStore> client_cert_store,
-      ResourceRequestInfo::WebContentsGetter web_contents_getter,
-      net::SSLCertRequestInfo* cert_request_info,
-      Delegate* delegate);
+  SSLClientAuthHandler(std::unique_ptr<net::ClientCertStore> client_cert_store,
+                       WebContents::Getter web_contents_getter,
+                       net::SSLCertRequestInfo* cert_request_info,
+                       Delegate* delegate);
   ~SSLClientAuthHandler();
 
   // Selects a certificate and resumes the URL request with that certificate.
@@ -96,7 +95,7 @@
   // will cancel the dialog corresponding to this certificate request.
   base::OnceClosure cancellation_callback_;
 
-  ResourceRequestInfo::WebContentsGetter web_contents_getter_;
+  WebContents::Getter web_contents_getter_;
 
   // The certs to choose from.
   scoped_refptr<net::SSLCertRequestInfo> cert_request_info_;
diff --git a/content/browser/ssl/ssl_error_handler.cc b/content/browser/ssl/ssl_error_handler.cc
index c875b71a..b7be110 100644
--- a/content/browser/ssl/ssl_error_handler.cc
+++ b/content/browser/ssl/ssl_error_handler.cc
@@ -11,7 +11,6 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_request_info.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_status_flags.h"
 #include "net/url_request/url_request.h"
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc
index 93c56823..a19cb92 100644
--- a/content/browser/storage_partition_impl_map.cc
+++ b/content/browser/storage_partition_impl_map.cc
@@ -23,13 +23,11 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "content/browser/appcache/appcache_interceptor.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
 #include "content/browser/background_fetch/background_fetch_context.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/code_cache/generated_code_cache_context.h"
 #include "content/browser/cookie_store/cookie_store_context.h"
-#include "content/browser/devtools/devtools_url_request_interceptor.h"
 #include "content/browser/fileapi/browser_file_system_helper.h"
 #include "content/browser/loader/navigation_url_loader_impl.h"
 #include "content/browser/loader/prefetch_url_loader_service.h"
@@ -51,7 +49,6 @@
 #include "services/network/public/cpp/features.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/blob/blob_url_request_job_factory.h"
-#include "storage/browser/fileapi/file_system_url_request_job_factory.h"
 
 using storage::FileSystemContext;
 using storage::BlobStorageContext;
diff --git a/content/browser/webui/shared_resources_data_source.cc b/content/browser/webui/shared_resources_data_source.cc
index d58811e6..9d2308a 100644
--- a/content/browser/webui/shared_resources_data_source.cc
+++ b/content/browser/webui/shared_resources_data_source.cc
@@ -292,7 +292,7 @@
 
 void SharedResourcesDataSource::StartDataRequest(
     const std::string& path,
-    const ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const WebContents::Getter& wc_getter,
     const URLDataSource::GotDataCallback& callback) {
   std::string updated_path = path;
 #if defined(OS_CHROMEOS)
@@ -427,7 +427,7 @@
 
 // Returns true if the WebContents making the request has disabled Polymer 2.
 bool SharedResourcesDataSource::IsPolymer2DisabledForPage(
-    const ResourceRequestInfo::WebContentsGetter& wc_getter) {
+    const WebContents::Getter& wc_getter) {
   // Return false in these cases, which sometimes occur in tests.
   if (!wc_getter)
     return false;
diff --git a/content/browser/webui/shared_resources_data_source.h b/content/browser/webui/shared_resources_data_source.h
index 36b6a63..3775ca0 100644
--- a/content/browser/webui/shared_resources_data_source.h
+++ b/content/browser/webui/shared_resources_data_source.h
@@ -23,7 +23,7 @@
   std::string GetSource() override;
   void StartDataRequest(
       const std::string& path,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const WebContents::Getter& wc_getter,
       const URLDataSource::GotDataCallback& callback) override;
   bool AllowCaching() override;
   std::string GetMimeType(const std::string& path) override;
@@ -41,8 +41,7 @@
 #if defined(OS_CHROMEOS)
   std::string disabled_polymer2_host_;
 
-  bool IsPolymer2DisabledForPage(
-      const ResourceRequestInfo::WebContentsGetter& wc_getter);
+  bool IsPolymer2DisabledForPage(const WebContents::Getter& wc_getter);
 #endif  // defined (OS_CHROMEOS)
 
   ~SharedResourcesDataSource() override;
diff --git a/content/browser/webui/web_ui_data_source_impl.cc b/content/browser/webui/web_ui_data_source_impl.cc
index 84a12355..03636a1 100644
--- a/content/browser/webui/web_ui_data_source_impl.cc
+++ b/content/browser/webui/web_ui_data_source_impl.cc
@@ -69,7 +69,7 @@
   }
   void StartDataRequest(
       const std::string& path,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const WebContents::Getter& wc_getter,
       const URLDataSource::GotDataCallback& callback) override {
     return parent_->StartDataRequest(path, wc_getter, callback);
   }
@@ -267,7 +267,7 @@
 
 void WebUIDataSourceImpl::StartDataRequest(
     const std::string& path,
-    const ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const WebContents::Getter& wc_getter,
     const URLDataSource::GotDataCallback& callback) {
   if (!should_handle_request_callback_.is_null() &&
       should_handle_request_callback_.Run(path)) {
diff --git a/content/browser/webui/web_ui_data_source_impl.h b/content/browser/webui/web_ui_data_source_impl.h
index 3d09b66..2942c35 100644
--- a/content/browser/webui/web_ui_data_source_impl.h
+++ b/content/browser/webui/web_ui_data_source_impl.h
@@ -84,10 +84,9 @@
   // Methods that match URLDataSource which are called by
   // InternalDataSource.
   std::string GetMimeType(const std::string& path) const;
-  void StartDataRequest(
-      const std::string& path,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const URLDataSource::GotDataCallback& callback);
+  void StartDataRequest(const std::string& path,
+                        const WebContents::Getter& wc_getter,
+                        const URLDataSource::GotDataCallback& callback);
 
   int PathToIdrOrDefault(const std::string& path) const;
 
diff --git a/content/browser/webui/web_ui_data_source_unittest.cc b/content/browser/webui/web_ui_data_source_unittest.cc
index 246e4bcb..3a2519b 100644
--- a/content/browser/webui/web_ui_data_source_unittest.cc
+++ b/content/browser/webui/web_ui_data_source_unittest.cc
@@ -64,8 +64,7 @@
 
   void StartDataRequest(const std::string& path,
                         const URLDataSource::GotDataCallback& callback) {
-    source_->StartDataRequest(path, ResourceRequestInfo::WebContentsGetter(),
-                              callback);
+    source_->StartDataRequest(path, WebContents::Getter(), callback);
   }
 
   std::string GetMimeType(const std::string& path) const {
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc
index d6462a4..d37554be 100644
--- a/content/browser/webui/web_ui_url_loader_factory.cc
+++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -181,7 +181,7 @@
   // TODO: fill all the time related field i.e. request_time response_time
   // request_start response_start
 
-  ResourceRequestInfo::WebContentsGetter wc_getter =
+  WebContents::Getter wc_getter =
       base::Bind(WebContents::FromFrameTreeNodeId, frame_tree_node_id);
 
   bool gzipped = source->source()->IsGzipped(path);
diff --git a/content/child/webthemeengine_impl_android.cc b/content/child/webthemeengine_impl_android.cc
index 2dce7f8c..e818c14 100644
--- a/content/child/webthemeengine_impl_android.cc
+++ b/content/child/webthemeengine_impl_android.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/public/platform/web_size.h"
 #include "ui/native_theme/native_theme.h"
 
+using blink::WebColorScheme;
 using blink::WebRect;
 using blink::WebThemeEngine;
 
@@ -84,6 +85,16 @@
   }
 }
 
+static ui::NativeTheme::ColorScheme NativeColorScheme(
+    WebColorScheme color_scheme) {
+  switch (color_scheme) {
+    case WebColorScheme::kLight:
+      return ui::NativeTheme::ColorScheme::kLight;
+    case WebColorScheme::kDark:
+      return ui::NativeTheme::ColorScheme::kDark;
+  }
+}
+
 static void GetNativeThemeExtraParams(
     WebThemeEngine::Part part,
     WebThemeEngine::State state,
@@ -207,12 +218,13 @@
     WebThemeEngine::Part part,
     WebThemeEngine::State state,
     const blink::WebRect& rect,
-    const WebThemeEngine::ExtraParams* extra_params) {
+    const WebThemeEngine::ExtraParams* extra_params,
+    blink::WebColorScheme color_scheme) {
   ui::NativeTheme::ExtraParams native_theme_extra_params;
   GetNativeThemeExtraParams(
       part, state, extra_params, &native_theme_extra_params);
   ui::NativeTheme::GetInstanceForWeb()->Paint(
       canvas, NativeThemePart(part), NativeThemeState(state), gfx::Rect(rect),
-      native_theme_extra_params);
+      native_theme_extra_params, NativeColorScheme(color_scheme));
 }
 }  // namespace content
diff --git a/content/child/webthemeengine_impl_android.h b/content/child/webthemeengine_impl_android.h
index 9fb867bf..df0a40b7 100644
--- a/content/child/webthemeengine_impl_android.h
+++ b/content/child/webthemeengine_impl_android.h
@@ -20,7 +20,8 @@
              blink::WebThemeEngine::Part part,
              blink::WebThemeEngine::State state,
              const blink::WebRect& rect,
-             const blink::WebThemeEngine::ExtraParams* extra_params) override;
+             const blink::WebThemeEngine::ExtraParams* extra_params,
+             blink::WebColorScheme color_scheme) override;
 };
 
 }  // namespace content
diff --git a/content/child/webthemeengine_impl_default.cc b/content/child/webthemeengine_impl_default.cc
index c59e99a..258d5c3 100644
--- a/content/child/webthemeengine_impl_default.cc
+++ b/content/child/webthemeengine_impl_default.cc
@@ -11,9 +11,10 @@
 #include "ui/native_theme/native_theme.h"
 #include "ui/native_theme/overlay_scrollbar_constants_aura.h"
 
+using blink::WebColorScheme;
 using blink::WebRect;
-using blink::WebThemeEngine;
 using blink::WebScrollbarOverlayColorTheme;
+using blink::WebThemeEngine;
 
 namespace content {
 namespace {
@@ -34,6 +35,10 @@
 
 }  // namespace
 
+// TODO(https://crbug.com/988434): The mapping functions below are duplicated
+// inside Blink and in the Android implementation of WebThemeEngine. They should
+// be implemented in one place where dependencies between Blink and
+// ui::NativeTheme make sense.
 static ui::NativeTheme::Part NativeThemePart(
     WebThemeEngine::Part part) {
   switch (part) {
@@ -106,6 +111,16 @@
   }
 }
 
+static ui::NativeTheme::ColorScheme NativeColorScheme(
+    WebColorScheme color_scheme) {
+  switch (color_scheme) {
+    case WebColorScheme::kLight:
+      return ui::NativeTheme::ColorScheme::kLight;
+    case WebColorScheme::kDark:
+      return ui::NativeTheme::ColorScheme::kDark;
+  }
+}
+
 static void GetNativeThemeExtraParams(
     WebThemeEngine::Part part,
     WebThemeEngine::State state,
@@ -238,13 +253,14 @@
     WebThemeEngine::Part part,
     WebThemeEngine::State state,
     const blink::WebRect& rect,
-    const WebThemeEngine::ExtraParams* extra_params) {
+    const WebThemeEngine::ExtraParams* extra_params,
+    blink::WebColorScheme color_scheme) {
   ui::NativeTheme::ExtraParams native_theme_extra_params;
   GetNativeThemeExtraParams(
       part, state, extra_params, &native_theme_extra_params);
   ui::NativeTheme::GetInstanceForWeb()->Paint(
       canvas, NativeThemePart(part), NativeThemeState(state), gfx::Rect(rect),
-      native_theme_extra_params);
+      native_theme_extra_params, NativeColorScheme(color_scheme));
 }
 
 void WebThemeEngineDefault::GetOverlayScrollbarStyle(ScrollbarStyle* style) {
diff --git a/content/child/webthemeengine_impl_default.h b/content/child/webthemeengine_impl_default.h
index 51e07200..180f15c 100644
--- a/content/child/webthemeengine_impl_default.h
+++ b/content/child/webthemeengine_impl_default.h
@@ -21,7 +21,8 @@
              blink::WebThemeEngine::Part part,
              blink::WebThemeEngine::State state,
              const blink::WebRect& rect,
-             const blink::WebThemeEngine::ExtraParams* extra_params) override;
+             const blink::WebThemeEngine::ExtraParams* extra_params,
+             blink::WebColorScheme color_scheme) override;
   void GetOverlayScrollbarStyle(
       blink::WebThemeEngine::ScrollbarStyle*) override;
   bool SupportsNinePatch(Part part) const override;
diff --git a/content/public/browser/background_fetch_delegate.h b/content/public/browser/background_fetch_delegate.h
index fb28a0f2..09436ef 100644
--- a/content/public/browser/background_fetch_delegate.h
+++ b/content/public/browser/background_fetch_delegate.h
@@ -15,7 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "content/common/content_export.h"
-#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
 #include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
@@ -120,7 +120,7 @@
   // |wc_getter| can be null, which means this is running from a worker context.
   virtual void GetPermissionForOrigin(
       const url::Origin& origin,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
+      const WebContents::Getter& wc_getter,
       GetPermissionForOriginCallback callback) = 0;
 
   // Creates a new download grouping identified by |job_unique_id|. Further
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index d1a38911..4aef09d6 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -883,7 +883,7 @@
 
 bool ContentBrowserClient::HandleExternalProtocol(
     const GURL& url,
-    ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    WebContents::Getter web_contents_getter,
     int child_id,
     NavigationUIData* navigation_data,
     bool is_main_frame,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index a8436e3..da6420d6 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -31,7 +31,7 @@
 #include "content/public/browser/overlay_window.h"
 #include "content/public/browser/page_visibility_state.h"
 #include "content/public/browser/quota_permission_context.h"
-#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/navigation_policy.h"
 #include "content/public/common/previews_state.h"
@@ -1480,7 +1480,7 @@
   // nullptr.
   virtual bool HandleExternalProtocol(
       const GURL& url,
-      ResourceRequestInfo::WebContentsGetter web_contents_getter,
+      WebContents::Getter web_contents_getter,
       int child_id,
       NavigationUIData* navigation_data,
       bool is_main_frame,
diff --git a/content/public/browser/download_manager_delegate.cc b/content/public/browser/download_manager_delegate.cc
index a4f9e36..c3f5f0f9 100644
--- a/content/public/browser/download_manager_delegate.cc
+++ b/content/public/browser/download_manager_delegate.cc
@@ -59,7 +59,7 @@
 }
 
 void DownloadManagerDelegate::CheckDownloadAllowed(
-    const ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+    const WebContents::Getter& web_contents_getter,
     const GURL& url,
     const std::string& request_method,
     base::Optional<url::Origin> request_initiator,
diff --git a/content/public/browser/download_manager_delegate.h b/content/public/browser/download_manager_delegate.h
index adf813f0..fccab360 100644
--- a/content/public/browser/download_manager_delegate.h
+++ b/content/public/browser/download_manager_delegate.h
@@ -15,8 +15,8 @@
 #include "components/download/public/common/download_danger_type.h"
 #include "components/download/public/common/download_item.h"
 #include "content/common/content_export.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/save_page_type.h"
+#include "content/public/browser/web_contents.h"
 #include "url/origin.h"
 
 namespace content {
@@ -188,7 +188,7 @@
   // Checks whether download is allowed to continue. |check_download_allowed_cb|
   // is called with the decision on completion.
   virtual void CheckDownloadAllowed(
-      const ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+      const WebContents::Getter& web_contents_getter,
       const GURL& url,
       const std::string& request_method,
       base::Optional<url::Origin> request_initiator,
diff --git a/content/public/browser/resource_request_info.h b/content/public/browser/resource_request_info.h
index 9b886c5..ca70246e 100644
--- a/content/public/browser/resource_request_info.h
+++ b/content/public/browser/resource_request_info.h
@@ -10,6 +10,7 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/navigation_ui_data.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/common/resource_intercept_policy.h"
 #include "content/public/common/resource_type.h"
@@ -23,7 +24,6 @@
 
 namespace content {
 class ResourceContext;
-class WebContents;
 
 // Each URLRequest allocated by the ResourceDispatcherHost has a
 // ResourceRequestInfo instance associated with it.
@@ -68,14 +68,6 @@
   CONTENT_EXPORT static bool OriginatedFromServiceWorker(
       const net::URLRequest* request);
 
-  // A callback that returns a pointer to a WebContents. The callback can
-  // always be used, but it may return nullptr: if the info used to
-  // instantiate the callback can no longer be used to return a WebContents,
-  // nullptr will be returned instead.
-  // The callback should only run on the UI thread and it should always be
-  // non-null.
-  using WebContentsGetter = base::Callback<WebContents*(void)>;
-
   // A callback that returns a frame tree node id . The callback can always
   // be used, but it may return -1 if no id is found. The callback should only
   // run on the UI thread.
@@ -87,7 +79,7 @@
   // thread.
   // Note: Not all resource requests will be owned by a WebContents. For
   // example, requests made by a ServiceWorker.
-  virtual WebContentsGetter GetWebContentsGetterForRequest() = 0;
+  virtual WebContents::Getter GetWebContentsGetterForRequest() = 0;
 
   // Returns a callback that returns an int with the frame tree node id
   //   associated with this request, or -1 if it no longer exists. This
diff --git a/content/public/browser/url_data_source.h b/content/public/browser/url_data_source.h
index 9ccdddfa..e6f7041 100644
--- a/content/public/browser/url_data_source.h
+++ b/content/public/browser/url_data_source.h
@@ -12,7 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "content/common/content_export.h"
-#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
 
 class GURL;
 
@@ -69,10 +69,9 @@
   // |wc_getter| can be called on the UI thread to return the WebContents for
   // this request if it originates from a render frame. If it originated from a
   // worker or if the frame has destructed it will return null.
-  virtual void StartDataRequest(
-      const std::string& path,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
-      const GotDataCallback& callback) = 0;
+  virtual void StartDataRequest(const std::string& path,
+                                const WebContents::Getter& wc_getter,
+                                const GotDataCallback& callback) = 0;
 
   // The following methods are all called on the IO thread.
 
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 50236e9..8a09477 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -252,6 +252,14 @@
   CONTENT_EXPORT static WebContents* FromFrameTreeNodeId(
       int frame_tree_node_id);
 
+  // A callback that returns a pointer to a WebContents. The callback can
+  // always be used, but it may return nullptr: if the info used to
+  // instantiate the callback can no longer be used to return a WebContents,
+  // nullptr will be returned instead.
+  // The callback should only run on the UI thread and it should always be
+  // non-null.
+  using Getter = base::Callback<WebContents*(void)>;
+
   // Sets delegate for platform specific screen orientation functionality.
   CONTENT_EXPORT static void SetScreenOrientationDelegate(
       ScreenOrientationDelegate* delegate);
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 44e93f96..628643b4 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -206,10 +206,6 @@
     "media/stream/user_media_processor.h",
     "media/video_capture/local_video_capturer_source.cc",
     "media/video_capture/local_video_capturer_source.h",
-    "media/video_capture/video_capture_impl.cc",
-    "media/video_capture/video_capture_impl.h",
-    "media/video_capture/video_capture_impl_manager.cc",
-    "media/video_capture/video_capture_impl_manager.h",
     "media/webrtc/audio_codec_factory.cc",
     "media/webrtc/audio_codec_factory.h",
     "media/webrtc/media_stream_track_metrics.cc",
diff --git a/content/renderer/media/stream/media_stream_center.cc b/content/renderer/media/stream/media_stream_center.cc
index 466823ae..6d17470 100644
--- a/content/renderer/media/stream/media_stream_center.cc
+++ b/content/renderer/media/stream/media_stream_center.cc
@@ -144,14 +144,6 @@
   }
 }
 
-void MediaStreamCenter::DidSetContentHint(
-    const blink::WebMediaStreamTrack& track) {
-  blink::WebPlatformMediaStreamTrack* native_track =
-      blink::WebPlatformMediaStreamTrack::GetTrack(track);
-  if (native_track)
-    native_track->SetContentHint(track.ContentHint());
-}
-
 void MediaStreamCenter::DidEnableMediaStreamTrack(
     const blink::WebMediaStreamTrack& track) {
   blink::WebPlatformMediaStreamTrack* native_track =
@@ -196,23 +188,4 @@
   source->StopSource();
 }
 
-void MediaStreamCenter::GetSourceSettings(
-    const blink::WebMediaStreamSource& web_source,
-    blink::WebMediaStreamTrack::Settings& settings) {
-  blink::MediaStreamAudioSource* const source =
-      blink::MediaStreamAudioSource::From(web_source);
-  if (!source)
-    return;
-
-  media::AudioParameters audio_parameters = source->GetAudioParameters();
-  if (audio_parameters.IsValid()) {
-    settings.sample_rate = audio_parameters.sample_rate();
-    settings.channel_count = audio_parameters.channels();
-    settings.latency = audio_parameters.GetBufferDuration().InSecondsF();
-  }
-  // kSampleFormatS16 is the format used for all audio input streams.
-  settings.sample_size =
-      media::SampleFormatToBitsPerChannel(media::kSampleFormatS16);
-}
-
 }  // namespace content
diff --git a/content/renderer/media/stream/media_stream_center.h b/content/renderer/media/stream/media_stream_center.h
index 7dd59df..535bbb3 100644
--- a/content/renderer/media/stream/media_stream_center.h
+++ b/content/renderer/media/stream/media_stream_center.h
@@ -31,8 +31,6 @@
       const blink::WebMediaStreamTrack& original,
       const blink::WebMediaStreamTrack& clone) override;
 
-  void DidSetContentHint(const blink::WebMediaStreamTrack& track) override;
-
   void DidEnableMediaStreamTrack(
       const blink::WebMediaStreamTrack& track) override;
 
@@ -46,10 +44,6 @@
   void DidStopMediaStreamSource(
       const blink::WebMediaStreamSource& web_source) override;
 
-  void GetSourceSettings(
-      const blink::WebMediaStreamSource& web_source,
-      blink::WebMediaStreamTrack::Settings& settings) override;
-
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaStreamCenter);
diff --git a/content/renderer/media/video_capture/local_video_capturer_source.cc b/content/renderer/media/video_capture/local_video_capturer_source.cc
index f1960a0..82d1fa92 100644
--- a/content/renderer/media/video_capture/local_video_capturer_source.cc
+++ b/content/renderer/media/video_capture/local_video_capturer_source.cc
@@ -7,9 +7,9 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "content/renderer/media/video_capture/video_capture_impl_manager.h"
 #include "content/renderer/render_thread_impl.h"
 #include "media/base/bind_to_current_loop.h"
+#include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
 
 namespace content {
 
diff --git a/content/renderer/media/video_capture/local_video_capturer_source.h b/content/renderer/media/video_capture/local_video_capturer_source.h
index 1bdc499..e7376d20 100644
--- a/content/renderer/media/video_capture/local_video_capturer_source.h
+++ b/content/renderer/media/video_capture/local_video_capturer_source.h
@@ -21,14 +21,17 @@
 class SingleThreadTaskRunner;
 }
 
+namespace blink {
+class WebVideoCaptureImplManager;
+}
+
 namespace content {
 
-class VideoCaptureImplManager;
-
 // LocalVideoCapturerSource is a delegate used by MediaStreamVideoCapturerSource
-// for local video capture. It uses the Render singleton VideoCaptureImplManager
-// to start / stop and receive I420 frames from Chrome's video capture
-// implementation. This is a main Render thread only object.
+// for local video capture. It uses the Render singleton
+// WebVideoCaptureImplManager to start / stop and receive I420 frames from
+// Chrome's video capture implementation. This is a main Render thread only
+// object.
 class LocalVideoCapturerSource : public media::VideoCapturerSource {
  public:
   static std::unique_ptr<media::VideoCapturerSource> Create(
@@ -57,7 +60,7 @@
   // |session_id_| identifies the capture device used for this capture session.
   const media::VideoCaptureSessionId session_id_;
 
-  VideoCaptureImplManager* const manager_;
+  blink::WebVideoCaptureImplManager* const manager_;
 
   base::OnceClosure release_device_cb_;
 
diff --git a/content/renderer/pepper/pepper_platform_camera_device.cc b/content/renderer/pepper/pepper_platform_camera_device.cc
index 93bce4a0..8b8cb28 100644
--- a/content/renderer/pepper/pepper_platform_camera_device.cc
+++ b/content/renderer/pepper/pepper_platform_camera_device.cc
@@ -8,13 +8,13 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "content/renderer/media/video_capture/video_capture_impl_manager.h"
 #include "content/renderer/pepper/gfx_conversion.h"
 #include "content/renderer/pepper/pepper_camera_device_host.h"
 #include "content/renderer/pepper/pepper_media_device_manager.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
 #include "media/base/bind_to_current_loop.h"
+#include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
 
 namespace content {
 
@@ -41,7 +41,7 @@
 
 void PepperPlatformCameraDevice::GetSupportedVideoCaptureFormats() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  VideoCaptureImplManager* manager =
+  blink::WebVideoCaptureImplManager* manager =
       RenderThreadImpl::current()->video_capture_impl_manager();
   manager->GetDeviceSupportedFormats(
       session_id_,
@@ -93,7 +93,7 @@
     label_ = label;
     session_id_ =
         device_manager->GetSessionID(PP_DEVICETYPE_DEV_VIDEOCAPTURE, label);
-    VideoCaptureImplManager* manager =
+    blink::WebVideoCaptureImplManager* manager =
         RenderThreadImpl::current()->video_capture_impl_manager();
     release_device_cb_ = manager->UseDevice(session_id_);
   }
diff --git a/content/renderer/pepper/pepper_platform_camera_device.h b/content/renderer/pepper/pepper_platform_camera_device.h
index 35a0b37..11905cf 100644
--- a/content/renderer/pepper/pepper_platform_camera_device.h
+++ b/content/renderer/pepper/pepper_platform_camera_device.h
@@ -37,7 +37,7 @@
  private:
   void OnDeviceOpened(int request_id, bool succeeded, const std::string& label);
 
-  // Called by VideoCaptureImplManager.
+  // Called by blink::WebVideoCaptureImplManager.
   void OnDeviceSupportedFormatsEnumerated(
       const media::VideoCaptureFormats& formats);
 
diff --git a/content/renderer/pepper/pepper_platform_video_capture.cc b/content/renderer/pepper/pepper_platform_video_capture.cc
index 1287f13..72dd4ce3 100644
--- a/content/renderer/pepper/pepper_platform_video_capture.cc
+++ b/content/renderer/pepper/pepper_platform_video_capture.cc
@@ -7,13 +7,13 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
-#include "content/renderer/media/video_capture/video_capture_impl_manager.h"
 #include "content/renderer/pepper/pepper_media_device_manager.h"
 #include "content/renderer/pepper/pepper_video_capture_host.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/video_frame.h"
+#include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
 
 namespace content {
 
@@ -43,7 +43,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   if (stop_capture_cb_)
     return;
-  VideoCaptureImplManager* manager =
+  blink::WebVideoCaptureImplManager* manager =
       RenderThreadImpl::current()->video_capture_impl_manager();
   stop_capture_cb_ =
       manager->StartCapture(session_id_, params,
@@ -102,7 +102,7 @@
     label_ = label;
     session_id_ = device_manager->GetSessionID(
         PP_DEVICETYPE_DEV_VIDEOCAPTURE, label);
-    VideoCaptureImplManager* manager =
+    blink::WebVideoCaptureImplManager* manager =
         RenderThreadImpl::current()->video_capture_impl_manager();
     release_device_cb_ = manager->UseDevice(session_id_);
   }
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index c47eb19..707e580 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -92,7 +92,6 @@
 #include "content/renderer/media/gpu/gpu_video_accelerator_factories_impl.h"
 #include "content/renderer/media/render_media_client.h"
 #include "content/renderer/media/stream/media_stream_center.h"
-#include "content/renderer/media/video_capture/video_capture_impl_manager.h"
 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
 #include "content/renderer/media/webrtc/peer_connection_tracker.h"
 #include "content/renderer/media/webrtc/rtc_peer_connection_handler.h"
@@ -139,6 +138,7 @@
 #include "services/viz/public/cpp/gpu/gpu.h"
 #include "skia/ext/skia_memory_dump_provider.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
 #include "third_party/blink/public/platform/web_cache.h"
 #include "third_party/blink/public/platform/web_image_generator.h"
@@ -742,7 +742,7 @@
   auto registry = std::make_unique<service_manager::BinderRegistry>();
   InitializeWebKit(registry.get());
 
-  vc_manager_.reset(new VideoCaptureImplManager());
+  vc_manager_.reset(new blink::WebVideoCaptureImplManager());
 
   browser_plugin_manager_.reset(new BrowserPluginManager());
   AddObserver(browser_plugin_manager_.get());
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 4f7588b6..d3b39bc9 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -68,6 +68,7 @@
 class SkBitmap;
 
 namespace blink {
+class WebVideoCaptureImplManager;
 class WebMediaStreamCenter;
 }
 
@@ -122,7 +123,6 @@
 class RenderThreadObserver;
 class RendererBlinkPlatformImpl;
 class ResourceDispatcher;
-class VideoCaptureImplManager;
 
 #if defined(OS_ANDROID)
 class StreamTextureFactory;
@@ -318,7 +318,7 @@
     return p2p_socket_dispatcher_.get();
   }
 
-  VideoCaptureImplManager* video_capture_impl_manager() const {
+  blink::WebVideoCaptureImplManager* video_capture_impl_manager() const {
     return vc_manager_.get();
   }
 
@@ -601,7 +601,7 @@
   base::Optional<AudioOutputIPCFactory> audio_output_ipc_factory_;
 
   // Used on the render thread.
-  std::unique_ptr<VideoCaptureImplManager> vc_manager_;
+  std::unique_ptr<blink::WebVideoCaptureImplManager> vc_manager_;
 
   // Used to keep track of the renderer's backgrounded and visibility state.
   // Updated via an IPC from the browser process. If nullopt, the browser
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index bb796c6e..0335070 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -76,7 +76,6 @@
 #include "content/renderer/internal_document_state_data.h"
 #include "content/renderer/loader/request_extra_data.h"
 #include "content/renderer/media/audio/audio_device_factory.h"
-#include "content/renderer/media/video_capture/video_capture_impl_manager.h"
 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
 #include "content/renderer/media/webrtc/rtc_peer_connection_handler.h"
 #include "content/renderer/render_frame_impl.h"
@@ -105,6 +104,7 @@
 #include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h"
 #include "third_party/blink/public/common/frame/user_activation_update_source.h"
 #include "third_party/blink/public/platform/file_path_conversion.h"
+#include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
 #include "third_party/blink/public/platform/url_conversion.h"
 #include "third_party/blink/public/platform/web_connection_type.h"
 #include "third_party/blink/public/platform/web_effective_connection_type.h"
diff --git a/content/shell/browser/web_test/web_test_background_fetch_delegate.cc b/content/shell/browser/web_test/web_test_background_fetch_delegate.cc
index 69ed38f16..1c5ba68 100644
--- a/content/shell/browser/web_test/web_test_background_fetch_delegate.cc
+++ b/content/shell/browser/web_test/web_test_background_fetch_delegate.cc
@@ -241,7 +241,7 @@
 
 void WebTestBackgroundFetchDelegate::GetPermissionForOrigin(
     const url::Origin& origin,
-    const ResourceRequestInfo::WebContentsGetter& wc_getter,
+    const WebContents::Getter& wc_getter,
     GetPermissionForOriginCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   std::move(callback).Run(BackgroundFetchPermission::ALLOWED);
diff --git a/content/shell/browser/web_test/web_test_background_fetch_delegate.h b/content/shell/browser/web_test/web_test_background_fetch_delegate.h
index 41b8562f..33d692a 100644
--- a/content/shell/browser/web_test/web_test_background_fetch_delegate.h
+++ b/content/shell/browser/web_test/web_test_background_fetch_delegate.h
@@ -29,10 +29,9 @@
 
   // BackgroundFetchDelegate implementation:
   void GetIconDisplaySize(GetIconDisplaySizeCallback callback) override;
-  void GetPermissionForOrigin(
-      const url::Origin& origin,
-      const ResourceRequestInfo::WebContentsGetter& wc_getter,
-      GetPermissionForOriginCallback callback) override;
+  void GetPermissionForOrigin(const url::Origin& origin,
+                              const WebContents::Getter& wc_getter,
+                              GetPermissionForOriginCallback callback) override;
   void CreateDownloadJob(
       base::WeakPtr<Client> client,
       std::unique_ptr<BackgroundFetchDescription> fetch_description) override;
diff --git a/content/shell/test_runner/mock_web_theme_engine.cc b/content/shell/test_runner/mock_web_theme_engine.cc
index cdd49cd37..d7392e3 100644
--- a/content/shell/test_runner/mock_web_theme_engine.cc
+++ b/content/shell/test_runner/mock_web_theme_engine.cc
@@ -305,7 +305,8 @@
                                WebThemeEngine::Part part,
                                WebThemeEngine::State state,
                                const blink::WebRect& rect,
-                               const WebThemeEngine::ExtraParams* extraParams) {
+                               const WebThemeEngine::ExtraParams* extraParams,
+                               blink::WebColorScheme color_scheme) {
   SkIRect irect = webRectToSkIRect(rect);
   cc::PaintFlags flags;
 
diff --git a/content/shell/test_runner/mock_web_theme_engine.h b/content/shell/test_runner/mock_web_theme_engine.h
index 1a56a5cf..c954b00 100644
--- a/content/shell/test_runner/mock_web_theme_engine.h
+++ b/content/shell/test_runner/mock_web_theme_engine.h
@@ -21,7 +21,8 @@
              blink::WebThemeEngine::Part,
              blink::WebThemeEngine::State,
              const blink::WebRect&,
-             const blink::WebThemeEngine::ExtraParams*) override;
+             const blink::WebThemeEngine::ExtraParams*,
+             blink::WebColorScheme) override;
 #endif  // !defined(OS_MACOSX)
 };
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index be952ae..8cf567e5 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -942,6 +942,7 @@
     "../browser/message_port_provider_browsertest.cc",
     "../browser/mojo_sandbox_browsertest.cc",
     "../browser/native_file_system/file_system_chooser_browsertest.cc",
+    "../browser/native_file_system/native_file_system_file_writer_impl_browsertest.cc",
     "../browser/navigation_browsertest.cc",
     "../browser/navigation_mhtml_browsertest.cc",
     "../browser/net/accept_header_browsertest.cc",
@@ -1489,7 +1490,6 @@
     "../browser/appcache/appcache_storage_unittest.cc",
     "../browser/appcache/appcache_unittest.cc",
     "../browser/appcache/appcache_update_job_unittest.cc",
-    "../browser/appcache/appcache_url_request_job_unittest.cc",
     "../browser/appcache/chrome_appcache_service_unittest.cc",
     "../browser/appcache/mock_appcache_policy.cc",
     "../browser/appcache/mock_appcache_policy.h",
@@ -1671,6 +1671,7 @@
     "../browser/media/webaudio/audio_context_manager_impl_unittest.cc",
     "../browser/memory/swap_metrics_driver_impl_unittest.cc",
     "../browser/native_file_system/file_system_chooser_unittest.cc",
+    "../browser/native_file_system/native_file_system_file_handle_impl_unittest.cc",
     "../browser/native_file_system/native_file_system_file_writer_impl_unittest.cc",
     "../browser/native_file_system/native_file_system_handle_base_unittest.cc",
     "../browser/native_file_system/native_file_system_manager_impl_unittest.cc",
@@ -1905,8 +1906,6 @@
     "../renderer/media/renderer_webaudiodevice_impl_unittest.cc",
     "../renderer/media/stream/processed_local_audio_source_unittest.cc",
     "../renderer/media/stream/user_media_client_impl_unittest.cc",
-    "../renderer/media/video_capture/video_capture_impl_manager_unittest.cc",
-    "../renderer/media/video_capture/video_capture_impl_unittest.cc",
     "../renderer/media/webrtc/fake_rtc_rtp_transceiver.cc",
     "../renderer/media/webrtc/fake_rtc_rtp_transceiver.h",
     "../renderer/media/webrtc/media_stream_remote_video_source_unittest.cc",
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.cc b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
index 3751736..1f0ebc38 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_manager.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
@@ -14,7 +14,6 @@
 #include "base/optional.h"
 #include "base/stl_util.h"
 #include "components/web_cache/browser/web_cache_manager.h"
-#include "content/public/browser/resource_request_info.h"
 #include "extensions/browser/api/declarative_net_request/composite_matcher.h"
 #include "extensions/browser/api/declarative_net_request/constants.h"
 #include "extensions/browser/api/declarative_net_request/utils.h"
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_action.cc b/extensions/browser/api/declarative_webrequest/webrequest_action.cc
index 8f4bd447..14db9db 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_action.cc
+++ b/extensions/browser/api/declarative_webrequest/webrequest_action.cc
@@ -12,7 +12,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/browser/api/declarative/deduping_factory.h"
 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
@@ -30,7 +29,6 @@
 #include "net/http/http_util.h"
 #include "third_party/re2/src/re2/re2.h"
 
-using content::ResourceRequestInfo;
 using extension_web_request_api_helpers::EventResponseDelta;
 
 namespace extensions {
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc b/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc
index 07d7365..de9c8af1 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc
+++ b/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute.cc
@@ -17,7 +17,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "content/public/browser/resource_request_info.h"
 #include "extensions/browser/api/declarative/deduping_factory.h"
 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
 #include "extensions/browser/api/declarative_webrequest/webrequest_condition.h"
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index da1b3ea..1e0def6 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -30,7 +30,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/child_process_host.h"
@@ -89,7 +88,6 @@
 #endif  // defined(OS_CHROMEOS)
 
 using content::BrowserThread;
-using content::ResourceRequestInfo;
 using extension_web_request_api_helpers::ExtraInfoSpec;
 
 namespace activity_log = activity_log_web_request_constants;
@@ -273,7 +271,6 @@
     return;
 
   std::unique_ptr<base::ListValue> event_args(new base::ListValue);
-  event_details->DetermineFrameDataOnUI();
   event_args->Append(event_details->GetAndClearDict());
 
   EventRouter* event_router = EventRouter::Get(browser_context);
@@ -1460,7 +1457,6 @@
     }
   }
 
-  event_details->SetFrameData(request->frame_data);
   DispatchEventToListeners(browser_context, std::move(listeners_to_dispatch),
                            std::move(event_details));
 
diff --git a/extensions/browser/api/web_request/web_request_event_details.cc b/extensions/browser/api/web_request/web_request_event_details.cc
index 3668333..3518af0e 100644
--- a/extensions/browser/api/web_request/web_request_event_details.cc
+++ b/extensions/browser/api/web_request/web_request_event_details.cc
@@ -12,7 +12,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/child_process_host.h"
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/api/web_request/upload_data_presenter.h"
@@ -58,6 +57,9 @@
   dict_.SetString(keys::kTypeKey,
                   WebRequestResourceTypeToString(request.web_request_type));
   dict_.SetString(keys::kUrlKey, request.url.spec());
+  dict_.SetInteger(keys::kTabIdKey, request.frame_data.tab_id);
+  dict_.SetInteger(keys::kFrameIdKey, request.frame_data.frame_id);
+  dict_.SetInteger(keys::kParentFrameIdKey, request.frame_data.parent_frame_id);
   initiator_ = request.initiator;
   render_process_id_ = request.render_process_id;
   render_frame_id_ = request.frame_id;
@@ -132,21 +134,6 @@
     dict_.SetString(keys::kIpKey, request.response_ip);
 }
 
-void WebRequestEventDetails::SetFrameData(
-    const ExtensionApiFrameIdMap::FrameData& frame_data) {
-  dict_.SetInteger(keys::kTabIdKey, frame_data.tab_id);
-  dict_.SetInteger(keys::kFrameIdKey, frame_data.frame_id);
-  dict_.SetInteger(keys::kParentFrameIdKey, frame_data.parent_frame_id);
-}
-
-void WebRequestEventDetails::DetermineFrameDataOnUI() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  ExtensionApiFrameIdMap::FrameData frame_data =
-      ExtensionApiFrameIdMap::Get()->GetFrameData(render_process_id_,
-                                                  render_frame_id_);
-  SetFrameData(frame_data);
-}
-
 std::unique_ptr<base::DictionaryValue> WebRequestEventDetails::GetFilteredDict(
     int extra_info_spec,
     PermissionHelper* permission_helper,
diff --git a/extensions/browser/api/web_request/web_request_event_details.h b/extensions/browser/api/web_request/web_request_event_details.h
index bac180e..2bbd918 100644
--- a/extensions/browser/api/web_request/web_request_event_details.h
+++ b/extensions/browser/api/web_request/web_request_event_details.h
@@ -95,19 +95,6 @@
     dict_.SetString(key, value);
   }
 
-  // Sets the following keys using the value provided.
-  // - tabId
-  // - frameId
-  // - parentFrameId
-  void SetFrameData(const ExtensionApiFrameIdMap::FrameData& frame_data);
-
-  // Sets the following keys using information from constructor.
-  // - tabId
-  // - frameId
-  // - parentFrameId
-  // This must be called from the UI thread.
-  void DetermineFrameDataOnUI();
-
   // Create an event dictionary that contains all required keys, and also the
   // extra keys as specified by the |extra_info_spec| filter. If the listener
   // this event will be dispatched to doesn't have permission for the initiator
diff --git a/extensions/browser/api/web_request/web_request_info.cc b/extensions/browser/api/web_request/web_request_info.cc
index f2af091..c18a61a 100644
--- a/extensions/browser/api/web_request/web_request_info.cc
+++ b/extensions/browser/api/web_request/web_request_info.cc
@@ -12,7 +12,6 @@
 #include "base/stl_util.h"
 #include "base/values.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/websocket_handshake_request_info.h"
 #include "extensions/browser/api/web_request/upload_data_presenter.h"
 #include "extensions/browser/api/web_request/web_request_api_constants.h"
diff --git a/extensions/browser/api/web_request/web_request_permissions.cc b/extensions/browser/api/web_request/web_request_permissions.cc
index 5611c800..bf4d32f 100644
--- a/extensions/browser/api/web_request/web_request_permissions.cc
+++ b/extensions/browser/api/web_request/web_request_permissions.cc
@@ -10,7 +10,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "content/public/browser/child_process_security_policy.h"
-#include "content/public/browser/resource_request_info.h"
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/api/web_request/permission_helper.h"
 #include "extensions/browser/api/web_request/web_request_api_constants.h"
@@ -30,7 +29,6 @@
 #include "chromeos/login/login_state/login_state.h"
 #endif  // defined(OS_CHROMEOS)
 
-using content::ResourceRequestInfo;
 using extensions::PermissionsData;
 
 namespace {
diff --git a/extensions/browser/api/web_request/web_request_resource_type.cc b/extensions/browser/api/web_request/web_request_resource_type.cc
index d96632f..e26d098 100644
--- a/extensions/browser/api/web_request/web_request_resource_type.cc
+++ b/extensions/browser/api/web_request/web_request_resource_type.cc
@@ -7,7 +7,6 @@
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/stl_util.h"
-#include "content/public/browser/resource_request_info.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
 
 namespace extensions {
diff --git a/extensions/browser/extension_api_frame_id_map.cc b/extensions/browser/extension_api_frame_id_map.cc
index 215ad35..11732db 100644
--- a/extensions/browser/extension_api_frame_id_map.cc
+++ b/extensions/browser/extension_api_frame_id_map.cc
@@ -151,13 +151,13 @@
   return web_contents->UnsafeFindFrameByFrameTreeNodeId(frame_id);
 }
 
-// static
 ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::KeyToValue(
-    const RenderFrameIdKey& key) const {
+    const RenderFrameIdKey& key,
+    bool require_live_frame) const {
   content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
       key.render_process_id, key.frame_routing_id);
 
-  if (!rfh || !rfh->IsRenderFrameLive())
+  if (!rfh || (require_live_frame && !rfh->IsRenderFrameLive()))
     return FrameData();
 
   content::WebContents* web_contents =
@@ -197,7 +197,7 @@
   if (frame_id_iter != deleted_frame_data_map_.end())
     return frame_id_iter->second;
 
-  return KeyToValue(key);
+  return KeyToValue(key, true /* require_live_frame */);
 }
 
 void ExtensionApiFrameIdMap::OnRenderFrameDeleted(
@@ -210,7 +210,8 @@
   // requests made in window.onunload may start after this has been called.
   // Delay the RemoveFrameData() call, so we will still have the frame data
   // cached when the beacon request comes in.
-  deleted_frame_data_map_.insert({key, KeyToValue(key)});
+  deleted_frame_data_map_.insert(
+      {key, KeyToValue(key, false /* require_live_frame */)});
   base::SequencedTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(
diff --git a/extensions/browser/extension_api_frame_id_map.h b/extensions/browser/extension_api_frame_id_map.h
index 58999ea1..8eacf1aa 100644
--- a/extensions/browser/extension_api_frame_id_map.h
+++ b/extensions/browser/extension_api_frame_id_map.h
@@ -141,10 +141,11 @@
   ~ExtensionApiFrameIdMap();
 
   // Determines the value to be stored in |frame_data_map_| for a given key.
+  // If |require_live_frame| is true, FrameData will only
   // Returns empty FrameData when the corresponding RenderFrameHost is not
-  // alive. This method is only called when |key| is not in |frame_data_map_|.
-  // Virtual for testing.
-  FrameData KeyToValue(const RenderFrameIdKey& key) const;
+  // alive and |require_live_frame| is true.
+  FrameData KeyToValue(const RenderFrameIdKey& key,
+                       bool require_live_frame) const;
 
   // Holds mappings of render frame key to FrameData from frames that have been
   // recently deleted. These are kept for a short time so beacon requests that
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc
index 751868e..6000521 100644
--- a/extensions/browser/extension_protocols.cc
+++ b/extensions/browser/extension_protocols.cc
@@ -43,7 +43,6 @@
 #include "content/public/browser/navigation_ui_data.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/resource_type.h"
 #include "crypto/secure_hash.h"
 #include "crypto/sha2.h"
@@ -80,7 +79,6 @@
 #include "url/url_util.h"
 
 using content::BrowserContext;
-using content::ResourceRequestInfo;
 using extensions::Extension;
 using extensions::SharedModuleInfo;
 
diff --git a/extensions/browser/url_request_util.cc b/extensions/browser/url_request_util.cc
index 566e708e..168a2f7 100644
--- a/extensions/browser/url_request_util.cc
+++ b/extensions/browser/url_request_util.cc
@@ -6,7 +6,6 @@
 
 #include <string>
 
-#include "content/public/browser/resource_request_info.h"
 #include "extensions/browser/extension_navigation_ui_data.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
diff --git a/extensions/shell/browser/shell_content_browser_client.cc b/extensions/shell/browser/shell_content_browser_client.cc
index 125d1111..79846b1 100644
--- a/extensions/shell/browser/shell_content_browser_client.cc
+++ b/extensions/shell/browser/shell_content_browser_client.cc
@@ -326,7 +326,7 @@
 
 bool ShellContentBrowserClient::HandleExternalProtocol(
     const GURL& url,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+    content::WebContents::Getter web_contents_getter,
     int child_id,
     content::NavigationUIData* navigation_data,
     bool is_main_frame,
diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h
index c5de66fc..5671c10 100644
--- a/extensions/shell/browser/shell_content_browser_client.h
+++ b/extensions/shell/browser/shell_content_browser_client.h
@@ -90,7 +90,7 @@
       bool* bypass_redirect_checks) override;
   bool HandleExternalProtocol(
       const GURL& url,
-      content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+      content::WebContents::Getter web_contents_getter,
       int child_id,
       content::NavigationUIData* navigation_data,
       bool is_main_frame,
diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc
index a69dc94..0f2a197e 100644
--- a/extensions/shell/browser/shell_extensions_browser_client.cc
+++ b/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -15,7 +15,6 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/resource_request_info.h"
 #include "content/public/common/user_agent.h"
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/core_extensions_browser_api_provider.h"
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index e3d5ebbab..3db98496 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -2292,10 +2292,6 @@
       mixins: "linux-gpu-fyi-ci-tester"
     }
     builders {
-      name: "Win10 FYI Exp Release (NVIDIA)"
-      mixins: "linux-gpu-fyi-ci-tester"
-    }
-    builders {
       name: "Win10 FYI Release (Intel HD 630)"
       mixins: "linux-gpu-fyi-ci-tester"
     }
@@ -2304,27 +2300,31 @@
       mixins: "linux-gpu-fyi-ci-tester"
     }
     builders {
-      name: "Win10 FYI Exp Release (Intel HD 630)"
-      mixins: "linux-gpu-fyi-ci-tester"
-    }
-    builders {
       name: "Win10 FYI Release (NVIDIA)"
       mixins: "linux-gpu-fyi-ci-tester"
     }
     builders {
-      name: "Win10 FYI Release (AMD RX 550)"
-      mixins: "linux-gpu-fyi-ci-tester"
-    }
-    builders {
-      name: "Win10 FYI Release (NVIDIA GeForce GTX 1660)"
-      mixins: "linux-gpu-fyi-ci-tester"
-      execution_timeout_secs: 64800 # 18h.
-    }
-    builders {
       name: "Win10 FYI Release XR Perf (NVIDIA)"
       mixins: "linux-gpu-fyi-ci-tester"
     }
     builders {
+      name: "Win10 FYI x64 Exp Release (Intel HD 630)"
+      mixins: "linux-gpu-fyi-ci-tester"
+    }
+    builders {
+      name: "Win10 FYI x64 Exp Release (NVIDIA)"
+      mixins: "linux-gpu-fyi-ci-tester"
+    }
+    builders {
+      name: "Win10 FYI x64 Release (AMD RX 550)"
+      mixins: "linux-gpu-fyi-ci-tester"
+    }
+    builders {
+      name: "Win10 FYI x64 Release (NVIDIA GeForce GTX 1660)"
+      mixins: "linux-gpu-fyi-ci-tester"
+      execution_timeout_secs: 64800 # 18h.
+    }
+    builders {
       name: "Win7 FYI Debug (AMD)"
       mixins: "linux-gpu-fyi-ci-tester"
     }
@@ -4425,7 +4425,7 @@
     }
     builders {
       mixins: "win-optional-gpu-try"
-      name: "gpu-fyi-try-win10-intel-exp"
+      name: "gpu-fyi-try-win10-intel-exp-64"
     }
     builders {
       mixins: "win-optional-gpu-try"
@@ -4441,7 +4441,7 @@
     }
     builders {
       mixins: "win-optional-gpu-try"
-      name: "gpu-fyi-try-win10-nvidia-exp"
+      name: "gpu-fyi-try-win10-nvidia-exp-64"
     }
     builders {
       mixins: "win-optional-gpu-try"
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index 7cc9a808..6e9eed0 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -3199,45 +3199,55 @@
   }
   builders {
     name: "buildbucket/luci.chromium.ci/Win10 FYI Debug (NVIDIA)"
-    category: "Windows|10|Nvidia"
+    category: "Windows|10-x86|Nvidia"
     short_name: "dbg"
   }
   builders {
     name: "buildbucket/luci.chromium.ci/Win10 FYI Release (Intel HD 630)"
-    category: "Windows|10|Intel"
+    category: "Windows|10-x86|Intel"
     short_name: "rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Win10 FYI dEQP Release (Intel HD 630)"
-    category: "Windows|10|Intel"
-    short_name: "dqp"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/Win10 FYI Exp Release (Intel HD 630)"
-    category: "Windows|10|Intel"
-    short_name: "exp"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Win10 FYI Release (NVIDIA)"
-    category: "Windows|10|Nvidia"
+    category: "Windows|10-x86|Nvidia"
     short_name: "rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Win10 FYI Release (NVIDIA GeForce GTX 1660)"
-    category: "Windows|10|Nvidia"
-    short_name: "gtx"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Win10 FYI Release XR Perf (NVIDIA)"
-    category: "Windows|10|Nvidia"
+    category: "Windows|10-x86|Nvidia"
     short_name: "xr"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Win10 FYI Release (AMD RX 550)"
-    category: "Windows|10|AMD"
+    name: "buildbucket/luci.chromium.ci/Win10 FYI dEQP Release (Intel HD 630)"
+    category: "Windows|10-x86|Intel"
+    short_name: "dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/Win10 FYI dEQP Release (NVIDIA)"
+    category: "Windows|10-x86|Nvidia"
+    short_name: "dqp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/Win10 FYI x64 Exp Release (Intel HD 630)"
+    category: "Windows|10-x64|Intel"
+    short_name: "exp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/Win10 FYI x64 Exp Release (NVIDIA)"
+    category: "Windows|10-x64|Nvidia"
+    short_name: "exp"
+  }
+  builders {
+    name: "buildbucket/luci.chromium.ci/Win10 FYI x64 Release (AMD RX 550)"
+    category: "Windows|10-x64|AMD"
     short_name: "rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/Win10 FYI x64 Release (NVIDIA GeForce GTX 1660)"
+    category: "Windows|10-x64|Nvidia"
+    short_name: "gtx"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/Win7 FYI Debug (AMD)"
     category: "Windows|7|AMD"
     short_name: "dbg"
@@ -3253,21 +3263,11 @@
     short_name: "rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Win10 FYI Exp Release (NVIDIA)"
-    category: "Windows|10|Nvidia"
-    short_name: "exp"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Win7 FYI Release (NVIDIA)"
     category: "Windows|7|Nvidia"
     short_name: "rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Win10 FYI dEQP Release (NVIDIA)"
-    category: "Windows|10|Nvidia"
-    short_name: "dqp"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/Win7 FYI x64 Release (NVIDIA)"
     category: "Windows|7|Nvidia|x64"
     short_name: "rel"
@@ -4530,7 +4530,7 @@
     name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-intel-dqp"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-intel-exp"
+    name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-intel-exp-64"
   }
   builders {
     name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-intel-rel"
@@ -4542,7 +4542,7 @@
     name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-nvidia-dqp"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-nvidia-exp"
+    name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-nvidia-exp-64"
   }
   builders {
     name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-nvidia-rel"
@@ -4877,7 +4877,7 @@
     name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-intel-dqp"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-intel-exp"
+    name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-intel-exp-64"
   }
   builders {
     name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-intel-rel"
@@ -4889,7 +4889,7 @@
     name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-nvidia-dqp"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-nvidia-exp"
+    name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-nvidia-exp-64"
   }
   builders {
     name: "buildbucket/luci.chromium.try/gpu-fyi-try-win10-nvidia-rel"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index d68e6b7..2154753 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -2710,39 +2710,6 @@
 }
 
 job {
-  id: "Win10 FYI Exp Release (Intel HD 630)"
-  # Triggered by "GPU FYI Win Builder"
-  acl_sets: "triggered-by-parent-builders"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "Win10 FYI Exp Release (Intel HD 630)"
-  }
-}
-
-job {
-  id: "Win10 FYI Exp Release (NVIDIA)"
-  # Triggered by "GPU FYI Win Builder"
-  acl_sets: "triggered-by-parent-builders"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "Win10 FYI Exp Release (NVIDIA)"
-  }
-}
-
-job {
-  id: "Win10 FYI Release (AMD RX 550)"
-  # Triggered by "GPU FYI Win Builder"
-  acl_sets: "triggered-by-parent-builders"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "Win10 FYI Release (AMD RX 550)"
-  }
-}
-
-job {
   id: "Win10 FYI Release (Intel HD 630)"
   # Triggered by "GPU FYI Win Builder"
   acl_sets: "triggered-by-parent-builders"
@@ -2776,17 +2743,6 @@
 }
 
 job {
-  id: "Win10 FYI Release (NVIDIA GeForce GTX 1660)"
-  # Triggered by "GPU FYI Win Builder"
-  acl_sets: "triggered-by-parent-builders"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "Win10 FYI Release (NVIDIA GeForce GTX 1660)"
-  }
-}
-
-job {
   id: "Win10 FYI Release XR Perf (NVIDIA)"
   # Triggered by "GPU FYI Win Builder"
   acl_sets: "triggered-by-parent-builders"
@@ -2798,6 +2754,50 @@
 }
 
 job {
+  id: "Win10 FYI x64 Exp Release (Intel HD 630)"
+  # Triggered by "GPU FYI Win x64 Builder"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Win10 FYI x64 Exp Release (Intel HD 630)"
+  }
+}
+
+job {
+  id: "Win10 FYI x64 Exp Release (NVIDIA)"
+  # Triggered by "GPU FYI Win x64 Builder"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Win10 FYI x64 Exp Release (NVIDIA)"
+  }
+}
+
+job {
+  id: "Win10 FYI x64 Release (AMD RX 550)"
+  # Triggered by "GPU FYI Win x64 Builder"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Win10 FYI x64 Release (AMD RX 550)"
+  }
+}
+
+job {
+  id: "Win10 FYI x64 Release (NVIDIA GeForce GTX 1660)"
+  # Triggered by "GPU FYI Win x64 Builder"
+  acl_sets: "triggered-by-parent-builders"
+  buildbucket: {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "Win10 FYI x64 Release (NVIDIA GeForce GTX 1660)"
+  }
+}
+
+job {
   id: "Win7 ANGLE Tryserver (AMD)"
   # Triggered by "GPU FYI Win Builder"
   acl_sets: "triggered-by-parent-builders"
diff --git a/ios/build/bots/scripts/xcode_log_parser.py b/ios/build/bots/scripts/xcode_log_parser.py
index 442281e..43b1245 100644
--- a/ios/build/bots/scripts/xcode_log_parser.py
+++ b/ios/build/bots/scripts/xcode_log_parser.py
@@ -67,12 +67,9 @@
     # "Screenshot At Failure" : <UIImage: 0x6000032ab410>, {768, 1024}
     if 'UIImage:' in screenshots_files:
       return
-    LOGGER.info('Screenshots for failure "%s" in "%s"' % (
-        os.path.basename(test_case_folder), test_case_folder))
     d = json.loads(screenshots_files)
     for f in d.values():
       if not os.path.exists(f):
-        LOGGER.warning('File %s does not exist!' % f)
         continue
       screenshot = os.path.join(test_case_folder, os.path.basename(f))
       shutil.copyfile(f, screenshot)
diff --git a/ios/build/bots/scripts/xcodebuild_runner.py b/ios/build/bots/scripts/xcodebuild_runner.py
index f1f984a..ab31e1a 100644
--- a/ios/build/bots/scripts/xcodebuild_runner.py
+++ b/ios/build/bots/scripts/xcodebuild_runner.py
@@ -20,6 +20,7 @@
 import xcode_log_parser
 
 LOGGER = logging.getLogger(__name__)
+MAXIMUM_TESTS_PER_SHARD_FOR_RERUN = 20
 
 
 class LaunchCommandCreationError(test_runner.TestRunnerError):
@@ -36,6 +37,33 @@
     super(LaunchCommandPoolCreationError, self).__init__(message)
 
 
+def get_all_tests(app_path, test_cases=None):
+  """Gets all tests from test bundle."""
+  test_app_bundle = os.path.join(app_path, os.path.splitext(
+      os.path.basename(app_path))[0])
+  # Method names that starts with test* and also are in *TestCase classes
+  # but they are not test-methods.
+  # TODO(crbug.com/982435): Rename not test methods with test-suffix.
+  not_tests = ['ChromeTestCase/testServer', 'FindInPageTestCase/testURL']
+  all_tests = []
+  for test_class, test_method in test_runner.get_test_names(test_app_bundle):
+    test_name = '%s/%s' % (test_class, test_method)
+    if (test_name not in not_tests and
+        # Filter by self.test_cases if specified
+        (test_class in test_cases if test_cases else True)):
+      all_tests.append(test_name)
+  return all_tests
+
+
+def erase_all_simulators():
+  """Erases all simulator devices.
+
+  Fix for DVTCoreSimulatorAdditionsErrorDomain error.
+  """
+  LOGGER.info('Erasing all simulators.')
+  subprocess.call(['xcrun', 'simctl', 'erase', 'all'])
+
+
 def terminate_process(proc):
   """Terminates the process.
 
@@ -278,9 +306,16 @@
     self.test_results['attempts'] = []
     cancelled_statuses = {'TESTS_DID_NOT_START', 'BUILD_INTERRUPTED'}
     shards = self.shards
+    running_tests = set(get_all_tests(self.egtests_app.egtests_path,
+                                      self.egtests_app.included_tests))
 
     # total number of attempts is self.retries+1
     for attempt in range(self.retries + 1):
+      # Erase all simulators per each attempt
+      if 'iOS Simulator' in self.destination:
+        # kill all running simulators to prevent possible memory leaks
+        test_runner.SimulatorTestRunner.kill_simulators()
+        erase_all_simulators()
       outdir_attempt = os.path.join(self.out_dir, 'attempt_%d' % attempt)
       cmd_list = self.command(self.egtests_app,
                               outdir_attempt,
@@ -295,16 +330,29 @@
       if self.retries == attempt or not self.test_results[
           'attempts'][-1]['failed']:
         break
-      self._log_parser.copy_screenshots(outdir_attempt)
       # Exclude passed tests in next test attempt.
       self.egtests_app.excluded_tests += self.test_results['attempts'][-1][
           'passed']
+      # crbug.com/987664 - for the case when
+      # all tests passed but build was interrupted,
+      # excluded(passed) tests are equal to tests to run.
+      if set(self.egtests_app.excluded_tests) == running_tests:
+        for status in cancelled_statuses:
+          failure = self.test_results['attempts'][-1]['failed'].pop(
+              status, None)
+          if failure:
+            LOGGER.info('Failure for passed tests %s: %s' % (status, failure))
+        break
+      self._log_parser.copy_screenshots(outdir_attempt)
       # If tests are not completed(interrupted or did not start)
       # re-run them with the same number of shards,
       # otherwise re-run with shards=1 and exclude passed tests.
       cancelled_attempt = cancelled_statuses.intersection(
           self.test_results['attempts'][-1]['failed'].keys())
-      if not cancelled_attempt:
+      if (not cancelled_attempt
+          # If need to re-run less than 20 tests, 1 shard should be enough.
+          or (len(running_tests) - len(self.egtests_app.excluded_tests)
+              <= MAXIMUM_TESTS_PER_SHARD_FOR_RERUN)):
         shards = 1
     self.test_results['end_run'] = int(time.time())
     self.summary_log()
@@ -362,7 +410,7 @@
            '-xctestrun', self.fill_xctest_run(egtests_app),
            '-destination', destination,
            '-resultBundlePath', out_dir]
-    if self.shards > 1:
+    if shards > 1:
       cmd += ['-parallel-testing-enabled', 'YES',
               '-parallel-testing-worker-count', str(shards)]
     return cmd
@@ -432,7 +480,6 @@
         xctest=False
     )
     self.set_up()
-    self.erase_all_simulators()
     self.host_app_path = None
     if host_app_path != 'NO_PATH':
       self.host_app_path = os.path.abspath(host_app_path)
@@ -530,35 +577,11 @@
         all_failures - set(self.logs['failed tests']))
 
     # Gets not-started/interrupted tests
-    aborted_tests = list(set(self.get_all_tests()) - set(
-        self.logs['failed tests']) - set(self.logs['passed tests']))
+    all_tests_to_run = set(get_all_tests(self.app_path, self.test_cases))
+    aborted_tests = list(all_tests_to_run - set(self.logs['failed tests']) -
+                         set(self.logs['passed tests']))
     aborted_tests.sort()
     self.logs['aborted tests'] = aborted_tests
 
     # Test is failed if there are failures for the last run.
     return not self.logs['failed tests']
-
-  def erase_all_simulators(self):
-    """Erases all simulator devices.
-
-    Fix for DVTCoreSimulatorAdditionsErrorDomain error.
-    """
-    LOGGER.info('Erasing all simulators.')
-    subprocess.call(['xcrun', 'simctl', 'erase', 'all'])
-
-  def get_all_tests(self):
-    """Gets all tests from test bundle."""
-    test_app_bundle = os.path.join(self.app_path, os.path.splitext(
-        os.path.basename(self.app_path))[0])
-    # Method names that starts with test* and also are in *TestCase classes
-    # but they are not test-methods.
-    # TODO(crbug.com/982435): Rename not test methods with test-suffix.
-    not_tests = ['ChromeTestCase/testServer', 'FindInPageTestCase/testURL']
-    all_tests = []
-    for test_class, test_method in test_runner.get_test_names(test_app_bundle):
-      test_name = '%s/%s' % (test_class, test_method)
-      if (test_name not in not_tests and
-          # Filter by self.test_cases if specified
-          (test_class in self.test_cases if self.test_cases else True)):
-        all_tests.append(test_name)
-    return all_tests
diff --git a/ios/build/bots/scripts/xcodebuild_runner_test.py b/ios/build/bots/scripts/xcodebuild_runner_test.py
index 18dfd6e4..f91c5b6 100644
--- a/ios/build/bots/scripts/xcodebuild_runner_test.py
+++ b/ios/build/bots/scripts/xcodebuild_runner_test.py
@@ -32,6 +32,9 @@
     self.mock(os.path, 'exists', lambda _: True)
     self.mock(xcode_log_parser.XcodeLogParser, 'copy_screenshots',
               lambda _1, _2: None)
+    self.mock(os, 'listdir', lambda _: ['any_egtests.xctest'])
+    self.mock(xcodebuild_runner, 'get_all_tests',
+              lambda _1, _2: ['Class1/passedTest1', 'Class1/passedTest2'])
     self.tmpdir = tempfile.mkdtemp()
 
   def tearDown(self):
@@ -112,9 +115,7 @@
     with self.assertRaises(test_runner.PlugInsNotFoundError):
       egtests._xctest_path()
 
-  @mock.patch('os.listdir', autospec=True)
-  def testEgtests_found_xctest(self, mock_listdir):
-    mock_listdir.return_value = ['any_egtests.xctest']
+  def testEgtests_found_xctest(self):
     self.assertEqual('/PlugIns/any_egtests.xctest',
                      xcodebuild_runner.EgtestsApp(
                          _EGTESTS_APP_PATH)._xctest_path())
@@ -126,18 +127,13 @@
     with self.assertRaises(test_runner.XCTestPlugInNotFoundError):
       egtest._xctest_path()
 
-  @mock.patch('os.listdir', autospec=True)
-  def testEgtests_xctestRunNode_without_filter(self, mock_listdir):
-    mock_listdir.return_value = ['any_egtests.xctest']
+  def testEgtests_xctestRunNode_without_filter(self):
     egtest_node = xcodebuild_runner.EgtestsApp(
         _EGTESTS_APP_PATH).xctestrun_node()['any_egtests_module']
     self.assertNotIn('OnlyTestIdentifiers', egtest_node)
     self.assertNotIn('SkipTestIdentifiers', egtest_node)
 
-  @mock.patch('os.listdir', autospec=True)
-  def testEgtests_xctestRunNode_with_filter_only_identifiers(self,
-                                                             mock_listdir):
-    mock_listdir.return_value = ['any_egtests.xctest']
+  def testEgtests_xctestRunNode_with_filter_only_identifiers(self):
     filtered_tests = ['TestCase1/testMethod1', 'TestCase1/testMethod2',
                       'TestCase2/testMethod1', 'TestCase1/testMethod2']
     egtest_node = xcodebuild_runner.EgtestsApp(
@@ -146,10 +142,7 @@
     self.assertEqual(filtered_tests, egtest_node['OnlyTestIdentifiers'])
     self.assertNotIn('SkipTestIdentifiers', egtest_node)
 
-  @mock.patch('os.listdir', autospec=True)
-  def testEgtests_xctestRunNode_with_filter_skip_identifiers(self,
-                                                             mock_listdir):
-    mock_listdir.return_value = ['any_egtests.xctest']
+  def testEgtests_xctestRunNode_with_filter_skip_identifiers(self):
     skipped_tests = ['TestCase1/testMethod1', 'TestCase1/testMethod2',
                      'TestCase2/testMethod1', 'TestCase1/testMethod2']
     egtest_node = xcodebuild_runner.EgtestsApp(
@@ -195,17 +188,15 @@
       xcodebuild_runner.LaunchCommand([], 'destination', shards=1, retries=1,
                                       out_dir=_OUT_DIR).fill_xctest_run([])
 
-  @mock.patch('os.listdir', autospec=True)
   @mock.patch('test_runner.get_current_xcode_info', autospec=True)
   @mock.patch('xcode_log_parser.XcodeLogParser.collect_test_results')
   def testLaunchCommand_restartFailed1stAttempt(self, mock_collect_results,
-                                                xcode_version, mock_listdir):
-    mock_listdir.return_value = ['any_egtests.xctest']
+                                                xcode_version):
     egtests = xcodebuild_runner.EgtestsApp(_EGTESTS_APP_PATH)
     xcode_version.return_value = {'version': '10.2.1'}
     mock_collect_results.side_effect = [
         {'failed': {'TESTS_DID_NOT_START': ['not started']}, 'passed': []},
-        {'failed': {}, 'passed': ['passedTest1']}
+        {'failed': {}, 'passed': ['Class1/passedTest1', 'Class1/passedTest2']}
     ]
     launch_command = xcodebuild_runner.LaunchCommand(egtests,
                                                      _DESTINATION,
@@ -215,3 +206,22 @@
     self.fake_launch_attempt(launch_command, ['not_started', 'pass'])
     launch_command.launch()
     self.assertEqual(2, len(launch_command.test_results))
+
+  @mock.patch('test_runner.get_current_xcode_info', autospec=True)
+  @mock.patch('xcode_log_parser.XcodeLogParser.collect_test_results')
+  def testLaunchCommand_notRestartPassedTest(self, mock_collect_results,
+                                             xcode_version):
+    egtests = xcodebuild_runner.EgtestsApp(_EGTESTS_APP_PATH)
+    xcode_version.return_value = {'version': '10.2.1'}
+    mock_collect_results.side_effect = [
+        {'failed': {'BUILD_INTERRUPTED': 'BUILD_INTERRUPTED: attempt # 0'},
+         'passed': ['Class1/passedTest1', 'Class1/passedTest2']}
+    ]
+    launch_command = xcodebuild_runner.LaunchCommand(egtests,
+                                                     _DESTINATION,
+                                                     shards=1,
+                                                     retries=3,
+                                                     out_dir=self.tmpdir)
+    self.fake_launch_attempt(launch_command, ['pass'])
+    launch_command.launch()
+    self.assertEqual(2, len(launch_command.test_results))
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 408716d..373fd94b 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -109,13 +109,11 @@
   "+libxml/xmlwriter.h",
   "+net",
   "+rlz/buildflags",
-  "+services/identity/public",
   "+services/metrics/public",
   "+services/metrics/public/cpp",
   "+services/network/network_change_manager.h",
   "+services/network/public/mojom",
   "+services/network/public/cpp",
-  "+services/service_manager/public",
   "+third_party/breakpad/breakpad/src/client/ios",
   "+third_party/breakpad/breakpad/src/common",
   "+third_party/google_toolbox_for_mac",
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn
index 9836169e..c14f8d30 100644
--- a/ios/chrome/browser/browser_state/BUILD.gn
+++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -128,7 +128,6 @@
     "//ios/web/net/cookies",
     "//net",
     "//net:extras",
-    "//services/identity/public/mojom",
   ]
   allow_circular_includes_from = [
     "//ios/chrome/browser",
@@ -205,24 +204,3 @@
 
   configs += [ "//build/config/compiler:enable_arc" ]
 }
-
-source_set("eg_tests") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  testonly = true
-  sources = [
-    "browser_state_services_egtest.mm",
-  ]
-  deps = [
-    ":browser_state",
-    "//base",
-    "//base/test:test_support",
-    "//ios/chrome/test/app:test_support",
-    "//ios/chrome/test/earl_grey:test_support",
-    "//ios/testing/earl_grey:earl_grey_support",
-    "//ios/third_party/earl_grey:earl_grey+link",
-    "//ios/web:earl_grey_test_support",
-    "//ios/web/public",
-    "//services/identity/public/mojom",
-    "//services/service_manager/public/cpp",
-  ]
-}
diff --git a/ios/chrome/browser/browser_state/browser_state_services_egtest.mm b/ios/chrome/browser/browser_state/browser_state_services_egtest.mm
deleted file mode 100644
index 62f3c206..0000000
--- a/ios/chrome/browser/browser_state/browser_state_services_egtest.mm
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <EarlGrey/EarlGrey.h>
-
-#include "base/bind.h"
-#include "base/run_loop.h"
-#import "base/test/ios/wait_util.h"
-#import "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/test/app/chrome_test_util.h"
-#import "ios/chrome/test/earl_grey/chrome_test_case.h"
-#include "ios/web/public/browser_state.h"
-#include "ios/web/public/service/service_manager_connection.h"
-#include "services/identity/public/mojom/constants.mojom.h"
-#include "services/identity/public/mojom/identity_accessor.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-// Callback passed to
-// identity::mojom::IdentityAccessor::GetPrimaryAccountInfo(). Sets
-// |echo_callback_called_flag| to true to indicate that the callback was
-// invoked.
-void OnGotPrimaryAccountInfo(
-    bool* get_primary_account_info_callback_called_flag,
-    const base::Optional<CoreAccountId>& account_id,
-    const base::Optional<std::string>& gaia,
-    const base::Optional<std::string>& email,
-    const identity::AccountState& account_state) {
-  GREYAssert(!account_id, @"AccountId has unexpected value");
-  *get_primary_account_info_callback_called_flag = true;
-}
-
-// Waits until a given callback is invoked (as signalled by that callback
-// setting |callback_called_flag| to true).
-void WaitForCallback(const std::string& callback_name,
-                     bool* callback_called_flag) {
-  GREYCondition* condition =
-      [GREYCondition conditionWithName:@"Wait for callback"
-                                 block:^BOOL {
-                                   return *callback_called_flag;
-                                 }];
-  GREYAssert(
-      [condition waitWithTimeout:base::test::ios::kWaitForUIElementTimeout],
-      @"Failed waiting for %s callback", callback_name.c_str());
-}
-}
-
-// Tests embedding of various services in ChromeBrowserState.
-@interface BrowserStateServicesTestCase : ChromeTestCase
-@end
-
-@implementation BrowserStateServicesTestCase
-
-// Tests that it is possible to connect to the Identity Service.
-- (void)testConnectionToIdentityService {
-  ios::ChromeBrowserState* browserState =
-      chrome_test_util::GetOriginalBrowserState();
-
-  // Connect to the Identity Service and bind an IdentityManager instance.
-  identity::mojom::IdentityAccessorPtr identityAccessor;
-  web::BrowserState::GetConnectorFor(browserState)
-      ->BindInterface(identity::mojom::kServiceName,
-                      mojo::MakeRequest(&identityAccessor));
-
-  bool getPrimaryAccountInfoCallbackCalled = false;
-  identityAccessor->GetPrimaryAccountInfo(base::BindOnce(
-      &OnGotPrimaryAccountInfo, &getPrimaryAccountInfoCallbackCalled));
-
-  WaitForCallback("GetPrimaryAccountInfo",
-                  &getPrimaryAccountInfoCallbackCalled);
-}
-
-@end
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
index 79f25d2..6885ea4b 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
@@ -32,9 +32,7 @@
 #include "ios/chrome/browser/prefs/browser_prefs.h"
 #include "ios/chrome/browser/prefs/ios_chrome_pref_service_factory.h"
 #include "ios/chrome/browser/send_tab_to_self/send_tab_to_self_client_service_factory.h"
-#include "ios/chrome/browser/signin/identity_service_creator.h"
 #include "ios/web/public/thread/web_thread.h"
-#include "services/identity/public/mojom/constants.mojom.h"
 
 namespace {
 
@@ -78,8 +76,6 @@
       state_path_(path),
       pref_registry_(new user_prefs::PrefRegistrySyncable),
       io_data_(new ChromeBrowserStateImplIOData::Handle(this)) {
-  BrowserState::Initialize(this, state_path_);
-
   otr_state_path_ = state_path_.Append(FILE_PATH_LITERAL("OTR"));
 
   // It would be nice to use PathService for fetching this directory, but
@@ -171,19 +167,6 @@
   return state_path_;
 }
 
-std::unique_ptr<service_manager::Service>
-ChromeBrowserStateImpl::HandleServiceRequest(
-    const std::string& service_name,
-    service_manager::mojom::ServiceRequest request) {
-  // TODO(crbug.com/787794): It would be nice to avoid ChromeBrowserState/
-  // Profile needing to know explicitly about every service that it is
-  // embedding.
-  if (service_name == identity::mojom::kServiceName)
-    return CreateIdentityService(this, std::move(request));
-
-  return nullptr;
-}
-
 void ChromeBrowserStateImpl::SetOffTheRecordChromeBrowserState(
     std::unique_ptr<ios::ChromeBrowserState> otr_state) {
   DCHECK(!otr_state_);
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl.h b/ios/chrome/browser/browser_state/chrome_browser_state_impl.h
index 303ae8b0..9e4dc8b 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.h
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.h
@@ -46,9 +46,6 @@
   // BrowserState:
   bool IsOffTheRecord() const override;
   base::FilePath GetStatePath() const override;
-  std::unique_ptr<service_manager::Service> HandleServiceRequest(
-      const std::string& service_name,
-      service_manager::mojom::ServiceRequest request) override;
 
  private:
   friend class ChromeBrowserStateManagerImpl;
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
index 123babf1..e7564e5 100644
--- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
+++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.cc
@@ -26,7 +26,6 @@
       original_chrome_browser_state_(original_chrome_browser_state),
       prefs_(static_cast<sync_preferences::PrefServiceSyncable*>(
           original_chrome_browser_state->GetOffTheRecordPrefs())) {
-  BrowserState::Initialize(this, otr_state_path_);
   user_prefs::UserPrefs::Set(this, GetPrefs());
   io_data_.reset(new OffTheRecordChromeBrowserStateIOData::Handle(this));
   BrowserStateDependencyManager::GetInstance()->CreateBrowserStateServices(
diff --git a/ios/chrome/browser/browser_state/test_chrome_browser_state.mm b/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
index 1fc59ec2..784ade44 100644
--- a/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
+++ b/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
@@ -176,8 +176,6 @@
   if (!base::PathExists(state_path_))
     base::CreateDirectory(state_path_);
 
-  BrowserState::Initialize(this, GetStatePath());
-
   // Normally this would happen during browser startup, but for tests we need to
   // trigger creation of BrowserState-related services.
   EnsureBrowserStateKeyedServiceFactoriesBuilt();
diff --git a/ios/chrome/browser/signin/BUILD.gn b/ios/chrome/browser/signin/BUILD.gn
index 61bff4e..3029291 100644
--- a/ios/chrome/browser/signin/BUILD.gn
+++ b/ios/chrome/browser/signin/BUILD.gn
@@ -33,8 +33,6 @@
     "identity_manager_factory.cc",
     "identity_manager_factory.h",
     "identity_manager_factory_observer.h",
-    "identity_service_creator.cc",
-    "identity_service_creator.h",
     "ios_chrome_signin_client.h",
     "ios_chrome_signin_client.mm",
     "ios_chrome_signin_status_metrics_provider_delegate.cc",
@@ -85,8 +83,6 @@
     "//ios/web/common",
     "//ios/web/common:web_view_creation_util",
     "//net",
-    "//services/identity:lib",
-    "//services/service_manager/public/mojom",
     "//url",
   ]
 }
diff --git a/ios/chrome/browser/signin/DEPS b/ios/chrome/browser/signin/DEPS
deleted file mode 100644
index a5ba9e61..0000000
--- a/ios/chrome/browser/signin/DEPS
+++ /dev/null
@@ -1,7 +0,0 @@
-specific_include_rules = {
-  # The dependence on the Identity Service implementation should be used *only*
-  # for Identity Service creation.
-  "identity_service_creator.cc": [
-    "+services/identity/identity_service.h",
-  ],
-}
diff --git a/ios/chrome/browser/signin/identity_service_creator.cc b/ios/chrome/browser/signin/identity_service_creator.cc
deleted file mode 100644
index f75ce470..0000000
--- a/ios/chrome/browser/signin/identity_service_creator.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/chrome/browser/signin/identity_service_creator.h"
-
-#include <memory>
-
-#include "ios/chrome/browser/signin/identity_manager_factory.h"
-#include "services/identity/identity_service.h"
-
-std::unique_ptr<service_manager::Service> CreateIdentityService(
-    ios::ChromeBrowserState* browser_state,
-    service_manager::mojom::ServiceRequest request) {
-  signin::IdentityManager* identity_manager =
-      IdentityManagerFactory::GetForBrowserState(browser_state);
-  return std::make_unique<identity::IdentityService>(identity_manager,
-                                                     std::move(request));
-}
diff --git a/ios/chrome/browser/signin/identity_service_creator.h b/ios/chrome/browser/signin/identity_service_creator.h
deleted file mode 100644
index 460aeb8e..0000000
--- a/ios/chrome/browser/signin/identity_service_creator.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_SIGNIN_IDENTITY_SERVICE_CREATOR_H_
-#define IOS_CHROME_BROWSER_SIGNIN_IDENTITY_SERVICE_CREATOR_H_
-
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
-
-// Creates an instance of the Identity Service for |browser_state| and
-// |request|.
-std::unique_ptr<service_manager::Service> CreateIdentityService(
-    ios::ChromeBrowserState* browser_state,
-    service_manager::mojom::ServiceRequest request);
-
-#endif  // IOS_CHROME_BROWSER_SIGNIN_IDENTITY_SERVICE_CREATOR_H_
diff --git a/ios/chrome/browser/ui/webui/BUILD.gn b/ios/chrome/browser/ui/webui/BUILD.gn
index 6a0cae91..25db1d54 100644
--- a/ios/chrome/browser/ui/webui/BUILD.gn
+++ b/ios/chrome/browser/ui/webui/BUILD.gn
@@ -74,7 +74,6 @@
     "//ios/web/public/js_messaging",
     "//ios/web/public/webui",
     "//net",
-    "//services/service_manager/public/cpp",
     "//ui/base",
     "//url",
   ]
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index bcc0491..fb9e377 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -208,8 +208,6 @@
   sources = [
     "blocked_popup_tab_helper.h",
     "blocked_popup_tab_helper.mm",
-    "chrome_overlay_manifests.cc",
-    "chrome_overlay_manifests.h",
     "chrome_web_client.h",
     "chrome_web_client.mm",
     "print_tab_helper.h",
@@ -248,9 +246,6 @@
     "//ios/web/public",
     "//ios/web/public/js_messaging",
     "//net",
-    "//services/identity/public/cpp:manifest",
-    "//services/identity/public/mojom",
-    "//services/service_manager/public/cpp",
     "//ui/base",
     "//ui/gfx",
     "//url",
diff --git a/ios/chrome/browser/web/DEPS b/ios/chrome/browser/web/DEPS
index 0451482..46d60a2 100644
--- a/ios/chrome/browser/web/DEPS
+++ b/ios/chrome/browser/web/DEPS
@@ -1,7 +1,3 @@
-include_rules = [
-  "+services/identity/public/cpp/manifest.h",
-]
-
 specific_include_rules = {
   # web::HttpServer is deprecated in favor of net::EmbeddedTestServer.
   # TODO:(crbug.com/891834) Remove this exception.
diff --git a/ios/chrome/browser/web/OWNERS b/ios/chrome/browser/web/OWNERS
index 31a22b3e..1a6c73c5 100644
--- a/ios/chrome/browser/web/OWNERS
+++ b/ios/chrome/browser/web/OWNERS
@@ -3,8 +3,3 @@
 
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
-
-per-file chrome_overlay_manifests.cc=set noparent
-per-file chrome_overlay_manifests.cc=file://ipc/SECURITY_OWNERS
-per-file chrome_overlay_manifests.h=set noparent
-per-file chrome_overlay_manifests.h=file://ipc/SECURITY_OWNERS
diff --git a/ios/chrome/browser/web/chrome_overlay_manifests.cc b/ios/chrome/browser/web/chrome_overlay_manifests.cc
deleted file mode 100644
index 3d3a9f7..0000000
--- a/ios/chrome/browser/web/chrome_overlay_manifests.cc
+++ /dev/null
@@ -1,20 +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 "ios/chrome/browser/web/chrome_overlay_manifests.h"
-
-#include "base/no_destructor.h"
-#include "services/identity/public/cpp/manifest.h"
-#include "services/identity/public/mojom/constants.mojom.h"
-#include "services/service_manager/public/cpp/manifest_builder.h"
-
-const service_manager::Manifest& GetChromeWebBrowserOverlayManifest() {
-  static base::NoDestructor<service_manager::Manifest> manifest{
-      service_manager::ManifestBuilder()
-          .RequireCapability(identity::mojom::kServiceName, "identity_accessor")
-          .PackageService(identity::GetManifest())
-          .Build()};
-
-  return *manifest;
-}
diff --git a/ios/chrome/browser/web/chrome_overlay_manifests.h b/ios/chrome/browser/web/chrome_overlay_manifests.h
deleted file mode 100644
index 06bc713..0000000
--- a/ios/chrome/browser/web/chrome_overlay_manifests.h
+++ /dev/null
@@ -1,15 +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 IOS_CHROME_BROWSER_WEB_CHROME_OVERLAY_MANIFESTS_H_
-#define IOS_CHROME_BROWSER_WEB_CHROME_OVERLAY_MANIFESTS_H_
-
-#include "services/service_manager/public/cpp/manifest.h"
-
-// Returns the manifest Chrome amends to the web_browser service manifest. This
-// allows Chrome to extend the capabilities exposed and/or required by
-// web_browser service instances.
-const service_manager::Manifest& GetChromeWebBrowserOverlayManifest();
-
-#endif  // IOS_CHROME_BROWSER_WEB_CHROME_OVERLAY_MANIFESTS_H_
diff --git a/ios/chrome/browser/web/chrome_web_client.h b/ios/chrome/browser/web/chrome_web_client.h
index 9194f10..259af279 100644
--- a/ios/chrome/browser/web/chrome_web_client.h
+++ b/ios/chrome/browser/web/chrome_web_client.h
@@ -35,8 +35,6 @@
       ui::ScaleFactor scale_factor) const override;
   base::RefCountedMemory* GetDataResourceBytes(int resource_id) const override;
   bool IsDataResourceGzipped(int resource_id) const override;
-  base::Optional<service_manager::Manifest> GetServiceManifestOverlay(
-      base::StringPiece name) override;
   void GetAdditionalWebUISchemes(
       std::vector<std::string>* additional_schemes) override;
   void PostBrowserURLRewriterCreation(
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm
index 3c40171..aeb0edcc 100644
--- a/ios/chrome/browser/web/chrome_web_client.mm
+++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -23,7 +23,6 @@
 #import "ios/chrome/browser/reading_list/offline_page_tab_helper.h"
 #include "ios/chrome/browser/ssl/ios_ssl_error_handler.h"
 #import "ios/chrome/browser/ui/elements/windowed_container_view.h"
-#include "ios/chrome/browser/web/chrome_overlay_manifests.h"
 #import "ios/chrome/browser/web/error_page_util.h"
 #include "ios/public/provider/chrome/browser/browser_url_rewriter_provider.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
@@ -31,7 +30,6 @@
 #include "ios/public/provider/chrome/browser/voice/voice_search_provider.h"
 #include "ios/web/common/user_agent.h"
 #include "ios/web/public/navigation/browser_url_rewriter.h"
-#include "ios/web/public/service/service_names.mojom.h"
 #include "net/http/http_util.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -151,13 +149,6 @@
   return ui::ResourceBundle::GetSharedInstance().IsGzipped(resource_id);
 }
 
-base::Optional<service_manager::Manifest>
-ChromeWebClient::GetServiceManifestOverlay(base::StringPiece name) {
-  if (name == web::mojom::kBrowserServiceName)
-    return GetChromeWebBrowserOverlayManifest();
-  return base::nullopt;
-}
-
 void ChromeWebClient::GetAdditionalWebUISchemes(
     std::vector<std::string>* additional_schemes) {
   additional_schemes->push_back(dom_distiller::kDomDistillerScheme);
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index 79ec786..71ba73a 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -26,7 +26,6 @@
 chrome_ios_eg_test("ios_chrome_integration_egtests") {
   deps = [
     "//ios/chrome/browser/autofill:eg_tests",
-    "//ios/chrome/browser/browser_state:eg_tests",
     "//ios/chrome/browser/context_menu:eg_tests",
     "//ios/chrome/browser/device_sharing:eg_tests",
     "//ios/chrome/browser/feature_engagement:eg_tests",
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 1080e55..10b38071 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -17,8 +17,6 @@
 
 source_set("web") {
   public_deps = [
-    "//ios/web/public/service:service_names",
-
     # TODO(crbug.com/616244): Remove private files from public dependencies.
     ":threads",
     "//ios/web/navigation:core",
@@ -26,7 +24,6 @@
     "//ios/web/public",
     "//ios/web/public/download",
     "//ios/web/public/init",
-    "//ios/web/service",
     "//ios/web/web_state:web_state_impl_header",
     "//ios/web/web_state/ui",
     "//ios/web/web_state/ui:wk_web_view_configuration_provider",
@@ -51,14 +48,12 @@
     "//ios/web/public/security",
     "//ios/web/public/session",
     "//ios/web/security",
-    "//ios/web/service",
     "//ios/web/session",
     "//ios/web/thread",
     "//ios/web/ui",
     "//ios/web/web_state",
     "//ios/web/web_state:web_view_internal_creation_util",
     "//services/network:network_service",
-    "//services/service_manager/public/cpp",
   ]
 
   sources = [
@@ -333,7 +328,6 @@
     "//ios/web/test:test_support",
     "//ios/web/test/fakes",
     "//net:test_support",
-    "//services/service_manager/public/cpp",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/ocmock",
@@ -398,7 +392,6 @@
     "//ios/web/web_state:page_viewport_state",
     "//ios/web/web_state:web_view_internal_creation_util",
     "//net:test_support",
-    "//services/service_manager/public/cpp",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/ocmock",
@@ -444,7 +437,6 @@
     "//ios/web/web_state:context_menu",
     "//ios/web/web_state/js",
     "//net:test_support",
-    "//services/service_manager/public/cpp",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/ocmock",
@@ -490,7 +482,6 @@
     "//ios/web/web_state/js",
     "//ios/web/web_state/ui:crw_context_menu_controller",
     "//net:test_support",
-    "//services/service_manager/public/cpp",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/ocmock",
@@ -527,7 +518,6 @@
     "//ios/web/test:test_support",
     "//net:test_support",
     "//services/network:test_support",
-    "//services/service_manager/public/cpp",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/ocmock",
@@ -576,7 +566,6 @@
     "//mojo/core/embedder",
     "//net:test_support",
     "//services/network/public/cpp",
-    "//services/service_manager/public/cpp",
     "//testing/gtest",
     "//ui/base:test_support",
     "//ui/resources",
diff --git a/ios/web/DEPS b/ios/web/DEPS
index da771b4ce..3c0964d 100644
--- a/ios/web/DEPS
+++ b/ios/web/DEPS
@@ -11,9 +11,6 @@
   "+services/network/public/mojom",
   "+ui",
 
-  # Needed to embed the ServiceManager in //ios/web.
-  "+services/service_manager",
-
   # For tests.
   "+ios/testing",
   "+ios/third_party/earl_grey/src",
diff --git a/ios/web/browser_state.mm b/ios/web/browser_state.mm
index 44ed2fd..dc48f79 100644
--- a/ios/web/browser_state.mm
+++ b/ios/web/browser_state.mm
@@ -17,8 +17,6 @@
 #include "base/token.h"
 #include "ios/web/public/init/network_context_owner.h"
 #include "ios/web/public/security/certificate_policy_cache.h"
-#include "ios/web/public/service/service_manager_connection.h"
-#include "ios/web/public/service/service_names.mojom.h"
 #include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/web_client.h"
@@ -29,8 +27,6 @@
 #include "net/url_request/url_request_context_getter_observer.h"
 #include "services/network/network_context.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -39,21 +35,12 @@
 namespace web {
 namespace {
 
-// Maps service instance group IDs to associated BrowserState instances.
-std::map<base::Token, BrowserState*>& GetInstanceGroupToBrowserState() {
-  static base::NoDestructor<std::map<base::Token, BrowserState*>>
-      instance_group_to_browser_state;
-  return *instance_group_to_browser_state;
-}
-
 // Private key used for safe conversion of base::SupportsUserData to
 // web::BrowserState in web::BrowserState::FromSupportsUserData.
 const char kBrowserStateIdentifierKey[] = "BrowserStateIdentifierKey";
 
 // Data key names.
 const char kCertificatePolicyCacheKeyName[] = "cert_policy_cache";
-const char kServiceManagerConnection[] = "service-manager-connection";
-const char kServiceInstanceGroup[] = "service-instance-group";
 
 // Wraps a CertificatePolicyCache as a SupportsUserData::Data; this is necessary
 // since reference counted objects can't be user data.
@@ -64,89 +51,6 @@
   scoped_refptr<CertificatePolicyCache> policy_cache;
 };
 
-// Container for a service instance group ID to support association between
-// BrowserStates and service instance groups.
-class ServiceInstanceGroupHolder : public base::SupportsUserData::Data {
- public:
-  explicit ServiceInstanceGroupHolder(const base::Token& instance_group)
-      : instance_group_(instance_group) {}
-  ~ServiceInstanceGroupHolder() override = default;
-
-  const base::Token& instance_group() const { return instance_group_; }
-
- private:
-  base::Token instance_group_;
-
-  DISALLOW_COPY_AND_ASSIGN(ServiceInstanceGroupHolder);
-};
-
-// Eliminates the mapping from |browser_state|'s associated instance group ID
-// (if any) to |browser_state|.
-void RemoveBrowserStateFromInstanceGroupMap(BrowserState* browser_state) {
-  ServiceInstanceGroupHolder* holder = static_cast<ServiceInstanceGroupHolder*>(
-      browser_state->GetUserData(kServiceInstanceGroup));
-  if (holder) {
-    GetInstanceGroupToBrowserState().erase(holder->instance_group());
-  }
-}
-
-// Container for a ServiceManagerConnection to support association between
-// a BrowserState and the ServiceManagerConnection initiated on behalf of that
-// BrowserState.
-class BrowserStateServiceManagerConnectionHolder
-    : public base::SupportsUserData::Data {
- public:
-  BrowserStateServiceManagerConnectionHolder(
-      BrowserState* browser_state,
-      service_manager::mojom::ServiceRequest request)
-      : browser_state_(browser_state),
-        service_manager_connection_(ServiceManagerConnection::Create(
-            std::move(request),
-            base::CreateSingleThreadTaskRunnerWithTraits({WebThread::IO}))) {
-    service_manager_connection_->SetDefaultServiceRequestHandler(
-        base::BindRepeating(
-            &BrowserStateServiceManagerConnectionHolder::OnServiceRequest,
-            weak_ptr_factory_.GetWeakPtr()));
-  }
-  ~BrowserStateServiceManagerConnectionHolder() override {}
-
-  ServiceManagerConnection* service_manager_connection() {
-    return service_manager_connection_.get();
-  }
-
- private:
-  void OnServiceRequest(const std::string& service_name,
-                        service_manager::mojom::ServiceRequest request) {
-    std::unique_ptr<service_manager::Service> service =
-        browser_state_->HandleServiceRequest(service_name, std::move(request));
-    if (!service) {
-      LOG(ERROR) << "Ignoring request for unknown per-browser-state service:"
-                 << service_name;
-      return;
-    }
-
-    auto* raw_service = service.get();
-    service->set_termination_closure(base::BindOnce(
-        &BrowserStateServiceManagerConnectionHolder::OnServiceQuit,
-        base::Unretained(this), raw_service));
-    running_services_.emplace(raw_service, std::move(service));
-  }
-
-  void OnServiceQuit(service_manager::Service* service) {
-    running_services_.erase(service);
-  }
-
-  BrowserState* const browser_state_;
-  std::unique_ptr<ServiceManagerConnection> service_manager_connection_;
-  std::map<service_manager::Service*, std::unique_ptr<service_manager::Service>>
-      running_services_;
-
-  base::WeakPtrFactory<BrowserStateServiceManagerConnectionHolder>
-      weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserStateServiceManagerConnectionHolder);
-};
-
 }  // namespace
 
 // static
@@ -181,9 +85,6 @@
 }
 
 BrowserState::~BrowserState() {
-  CHECK(GetUserData(kServiceInstanceGroup))
-      << "Attempting to destroy a BrowserState that never called "
-      << "Initialize()";
   shared_url_loader_factory_->Detach();
 
   if (network_context_) {
@@ -191,8 +92,6 @@
                                network_context_owner_.release());
   }
 
-  RemoveBrowserStateFromInstanceGroupMap(this);
-
   // Delete the URLDataManagerIOSBackend instance on the IO thread if it has
   // been created. Note that while this check can theoretically race with a
   // call to |GetURLDataManagerIOSBackendOnIOThread()|, if any clients of this
@@ -275,89 +174,4 @@
   return static_cast<BrowserState*>(supports_user_data);
 }
 
-// static
-void BrowserState::Initialize(BrowserState* browser_state,
-                              const base::FilePath& path) {
-  base::Token new_group = base::Token::CreateRandom();
-
-  // Note: If the file service is ever used on iOS, code needs to be added here
-  // to have the file service associate |path| as the user dir of the instance
-  // group of |browser_state| (see corresponding code in
-  // content::BrowserContext::Initialize). crbug.com/739450
-
-  RemoveBrowserStateFromInstanceGroupMap(browser_state);
-  GetInstanceGroupToBrowserState()[new_group] = browser_state;
-  browser_state->SetUserData(
-      kServiceInstanceGroup,
-      std::make_unique<ServiceInstanceGroupHolder>(new_group));
-
-  ServiceManagerConnection* service_manager_connection =
-      ServiceManagerConnection::Get();
-  if (service_manager_connection && base::ThreadTaskRunnerHandle::IsSet()) {
-    // NOTE: Many unit tests create a TestBrowserState without initializing
-    // Mojo or the global service manager connection.
-
-    // Have the global service manager connection start an instance of the
-    // web_browser service that is associated with this BrowserState (via
-    // |new_group|).
-    mojo::PendingRemote<service_manager::mojom::Service> service;
-    auto service_receiver = service.InitWithNewPipeAndPassReceiver();
-
-    mojo::Remote<service_manager::mojom::ProcessMetadata> metadata;
-    service_manager::Identity identity(mojom::kBrowserServiceName, new_group,
-                                       base::Token{},
-                                       base::Token::CreateRandom());
-    service_manager_connection->GetConnector()->RegisterServiceInstance(
-        identity, std::move(service), metadata.BindNewPipeAndPassReceiver());
-    metadata->SetPID(base::GetCurrentProcId());
-
-    auto connection_holder =
-        std::make_unique<BrowserStateServiceManagerConnectionHolder>(
-            browser_state, std::move(service_receiver));
-
-    ServiceManagerConnection* connection =
-        connection_holder->service_manager_connection();
-
-    browser_state->SetUserData(kServiceManagerConnection,
-                               std::move(connection_holder));
-
-    connection->Start();
-  }
-}
-
-// static
-const base::Token& BrowserState::GetServiceInstanceGroupFor(
-    BrowserState* browser_state) {
-  ServiceInstanceGroupHolder* holder = static_cast<ServiceInstanceGroupHolder*>(
-      browser_state->GetUserData(kServiceInstanceGroup));
-  CHECK(holder)
-      << "Attempting to get the instance group for a BrowserState that was "
-      << "never Initialize()ed.";
-  return holder->instance_group();
-}
-
-// static
-service_manager::Connector* BrowserState::GetConnectorFor(
-    BrowserState* browser_state) {
-  ServiceManagerConnection* connection =
-      GetServiceManagerConnectionFor(browser_state);
-  return connection ? connection->GetConnector() : nullptr;
-}
-
-// static
-ServiceManagerConnection* BrowserState::GetServiceManagerConnectionFor(
-    BrowserState* browser_state) {
-  BrowserStateServiceManagerConnectionHolder* connection_holder =
-      static_cast<BrowserStateServiceManagerConnectionHolder*>(
-          browser_state->GetUserData(kServiceManagerConnection));
-  return connection_holder ? connection_holder->service_manager_connection()
-                           : nullptr;
-}
-
-std::unique_ptr<service_manager::Service> BrowserState::HandleServiceRequest(
-    const std::string& service_name,
-    service_manager::mojom::ServiceRequest request) {
-  return nullptr;
-}
-
 }  // namespace web
diff --git a/ios/web/init/BUILD.gn b/ios/web/init/BUILD.gn
index 93c22555..958a65b 100644
--- a/ios/web/init/BUILD.gn
+++ b/ios/web/init/BUILD.gn
@@ -21,7 +21,6 @@
     "//ios/web/net",
     "//ios/web/public",
     "//ios/web/public/init",
-    "//ios/web/service",
     "//ios/web/webui",
     "//mojo/core/embedder",
     "//net",
diff --git a/ios/web/init/web_main_loop.h b/ios/web/init/web_main_loop.h
index 4983804..aade4b8 100644
--- a/ios/web/init/web_main_loop.h
+++ b/ios/web/init/web_main_loop.h
@@ -13,7 +13,6 @@
 
 namespace web {
 class CookieNotificationBridge;
-class ServiceManagerContext;
 class WebMainParts;
 class WebThreadImpl;
 class WebSubThread;
@@ -79,7 +78,6 @@
 
   // Members initialized in |WebThreadsStarted()| --------------------------
   std::unique_ptr<CookieNotificationBridge> cookie_notification_bridge_;
-  std::unique_ptr<ServiceManagerContext> service_manager_context_;
 
   DISALLOW_COPY_AND_ASSIGN(WebMainLoop);
 };
diff --git a/ios/web/init/web_main_loop.mm b/ios/web/init/web_main_loop.mm
index c0f0322..22d8975 100644
--- a/ios/web/init/web_main_loop.mm
+++ b/ios/web/init/web_main_loop.mm
@@ -27,7 +27,6 @@
 #include "ios/web/public/init/web_main_parts.h"
 #include "ios/web/public/thread/web_task_traits.h"
 #import "ios/web/public/web_client.h"
-#include "ios/web/service/service_manager_context.h"
 #include "ios/web/web_sub_thread.h"
 #include "ios/web/web_thread_impl.h"
 #include "ios/web/webui/url_data_manager_ios.h"
@@ -177,8 +176,6 @@
     parts_->PostMainMessageLoopRun();
   }
 
-  service_manager_context_.reset();
-
   io_thread_.reset();
 
   // Only stop IO thread above as this is the only WebThread besides UI (which
@@ -212,7 +209,6 @@
 
 int WebMainLoop::WebThreadsStarted() {
   cookie_notification_bridge_.reset(new CookieNotificationBridge);
-  service_manager_context_ = std::make_unique<ServiceManagerContext>();
   return result_code_;
 }
 
diff --git a/ios/web/public/BUILD.gn b/ios/web/public/BUILD.gn
index ea5f891..37d812f 100644
--- a/ios/web/public/BUILD.gn
+++ b/ios/web/public/BUILD.gn
@@ -9,7 +9,6 @@
     ":web_state_observer",
     "//ios/web/public/favicon",
     "//ios/web/public/navigation",
-    "//ios/web/public/service",
     "//ios/web/public/thread",
     "//net",
     "//services/network/public/cpp",
@@ -20,7 +19,6 @@
     "//ios/web/common",
     "//ios/web/common:user_agent",
     "//ios/web/public/deprecated",
-    "//services/service_manager/public/cpp",
     "//ui/base",
   ]
 
diff --git a/ios/web/public/browser_state.h b/ios/web/public/browser_state.h
index 7afd2186..3ce5be2 100644
--- a/ios/web/public/browser_state.h
+++ b/ios/web/public/browser_state.h
@@ -12,12 +12,9 @@
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
 
 namespace base {
 class FilePath;
-class Token;
 }
 
 namespace net {
@@ -29,14 +26,9 @@
 class WeakWrapperSharedURLLoaderFactory;
 }  // namespace network
 
-namespace service_manager {
-class Connector;
-}
-
 namespace web {
 class CertificatePolicyCache;
 class NetworkContextOwner;
-class ServiceManagerConnection;
 class URLDataManagerIOS;
 class URLDataManagerIOSBackend;
 class URLRequestChromeJob;
@@ -83,28 +75,6 @@
   static BrowserState* FromSupportsUserData(
       base::SupportsUserData* supports_user_data);
 
-  // Returns a service instance group associated with this BrowserState. This ID
-  // is not persistent across runs. See
-  // services/service_manager/public/mojom/connector.mojom. By default,
-  // this instance group ID is randomly generated when Initialize() is called.
-  static const base::Token& GetServiceInstanceGroupFor(
-      BrowserState* browser_state);
-
-  // Returns a Connector associated with this BrowserState, which can be used
-  // to connect to service instances bound as this user.
-  static service_manager::Connector* GetConnectorFor(
-      BrowserState* browser_state);
-
-  // Returns a ServiceManagerConnection associated with this BrowserState,
-  // which can be used to connect to service instances bound as this user.
-  static ServiceManagerConnection* GetServiceManagerConnectionFor(
-      BrowserState* browser_state);
-
-  // Handles an incoming request for a per-browser-state service.
-  virtual std::unique_ptr<service_manager::Service> HandleServiceRequest(
-      const std::string& service_name,
-      service_manager::mojom::ServiceRequest request);
-
   // Updates |cors_exempt_header_list| field of the given |param| to register
   // headers that are used in content for special purpose and should not be
   // blocked by CORS checks.
@@ -114,12 +84,6 @@
  protected:
   BrowserState();
 
-  // Makes the Service Manager aware of this BrowserState, and assigns an
-  // instance group ID to it. Must be called for each BrowserState created.
-  // |path| should be the same path that would be returned by GetStatePath().
-  static void Initialize(BrowserState* browser_state,
-                         const base::FilePath& path);
-
  private:
   friend class URLDataManagerIOS;
   friend class URLRequestChromeJob;
diff --git a/ios/web/public/service/BUILD.gn b/ios/web/public/service/BUILD.gn
deleted file mode 100644
index d92ed99..0000000
--- a/ios/web/public/service/BUILD.gn
+++ /dev/null
@@ -1,29 +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.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-source_set("service") {
-  deps = [
-    "//base",
-    "//services/network/public/cpp",
-    "//services/network/public/mojom",
-    "//services/service_manager/public/cpp",
-    "//services/service_manager/public/cpp:cpp_types",
-    "//services/service_manager/public/mojom",
-  ]
-
-  sources = [
-    "service_manager_connection.h",
-    "web_state_interface_provider.h",
-  ]
-
-  configs += [ "//build/config/compiler:enable_arc" ]
-}
-
-mojom("service_names") {
-  sources = [
-    "service_names.mojom",
-  ]
-}
diff --git a/ios/web/public/service/OWNERS b/ios/web/public/service/OWNERS
deleted file mode 100644
index 4415d23..0000000
--- a/ios/web/public/service/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-rockot@google.com
-
-# TEAM: ios-directory-owners@chromium.org
-# OS: iOS
-
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/ios/web/public/service/README.md b/ios/web/public/service/README.md
deleted file mode 100644
index 9f8b6a9d..0000000
--- a/ios/web/public/service/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This directory contains API for establishing mojo connection with web service.
diff --git a/ios/web/public/service/service_manager_connection.h b/ios/web/public/service/service_manager_connection.h
deleted file mode 100644
index 77dffdc..0000000
--- a/ios/web/public/service/service_manager_connection.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_WEB_PUBLIC_SERVICE_SERVICE_MANAGER_CONNECTION_H_
-#define IOS_WEB_PUBLIC_SERVICE_SERVICE_MANAGER_CONNECTION_H_
-
-#include <memory>
-
-#include "base/callback_forward.h"
-#include "base/sequenced_task_runner.h"
-#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
-
-namespace service_manager {
-class Connector;
-}
-
-namespace web {
-
-// Encapsulates a connection to a //services/service_manager.
-// Access a global instance on the thread the ServiceContext was bound by
-// calling Holder::Get().
-// Clients can add service_manager::Service implementations whose exposed
-// interfaces
-// will be exposed to inbound connections to this object's Service.
-// Alternatively clients can define named services that will be constructed when
-// requests for those service names are received.
-// Clients must call any of the registration methods when receiving
-// WebClient::RegisterInProcessServices().
-class ServiceManagerConnection {
- public:
-  // Sets |connection| as the connection that is globally accessible from the
-  // UI thread. Should be called on the UI thread.
-  static void Set(std::unique_ptr<ServiceManagerConnection> connection);
-
-  // Returns the global instance, or nullptr if the Service Manager
-  // connection has not yet been bound. Should be called on the UI thread.
-  static ServiceManagerConnection* Get();
-
-  // Destroys the global instance. Should be called on the UI thread.
-  static void Destroy();
-
-  virtual ~ServiceManagerConnection();
-
-  // Creates a ServiceManagerConnection from |request|. The connection binds
-  // its interfaces and accept new connections on |io_task_runner| only. Note
-  // that no incoming connections are accepted until Start() is called.
-  static std::unique_ptr<ServiceManagerConnection> Create(
-      service_manager::mojom::ServiceRequest request,
-      scoped_refptr<base::SequencedTaskRunner> io_task_runner);
-
-  // Begins accepting incoming connections.
-  virtual void Start() = 0;
-
-  // Returns the service_manager::Connector received via this connection's
-  // Service implementation. Use this to initiate connections as this object's
-  // Identity.
-  virtual service_manager::Connector* GetConnector() = 0;
-
-  // Sets a callback to be invoked on the ServiceManagerConnection's owning
-  // sequence with any unhandled service requests.
-  using ServiceRequestHandler = base::RepeatingCallback<void(
-      const std::string& service_name,
-      service_manager::mojom::ServiceRequest request)>;
-  virtual void SetDefaultServiceRequestHandler(
-      const ServiceRequestHandler& handler) = 0;
-};
-
-}  // namespace web
-
-#endif  // IOS_WEB_PUBLIC_SERVICE_SERVICE_MANAGER_CONNECTION_H_
diff --git a/ios/web/public/service/service_names.mojom b/ios/web/public/service/service_names.mojom
deleted file mode 100644
index 25c5a90..0000000
--- a/ios/web/public/service/service_names.mojom
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module web.mojom;
-
-// The service name the browser identifies as when connecting to the Service
-// Manager for its privileged global singleton instance.
-const string kSystemServiceName = "web_system";
-
-// The service name the browser identifies as when connecting to the Service
-// Manager for each BrowserState instance.
-const string kBrowserServiceName = "web_browser";
diff --git a/ios/web/public/service/web_state_interface_provider.h b/ios/web/public/service/web_state_interface_provider.h
deleted file mode 100644
index 52ad2681..0000000
--- a/ios/web/public/service/web_state_interface_provider.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_WEB_PUBLIC_SERVICE_WEB_STATE_INTERFACE_PROVIDER_H_
-#define IOS_WEB_PUBLIC_SERVICE_WEB_STATE_INTERFACE_PROVIDER_H_
-
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/mojom/interface_provider.mojom.h"
-
-namespace web {
-
-class WebStateInterfaceProvider
-    : public service_manager::mojom::InterfaceProvider {
- public:
-  WebStateInterfaceProvider();
-  ~WebStateInterfaceProvider() override;
-
-  void Bind(service_manager::mojom::InterfaceProviderRequest request);
-
-  service_manager::BinderRegistry* registry() { return &registry_; }
-
- private:
-  // service_manager::mojom::InterfaceProvider:
-  void GetInterface(const std::string& interface_name,
-                    mojo::ScopedMessagePipeHandle handle) override;
-
-  service_manager::BinderRegistry registry_;
-
-  mojo::Binding<service_manager::mojom::InterfaceProvider> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebStateInterfaceProvider);
-};
-
-}  // namespace web
-
-#endif  // IOS_WEB_PUBLIC_SERVICE_WEB_STATE_INTERFACE_PROVIDER_H_
diff --git a/ios/web/public/test/BUILD.gn b/ios/web/public/test/BUILD.gn
index f4e8d7d..36d594c2 100644
--- a/ios/web/public/test/BUILD.gn
+++ b/ios/web/public/test/BUILD.gn
@@ -31,8 +31,6 @@
     "scoped_testing_web_client.mm",
     "test_redirect_observer.h",
     "test_redirect_observer.mm",
-    "test_service_manager_context.h",
-    "test_service_manager_context.mm",
     "test_web_thread.h",
     "test_web_thread_bundle.h",
     "web_js_test.h",
diff --git a/ios/web/public/test/fakes/test_browser_state.cc b/ios/web/public/test/fakes/test_browser_state.cc
index 59f272e7..278e0e6 100644
--- a/ios/web/public/test/fakes/test_browser_state.cc
+++ b/ios/web/public/test/fakes/test_browser_state.cc
@@ -48,9 +48,7 @@
 // static
 const char TestBrowserState::kCorsExemptTestHeaderName[] = "ExemptTest";
 
-TestBrowserState::TestBrowserState() : is_off_the_record_(false) {
-  BrowserState::Initialize(this, GetStatePath());
-}
+TestBrowserState::TestBrowserState() : is_off_the_record_(false) {}
 
 TestBrowserState::~TestBrowserState() {}
 
diff --git a/ios/web/public/test/fakes/test_web_state.h b/ios/web/public/test/fakes/test_web_state.h
index 205bbae..22457d655 100644
--- a/ios/web/public/test/fakes/test_web_state.h
+++ b/ios/web/public/test/fakes/test_web_state.h
@@ -81,7 +81,6 @@
 
   void AddPolicyDecider(WebStatePolicyDecider* decider) override;
   void RemovePolicyDecider(WebStatePolicyDecider* decider) override;
-  WebStateInterfaceProvider* GetWebStateInterfaceProvider() override;
   void DidChangeVisibleSecurityState() override {}
   bool HasOpener() const override;
   void SetHasOpener(bool has_opener) override;
diff --git a/ios/web/public/test/fakes/test_web_state.mm b/ios/web/public/test/fakes/test_web_state.mm
index ce4360de..8f78a6fb 100644
--- a/ios/web/public/test/fakes/test_web_state.mm
+++ b/ios/web/public/test/fakes/test_web_state.mm
@@ -383,10 +383,6 @@
   policy_deciders_.RemoveObserver(decider);
 }
 
-WebStateInterfaceProvider* TestWebState::GetWebStateInterfaceProvider() {
-  return nullptr;
-}
-
 bool TestWebState::HasOpener() const {
   return has_opener_;
 }
diff --git a/ios/web/public/test/test_service_manager_context.h b/ios/web/public/test/test_service_manager_context.h
deleted file mode 100644
index 061c7c0e..0000000
--- a/ios/web/public/test/test_service_manager_context.h
+++ /dev/null
@@ -1,32 +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 IOS_WEB_PUBLIC_TEST_TEST_SERVICE_MANAGER_CONTEXT_H_
-#define IOS_WEB_PUBLIC_TEST_TEST_SERVICE_MANAGER_CONTEXT_H_
-
-#include <memory>
-
-#include "base/macros.h"
-
-namespace web {
-
-class ServiceManagerContext;
-
-// Provides a public helper for client unit tests to construct a
-// ServiceManagerContext, which is generally private to the ios/web
-// implementation. Requires an IO thread to use.
-class TestServiceManagerContext {
- public:
-  TestServiceManagerContext();
-  ~TestServiceManagerContext();
-
- private:
-  std::unique_ptr<ServiceManagerContext> context_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestServiceManagerContext);
-};
-
-}  // namespace web
-
-#endif  // IOS_WEB_PUBLIC_TEST_TEST_SERVICE_MANAGER_CONTEXT_H_
\ No newline at end of file
diff --git a/ios/web/public/test/test_service_manager_context.mm b/ios/web/public/test/test_service_manager_context.mm
deleted file mode 100644
index 6385a789..0000000
--- a/ios/web/public/test/test_service_manager_context.mm
+++ /dev/null
@@ -1,20 +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 "ios/web/public/test/test_service_manager_context.h"
-
-#include "ios/web/service/service_manager_context.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace web {
-
-TestServiceManagerContext::TestServiceManagerContext()
-    : context_(std::make_unique<ServiceManagerContext>()) {}
-
-TestServiceManagerContext::~TestServiceManagerContext() = default;
-
-}  // namespace web
\ No newline at end of file
diff --git a/ios/web/public/web_client.h b/ios/web/public/web_client.h
index 57bb049..dfc9e4d0 100644
--- a/ios/web/public/web_client.h
+++ b/ios/web/public/web_client.h
@@ -17,8 +17,7 @@
 #include "base/task/thread_pool/thread_pool.h"
 #include "base/values.h"
 #include "ios/web/common/user_agent.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "services/service_manager/public/cpp/manifest.h"
+#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
 #include "ui/base/layout.h"
 #include "url/url_util.h"
 
@@ -136,23 +135,12 @@
   virtual NSString* GetDocumentStartScriptForMainFrame(
       BrowserState* browser_state) const;
 
-  // Allows the embedder to augment service manifests for existing services.
-  // Specifically, the sets of exposed and required capabilities, interface
-  // filter capabilities (deprecated), and packaged services will be taken from
-  // the returned Manifest and amended to those of the existing Manifest for the
-  // service named |name|.
-  //
-  // If no overlay is provided for the service, this returns |base::nullopt|.
-  virtual base::Optional<service_manager::Manifest> GetServiceManifestOverlay(
-      base::StringPiece name);
-
   // Allows the embedder to bind an interface request for a WebState-scoped
   // interface that originated from the main frame of |web_state|. Called if
-  // |web_state| could not bind the request for |interface_name| itself.
-  virtual void BindInterfaceRequestFromMainFrame(
+  // |web_state| could not bind the receiver itself.
+  virtual void BindInterfaceReceiverFromMainFrame(
       WebState* web_state,
-      const std::string& interface_name,
-      mojo::ScopedMessagePipeHandle interface_pipe) {}
+      mojo::GenericPendingReceiver receiver) {}
 
   // Informs the embedder that a certificate error has occurred. |cert_error| is
   // a network error code defined in //net/base/net_error_list.h. If
diff --git a/ios/web/public/web_state/web_state.h b/ios/web/public/web_state/web_state.h
index f4b25bdd..3d941f4 100644
--- a/ios/web/public/web_state/web_state.h
+++ b/ios/web/public/web_state/web_state.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include <map>
 #include <memory>
 #include <string>
 #include <utility>
@@ -15,10 +16,11 @@
 #include "base/callback_forward.h"
 #include "base/callback_list.h"
 #include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
 #include "base/supports_user_data.h"
 #include "ios/web/public/deprecated/url_verification_constants.h"
 #include "ios/web/public/navigation/referrer.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/base/window_open_disposition.h"
@@ -53,7 +55,6 @@
 class WebFramesManager;
 class WebInterstitial;
 class WebStateDelegate;
-class WebStateInterfaceProvider;
 class WebStateObserver;
 class WebStatePolicyDecider;
 
@@ -105,6 +106,48 @@
     bool is_renderer_initiated;
   };
 
+  // InterfaceBinder can be instantiated by subclasses of WebState and returned
+  // by GetInterfaceBinderForMainFrame().
+  class InterfaceBinder {
+   public:
+    explicit InterfaceBinder(WebState* web_state);
+    ~InterfaceBinder();
+
+    template <typename Interface>
+    void AddInterface(
+        base::RepeatingCallback<void(mojo::PendingReceiver<Interface>)>
+            callback) {
+      AddInterface(
+          Interface::Name_,
+          base::BindRepeating(&WrapCallback<Interface>, std::move(callback)));
+    }
+
+    // Adds a callback to bind an interface receiver pipe carried by a
+    // GenericPendingReceiver.
+    using Callback =
+        base::RepeatingCallback<void(mojo::GenericPendingReceiver*)>;
+    void AddInterface(base::StringPiece interface_name, Callback callback);
+
+    // Attempts to bind |receiver| by matching its interface name against the
+    // callbacks registered on this InterfaceBinder.
+    void BindInterface(mojo::GenericPendingReceiver receiver);
+
+   private:
+    template <typename Interface>
+    static void WrapCallback(
+        base::RepeatingCallback<void(mojo::PendingReceiver<Interface>)>
+            callback,
+        mojo::GenericPendingReceiver* receiver) {
+      if (auto typed_receiver = receiver->As<Interface>())
+        callback.Run(std::move(typed_receiver));
+    }
+
+    WebState* const web_state_;
+    std::map<std::string, Callback> callbacks_;
+
+    DISALLOW_COPY_AND_ASSIGN(InterfaceBinder);
+  };
+
   // Creates a new WebState.
   static std::unique_ptr<WebState> Create(const CreateParams& params);
 
@@ -282,9 +325,6 @@
   // Returns the current CRWWebViewProxy object.
   virtual CRWWebViewProxyType GetWebViewProxy() const = 0;
 
-  // Returns Mojo interface registry for this WebState.
-  virtual WebStateInterfaceProvider* GetWebStateInterfaceProvider() = 0;
-
   // Typically an embedder will:
   //    - Implement this method to receive notification of changes to the page's
   //      |VisibleSecurityState|, updating security UI (e.g. a lock icon) to
@@ -294,23 +334,8 @@
   //      the security state (e.g. a non-secure form element is edited).
   virtual void DidChangeVisibleSecurityState() = 0;
 
- protected:
-  // Binds |interface_pipe| to an implementation of |interface_name| that is
-  // scoped to this WebState instance (if that such an implementation is
-  // present). Embedders of //ios/web can inject interface implementations by
-  // overriding WebClient::BindInterfaceRequestFromMainFrame().
-  // NOTE: Callers should use the more-friendly wrapper below.
-  virtual void BindInterfaceRequestFromMainFrame(
-      const std::string& interface_name,
-      mojo::ScopedMessagePipeHandle interface_pipe) {}
-
  public:
-  template <class Interface>
-  void BindInterfaceRequestFromMainFrame(
-      mojo::InterfaceRequest<Interface> request) {
-    BindInterfaceRequestFromMainFrame(Interface::Name_,
-                                      std::move(request.PassMessagePipe()));
-  }
+  virtual InterfaceBinder* GetInterfaceBinderForMainFrame();
 
   // Whether this WebState was created with an opener.
   // See CreateParams::created_with_opener for more details.
diff --git a/ios/web/service/BUILD.gn b/ios/web/service/BUILD.gn
deleted file mode 100644
index 05b529b9..0000000
--- a/ios/web/service/BUILD.gn
+++ /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.
-
-source_set("service") {
-  deps = [
-    "//ios/web/public",
-    "//ios/web/public/service:service_names",
-    "//services/network:network_service",
-    "//services/network/public/mojom",
-    "//services/service_manager",
-    "//services/service_manager/public/cpp",
-    "//services/service_manager/public/mojom",
-  ]
-  sources = [
-    "service_manager_connection_impl.cc",
-    "service_manager_connection_impl.h",
-    "service_manager_context.h",
-    "service_manager_context.mm",
-    "web_browser_manifest.h",
-    "web_browser_manifest.mm",
-    "web_state_interface_provider.cc",
-  ]
-
-  configs += [ "//build/config/compiler:enable_arc" ]
-}
-
-source_set("unittests") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  testonly = true
-  deps = [
-    ":service",
-    "//base",
-    "//base/test:test_support",
-    "//ios/web/public/test",
-    "//services/service_manager/public/cpp",
-    "//testing/gtest",
-  ]
-
-  sources = [
-    "service_manager_connection_impl_unittest.cc",
-  ]
-}
diff --git a/ios/web/service/OWNERS b/ios/web/service/OWNERS
deleted file mode 100644
index b225ddf..0000000
--- a/ios/web/service/OWNERS
+++ /dev/null
@@ -1,9 +0,0 @@
-rockot@google.com
-
-# TEAM: ios-directory-owners@chromium.org
-# OS: iOS
-
-per-file web_browser_manifest.cc=set noparent
-per-file web_browser_manifest.cc=file://ipc/SECURITY_OWNERS
-per-file web_browser_manifest.h=set noparent
-per-file web_browser_manifest.h=file://ipc/SECURITY_OWNERS
diff --git a/ios/web/service/service_manager_connection_impl.cc b/ios/web/service/service_manager_connection_impl.cc
deleted file mode 100644
index 0ad2047..0000000
--- a/ios/web/service/service_manager_connection_impl.cc
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/web/service/service_manager_connection_impl.h"
-
-#include <queue>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop_current.h"
-#include "base/no_destructor.h"
-#include "base/threading/thread_checker.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "ios/web/public/thread/web_thread.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_binding.h"
-#include "services/service_manager/public/mojom/constants.mojom.h"
-
-namespace web {
-namespace {
-
-std::unique_ptr<ServiceManagerConnection>& GetConnectionForProcess() {
-  static base::NoDestructor<std::unique_ptr<ServiceManagerConnection>>
-      connection_for_process;
-  return *connection_for_process;
-}
-
-}  // namespace
-
-// A ref-counted object which owns the IO thread state of a
-// ServiceManagerConnectionImpl. This includes Service bindings.
-class ServiceManagerConnectionImpl::IOThreadContext
-    : public base::RefCountedThreadSafe<IOThreadContext>,
-      public service_manager::Service {
- public:
-  IOThreadContext(service_manager::mojom::ServiceRequest service_request,
-                  scoped_refptr<base::SequencedTaskRunner> io_task_runner,
-                  service_manager::mojom::ConnectorRequest connector_request)
-      : pending_service_request_(std::move(service_request)),
-        io_task_runner_(io_task_runner),
-        pending_connector_request_(std::move(connector_request)),
-        weak_factory_(this) {
-    // This will be reattached by any of the IO thread functions on first call.
-    io_thread_checker_.DetachFromThread();
-  }
-
-  // Safe to call from any thread.
-  void Start(base::OnceClosure stop_callback,
-             const ServiceManagerConnection::ServiceRequestHandler&
-                 default_request_handler) {
-    DCHECK(!started_);
-
-    started_ = true;
-    callback_task_runner_ = base::ThreadTaskRunnerHandle::Get();
-    stop_callback_ = std::move(stop_callback);
-    default_request_handler_ = default_request_handler;
-    io_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&IOThreadContext::StartOnIOThread, this));
-  }
-
-  // Safe to call from whichever thread called Start() (or may have called
-  // Start()). Must be called before IO thread shutdown.
-  void ShutDown() {
-    if (!started_)
-      return;
-
-    bool posted = io_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&IOThreadContext::ShutDownOnIOThread, this));
-    DCHECK(posted);
-  }
-
- private:
-  friend class base::RefCountedThreadSafe<IOThreadContext>;
-
-  class MessageLoopObserver
-      : public base::MessageLoopCurrent::DestructionObserver {
-   public:
-    explicit MessageLoopObserver(base::WeakPtr<IOThreadContext> context)
-        : context_(context) {
-      base::MessageLoopCurrent::Get()->AddDestructionObserver(this);
-    }
-
-    ~MessageLoopObserver() override {
-      base::MessageLoopCurrent::Get()->RemoveDestructionObserver(this);
-    }
-
-    void ShutDown() {
-      if (!is_active_)
-        return;
-
-      // The call into |context_| below may reenter ShutDown(), hence we set
-      // |is_active_| to false here.
-      is_active_ = false;
-      if (context_)
-        context_->ShutDownOnIOThread();
-
-      delete this;
-    }
-
-   private:
-    void WillDestroyCurrentMessageLoop() override {
-      DCHECK(is_active_);
-      ShutDown();
-    }
-
-    bool is_active_ = true;
-    base::WeakPtr<IOThreadContext> context_;
-
-    DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver);
-  };
-
-  ~IOThreadContext() override {}
-
-  void StartOnIOThread() {
-    // Should bind |io_thread_checker_| to the context's thread.
-    DCHECK(io_thread_checker_.CalledOnValidThread());
-    DCHECK(!service_binding_);
-    service_binding_ = std::make_unique<service_manager::ServiceBinding>(
-        this, std::move(pending_service_request_));
-    service_binding_->GetConnector()->BindConnectorRequest(
-        std::move(pending_connector_request_));
-
-    // MessageLoopObserver owns itself.
-    message_loop_observer_ =
-        new MessageLoopObserver(weak_factory_.GetWeakPtr());
-  }
-
-  void ShutDownOnIOThread() {
-    DCHECK(io_thread_checker_.CalledOnValidThread());
-
-    weak_factory_.InvalidateWeakPtrs();
-
-    // Note that this method may be invoked by MessageLoopObserver observing
-    // MessageLoop destruction. In that case, this call to ShutDown is
-    // effectively a no-op. In any case it's safe.
-    if (message_loop_observer_) {
-      message_loop_observer_->ShutDown();
-      message_loop_observer_ = nullptr;
-    }
-
-    // Resetting the ServiceContext below may otherwise release the last
-    // reference to this IOThreadContext. We keep it alive until the stack
-    // unwinds.
-    scoped_refptr<IOThreadContext> keepalive(this);
-
-    service_binding_.reset();
-  }
-
-  // service_manager::Service:
-  void CreatePackagedServiceInstance(
-      const std::string& service_name,
-      mojo::PendingReceiver<service_manager::mojom::Service> receiver,
-      CreatePackagedServiceInstanceCallback callback) override {
-    DCHECK(io_thread_checker_.CalledOnValidThread());
-    callback_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(default_request_handler_, service_name,
-                                  service_manager::mojom::ServiceRequest(
-                                      std::move(receiver))));
-    std::move(callback).Run(base::ProcessId());
-  }
-
-  void OnDisconnected() override {
-    callback_task_runner_->PostTask(FROM_HERE, std::move(stop_callback_));
-  }
-
-  base::ThreadChecker io_thread_checker_;
-  bool started_ = false;
-
-  // Temporary state established on construction and consumed on the IO thread
-  // once the connection is started.
-  service_manager::mojom::ServiceRequest pending_service_request_;
-  scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
-  service_manager::mojom::ConnectorRequest pending_connector_request_;
-
-  // TaskRunner on which to run our owner's callbacks, i.e. the ones passed to
-  // Start().
-  scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
-
-  // Callback to run if the service is stopped by the service manager.
-  base::OnceClosure stop_callback_;
-
-  ServiceManagerConnection::ServiceRequestHandler default_request_handler_;
-
-  std::unique_ptr<service_manager::ServiceBinding> service_binding_;
-
-  // Not owned.
-  MessageLoopObserver* message_loop_observer_ = nullptr;
-
-  base::WeakPtrFactory<IOThreadContext> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(IOThreadContext);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// ServiceManagerConnection, public:
-
-// static
-void ServiceManagerConnection::Set(
-    std::unique_ptr<ServiceManagerConnection> connection) {
-  DCHECK_CURRENTLY_ON(WebThread::UI);
-  DCHECK(!GetConnectionForProcess());
-  GetConnectionForProcess() = std::move(connection);
-}
-
-// static
-ServiceManagerConnection* ServiceManagerConnection::Get() {
-  // WebThreads are not initialized in many unit tests. These tests also by
-  // definition are not setting the global ServiceManagerConnection (since
-  // otherwise the DCHECK in the above method would fire).
-  DCHECK(!web::WebThread::IsThreadInitialized(web::WebThread::UI) ||
-         web::WebThread::CurrentlyOn(web::WebThread::UI));
-  return GetConnectionForProcess().get();
-}
-
-// static
-void ServiceManagerConnection::Destroy() {
-  DCHECK_CURRENTLY_ON(WebThread::UI);
-
-  // This joins the service manager controller thread.
-  GetConnectionForProcess().reset();
-}
-
-// static
-std::unique_ptr<ServiceManagerConnection> ServiceManagerConnection::Create(
-    service_manager::mojom::ServiceRequest request,
-    scoped_refptr<base::SequencedTaskRunner> io_task_runner) {
-  return std::make_unique<ServiceManagerConnectionImpl>(std::move(request),
-                                                        io_task_runner);
-}
-
-ServiceManagerConnection::~ServiceManagerConnection() {}
-
-////////////////////////////////////////////////////////////////////////////////
-// ServiceManagerConnectionImpl, public:
-
-ServiceManagerConnectionImpl::ServiceManagerConnectionImpl(
-    service_manager::mojom::ServiceRequest request,
-    scoped_refptr<base::SequencedTaskRunner> io_task_runner)
-    : weak_factory_(this) {
-  service_manager::mojom::ConnectorRequest connector_request;
-  connector_ = service_manager::Connector::Create(&connector_request);
-  context_ = new IOThreadContext(std::move(request), io_task_runner,
-                                 std::move(connector_request));
-}
-
-ServiceManagerConnectionImpl::~ServiceManagerConnectionImpl() {
-  context_->ShutDown();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ServiceManagerConnectionImpl, ServiceManagerConnection implementation:
-
-void ServiceManagerConnectionImpl::Start() {
-  context_->Start(
-      base::BindOnce(&ServiceManagerConnectionImpl::OnConnectionLost,
-                     weak_factory_.GetWeakPtr()),
-      base::BindRepeating(
-          &ServiceManagerConnectionImpl::OnUnhandledServiceRequest,
-          weak_factory_.GetWeakPtr()));
-}
-
-service_manager::Connector* ServiceManagerConnectionImpl::GetConnector() {
-  return connector_.get();
-}
-
-void ServiceManagerConnectionImpl::SetDefaultServiceRequestHandler(
-    const ServiceRequestHandler& handler) {
-  default_request_handler_ = handler;
-}
-
-void ServiceManagerConnectionImpl::OnConnectionLost() {}
-
-void ServiceManagerConnectionImpl::GetInterface(
-    service_manager::mojom::InterfaceProvider* provider,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle request_handle) {
-  provider->GetInterface(interface_name, std::move(request_handle));
-}
-
-void ServiceManagerConnectionImpl::OnUnhandledServiceRequest(
-    const std::string& service_name,
-    service_manager::mojom::ServiceRequest request) {
-  if (default_request_handler_)
-    default_request_handler_.Run(service_name, std::move(request));
-  else
-    LOG(ERROR) << "Can't create service: " << service_name;
-}
-
-}  // namespace web
diff --git a/ios/web/service/service_manager_connection_impl.h b/ios/web/service/service_manager_connection_impl.h
deleted file mode 100644
index b5e19deba..0000000
--- a/ios/web/service/service_manager_connection_impl.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_WEB_SERVICE_SERVICE_MANAGER_CONNECTION_IMPL_H_
-#define IOS_WEB_SERVICE_SERVICE_MANAGER_CONNECTION_IMPL_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequenced_task_runner.h"
-#include "ios/web/public/service/service_manager_connection.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
-
-namespace service_manager {
-class Connector;
-}
-
-namespace web {
-
-class ServiceManagerConnectionImpl : public ServiceManagerConnection {
- public:
-  ServiceManagerConnectionImpl(
-      service_manager::mojom::ServiceRequest request,
-      scoped_refptr<base::SequencedTaskRunner> io_task_runner);
-  ~ServiceManagerConnectionImpl() override;
-
- private:
-  class IOThreadContext;
-
-  // ServiceManagerConnection:
-  void Start() override;
-  service_manager::Connector* GetConnector() override;
-  void SetDefaultServiceRequestHandler(
-      const ServiceRequestHandler& handler) override;
-
-  // Invoked when the connection to the Service Manager is lost.
-  void OnConnectionLost();
-
-  // Binds |request_handle| to an instance of |interface_name| provided by
-  // |interface_provider|.
-  void GetInterface(service_manager::mojom::InterfaceProvider* provider,
-                    const std::string& interface_name,
-                    mojo::ScopedMessagePipeHandle request_handle);
-
-  void OnUnhandledServiceRequest(
-      const std::string& service_name,
-      service_manager::mojom::ServiceRequest request);
-
-  std::unique_ptr<service_manager::Connector> connector_;
-
-  scoped_refptr<IOThreadContext> context_;
-  ServiceRequestHandler default_request_handler_;
-
-  base::WeakPtrFactory<ServiceManagerConnectionImpl> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ServiceManagerConnectionImpl);
-};
-
-}  // namespace web
-
-#endif  // IOS_WEB_SERVICE_SERVICE_MANAGER_CONNECTION_IMPL_H_
diff --git a/ios/web/service/service_manager_connection_impl_unittest.cc b/ios/web/service/service_manager_connection_impl_unittest.cc
deleted file mode 100644
index 7b10562..0000000
--- a/ios/web/service/service_manager_connection_impl_unittest.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/web/service/service_manager_connection_impl.h"
-
-#include "base/bind_helpers.h"
-#include "base/run_loop.h"
-#include "base/task/post_task.h"
-#include "base/test/bind_test_util.h"
-#include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/public/thread/web_task_traits.h"
-#include "ios/web/public/thread/web_thread.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/service_manager/public/cpp/constants.h"
-#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-namespace web {
-namespace {
-
-constexpr char kTestServiceName[] = "test service";
-
-}  // namespace
-
-using ServiceManagerConnectionImplTest = PlatformTest;
-
-TEST_F(ServiceManagerConnectionImplTest, ServiceLaunch) {
-  TestWebThreadBundle thread_bundle(
-      TestWebThreadBundle::Options::REAL_IO_THREAD);
-  service_manager::mojom::ServicePtr service;
-  ServiceManagerConnectionImpl connection_impl(
-      mojo::MakeRequest(&service),
-      base::CreateSingleThreadTaskRunnerWithTraits({WebThread::IO}));
-  ServiceManagerConnection& connection = connection_impl;
-  base::RunLoop run_loop;
-  connection.SetDefaultServiceRequestHandler(base::BindLambdaForTesting(
-      [&run_loop](const std::string& service_name,
-                  service_manager::mojom::ServiceRequest request) {
-        EXPECT_EQ(kTestServiceName, service_name);
-        run_loop.Quit();
-      }));
-  connection.Start();
-
-  mojo::PendingRemote<service_manager::mojom::Service> packaged_service;
-  mojo::PendingRemote<service_manager::mojom::ProcessMetadata> metadata;
-  ignore_result(metadata.InitWithNewPipeAndPassReceiver());
-  service->CreatePackagedServiceInstance(
-      service_manager::Identity(kTestServiceName, base::Token::CreateRandom(),
-                                base::Token(), base::Token::CreateRandom()),
-      packaged_service.InitWithNewPipeAndPassReceiver(), std::move(metadata));
-  run_loop.Run();
-}
-
-}  // namespace web
diff --git a/ios/web/service/service_manager_context.h b/ios/web/service/service_manager_context.h
deleted file mode 100644
index e70704b2..0000000
--- a/ios/web/service/service_manager_context.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_WEB_SERVICE_SERVICE_MANAGER_CONTEXT_H_
-#define IOS_WEB_SERVICE_SERVICE_MANAGER_CONTEXT_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-
-namespace web {
-
-// ServiceManagerContext manages the browser's connection to the ServiceManager,
-// hosting an in-process ServiceManagerContext.
-class ServiceManagerContext {
- public:
-  ServiceManagerContext();
-  ~ServiceManagerContext();
-
- private:
-  class InProcessServiceManagerContext;
-
-  scoped_refptr<InProcessServiceManagerContext> in_process_context_;
-
-  DISALLOW_COPY_AND_ASSIGN(ServiceManagerContext);
-};
-
-}  // namespace web
-
-#endif  // IOS_WEB_SERVICE_SERVICE_MANAGER_CONTEXT_H_
diff --git a/ios/web/service/service_manager_context.mm b/ios/web/service/service_manager_context.mm
deleted file mode 100644
index aaa5694..0000000
--- a/ios/web/service/service_manager_context.mm
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/web/service/service_manager_context.h"
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/macros.h"
-#include "base/process/process_handle.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/post_task.h"
-#include "ios/web/public/service/service_manager_connection.h"
-#include "ios/web/public/service/service_names.mojom.h"
-#include "ios/web/public/thread/web_task_traits.h"
-#include "ios/web/public/thread/web_thread.h"
-#include "ios/web/public/web_client.h"
-#include "ios/web/service/service_manager_connection_impl.h"
-#import "ios/web/service/web_browser_manifest.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/cpp/constants.h"
-#include "services/service_manager/public/cpp/manifest.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/mojom/service.mojom.h"
-#include "services/service_manager/service_manager.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace web {
-
-namespace {
-
-struct ManifestInfo {
-  const char* name;
-  int resource_id;
-};
-
-service_manager::Manifest GetWebSystemManifest() {
-  // TODO(crbug.com/961869): This is a bit of a temporary hack so that we can
-  // make the global service instance a singleton. For now we just mirror the
-  // per-BrowserState manifest (formerly also used for the global singleton
-  // instance), sans packaged services, since those are only meant to be tied to
-  // a BrowserState. The per-BrowserState service should go away soon, and then
-  // this can be removed.
-  service_manager::Manifest manifest = GetWebBrowserManifest();
-  manifest.service_name = mojom::kSystemServiceName;
-  manifest.packaged_services.clear();
-  manifest.options.instance_sharing_policy =
-      service_manager::Manifest::InstanceSharingPolicy::kSingleton;
-  return manifest;
-}
-
-using ServiceRunner = base::RepeatingCallback<void(
-    const service_manager::Identity&,
-    mojo::PendingReceiver<service_manager::mojom::Service> receiver)>;
-
-class BrowserServiceManagerDelegate
-    : public service_manager::ServiceManager::Delegate {
- public:
-  BrowserServiceManagerDelegate(
-      scoped_refptr<base::SequencedTaskRunner> task_runner,
-      ServiceRunner service_runner)
-      : task_runner_(std::move(task_runner)),
-        service_runner_(std::move(service_runner)) {}
-  ~BrowserServiceManagerDelegate() override = default;
-
-  bool RunBuiltinServiceInstanceInCurrentProcess(
-      const service_manager::Identity& identity,
-      mojo::PendingReceiver<service_manager::mojom::Service> receiver)
-      override {
-    task_runner_->PostTask(FROM_HERE, base::BindOnce(service_runner_, identity,
-                                                     std::move(receiver)));
-    return true;
-  }
-
-  std::unique_ptr<service_manager::ServiceProcessHost>
-  CreateProcessHostForBuiltinServiceInstance(
-      const service_manager::Identity& identity) override {
-    return nullptr;
-  }
-
-  std::unique_ptr<service_manager::ServiceProcessHost>
-  CreateProcessHostForServiceExecutable(
-      const base::FilePath& executable_path) override {
-    return nullptr;
-  }
-
- private:
-  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  const ServiceRunner service_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserServiceManagerDelegate);
-};
-
-}  // namespace
-
-// State which lives on the IO thread and drives the ServiceManager.
-class ServiceManagerContext::InProcessServiceManagerContext
-    : public base::RefCountedThreadSafe<InProcessServiceManagerContext> {
- public:
-  InProcessServiceManagerContext() {}
-
-  void Start(mojo::PendingRemote<service_manager::mojom::Service> system_remote,
-             std::vector<service_manager::Manifest> manifests,
-             ServiceRunner service_runner) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {WebThread::IO},
-        base::BindOnce(&InProcessServiceManagerContext::StartOnIOThread, this,
-                       std::move(manifests), std::move(system_remote),
-                       base::SequencedTaskRunnerHandle::Get(),
-                       std::move(service_runner)));
-  }
-
-  void ShutDown() {
-    base::PostTaskWithTraits(
-        FROM_HERE, {WebThread::IO},
-        base::BindOnce(&InProcessServiceManagerContext::ShutDownOnIOThread,
-                       this));
-  }
-
- private:
-  friend class base::RefCountedThreadSafe<InProcessServiceManagerContext>;
-
-  ~InProcessServiceManagerContext() = default;
-
-  // Creates the ServiceManager and registers the packaged services service
-  // with it, connecting the other end of the packaged services serviceto
-  // |packaged_services_service_info|.
-  void StartOnIOThread(
-      std::vector<service_manager::Manifest> manifests,
-      mojo::PendingRemote<service_manager::mojom::Service> system_remote,
-      scoped_refptr<base::SequencedTaskRunner> service_task_runner,
-      ServiceRunner service_runner) {
-    service_manager_ = std::make_unique<service_manager::ServiceManager>(
-        manifests,
-        std::make_unique<BrowserServiceManagerDelegate>(
-            std::move(service_task_runner), std::move(service_runner)));
-
-    mojo::Remote<service_manager::mojom::ProcessMetadata> metadata;
-    service_manager_->RegisterService(
-        service_manager::Identity(mojom::kSystemServiceName,
-                                  service_manager::kSystemInstanceGroup,
-                                  base::Token{}, base::Token::CreateRandom()),
-        std::move(system_remote), metadata.BindNewPipeAndPassReceiver());
-    metadata->SetPID(base::GetCurrentProcId());
-  }
-
-  void ShutDownOnIOThread() { service_manager_.reset(); }
-
-  std::unique_ptr<service_manager::ServiceManager> service_manager_;
-
-  DISALLOW_COPY_AND_ASSIGN(InProcessServiceManagerContext);
-};
-
-ServiceManagerContext::ServiceManagerContext() {
-  std::vector<service_manager::Manifest> manifests = {GetWebSystemManifest(),
-                                                      GetWebBrowserManifest()};
-  mojo::PendingRemote<service_manager::mojom::Service> system_remote;
-  ServiceManagerConnection::Set(ServiceManagerConnection::Create(
-      system_remote.InitWithNewPipeAndPassReceiver(),
-      base::CreateSingleThreadTaskRunnerWithTraits({WebThread::IO})));
-  auto* system_connection = ServiceManagerConnection::Get();
-
-  in_process_context_ = base::MakeRefCounted<InProcessServiceManagerContext>();
-  in_process_context_->Start(std::move(system_remote), std::move(manifests),
-                             base::DoNothing());
-  system_connection->Start();
-}
-
-ServiceManagerContext::~ServiceManagerContext() {
-  // NOTE: The in-process ServiceManager MUST be destroyed before the browser
-  // process-wide ServiceManagerConnection. Otherwise it's possible for the
-  // ServiceManager to receive connection requests for service:ios_web_browser
-  // which it may attempt to service by launching a new instance of the browser.
-  if (in_process_context_)
-    in_process_context_->ShutDown();
-  if (ServiceManagerConnection::Get())
-    ServiceManagerConnection::Destroy();
-}
-
-}  // namespace web
diff --git a/ios/web/service/web_browser_manifest.h b/ios/web/service/web_browser_manifest.h
deleted file mode 100644
index 0d5ea811c..0000000
--- a/ios/web/service/web_browser_manifest.h
+++ /dev/null
@@ -1,20 +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 IOS_WEB_SERVICE_WEB_BROWSER_MANIFEST_H_
-#define IOS_WEB_SERVICE_WEB_BROWSER_MANIFEST_H_
-
-#include "services/service_manager/public/cpp/manifest.h"
-
-namespace web {
-
-// Returns the service manifest for the web_browser service, which is the main
-// service that the core browser identifies as. This determines what service
-// capabilities the browser has access to, as well as what per-profile services
-// are packaged within the browser.
-const service_manager::Manifest& GetWebBrowserManifest();
-
-}  // namespace web
-
-#endif  // IOS_WEB_SERVICE_WEB_BROWSER_MANIFEST_H_
diff --git a/ios/web/service/web_browser_manifest.mm b/ios/web/service/web_browser_manifest.mm
deleted file mode 100644
index 2907044e..0000000
--- a/ios/web/service/web_browser_manifest.mm
+++ /dev/null
@@ -1,41 +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.
-
-#import "ios/web/service/web_browser_manifest.h"
-
-#include "base/no_destructor.h"
-#include "ios/web/public/service/service_names.mojom.h"
-#include "ios/web/public/web_client.h"
-#include "services/service_manager/public/cpp/manifest_builder.h"
-#include "services/service_manager/public/mojom/constants.mojom.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace web {
-
-const service_manager::Manifest& GetWebBrowserManifest() {
-  static base::NoDestructor<service_manager::Manifest> manifest{
-      service_manager::ManifestBuilder()
-          .WithServiceName(mojom::kBrowserServiceName)
-          .WithDisplayName("Web")
-          .WithOptions(service_manager::ManifestOptionsBuilder()
-                           .CanConnectToInstancesInAnyGroup(true)
-                           .CanConnectToInstancesWithAnyId(true)
-                           .CanRegisterOtherServiceInstances(true)
-                           .Build())
-          .RequireCapability(mojom::kBrowserServiceName, "")
-          .RequireCapability(mojom::kSystemServiceName, "")
-          .RequireCapability(service_manager::mojom::kServiceName,
-                             "service_manager:service_manager")
-          .Build()
-          .Amend(GetWebClient()
-                     ->GetServiceManifestOverlay(mojom::kBrowserServiceName)
-                     .value_or(service_manager::Manifest()))};
-
-  return *manifest;
-}
-
-}  // namespace web
diff --git a/ios/web/service/web_state_interface_provider.cc b/ios/web/service/web_state_interface_provider.cc
deleted file mode 100644
index fe921770..0000000
--- a/ios/web/service/web_state_interface_provider.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.
-
-#include "ios/web/public/service/web_state_interface_provider.h"
-
-namespace web {
-
-WebStateInterfaceProvider::WebStateInterfaceProvider() : binding_(this) {}
-WebStateInterfaceProvider::~WebStateInterfaceProvider() = default;
-
-void WebStateInterfaceProvider::Bind(
-    service_manager::mojom::InterfaceProviderRequest request) {
-  binding_.Bind(std::move(request));
-}
-
-void WebStateInterfaceProvider::GetInterface(
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle handle) {
-  registry_.BindInterface(interface_name, std::move(handle));
-}
-
-}  // namespace web
diff --git a/ios/web/shell/BUILD.gn b/ios/web/shell/BUILD.gn
index fd4f485d..71d8c41 100644
--- a/ios/web/shell/BUILD.gn
+++ b/ios/web/shell/BUILD.gn
@@ -71,10 +71,6 @@
     "//ios/web/public/init",
     "//net",
     "//net:extras",
-    "//services/service_manager/public/cpp",
-    "//services/test/user_id:lib",
-    "//services/test/user_id/public/cpp:manifest",
-    "//services/test/user_id/public/mojom",
     "//ui/base",
   ]
 
diff --git a/ios/web/shell/DEPS b/ios/web/shell/DEPS
index 7b20080..c4864a36 100644
--- a/ios/web/shell/DEPS
+++ b/ios/web/shell/DEPS
@@ -4,7 +4,5 @@
   "+ios/web/common",
   "+ios/web/public",
   "+ios/web/shell",
-  "+services/test/echo",
-  "+services/test/user_id",
 ]
 
diff --git a/ios/web/shell/shell_browser_state.h b/ios/web/shell/shell_browser_state.h
index dc4440f..045911a 100644
--- a/ios/web/shell/shell_browser_state.h
+++ b/ios/web/shell/shell_browser_state.h
@@ -25,9 +25,6 @@
   bool IsOffTheRecord() const override;
   base::FilePath GetStatePath() const override;
   net::URLRequestContextGetter* GetRequestContext() override;
-  std::unique_ptr<service_manager::Service> HandleServiceRequest(
-      const std::string& service_name,
-      service_manager::mojom::ServiceRequest request) override;
 
  private:
   base::FilePath path_;
diff --git a/ios/web/shell/shell_browser_state.mm b/ios/web/shell/shell_browser_state.mm
index fcc3a96..55b0135 100644
--- a/ios/web/shell/shell_browser_state.mm
+++ b/ios/web/shell/shell_browser_state.mm
@@ -12,7 +12,6 @@
 #include "ios/web/public/thread/web_task_traits.h"
 #include "ios/web/public/thread/web_thread.h"
 #include "ios/web/shell/shell_url_request_context_getter.h"
-#include "services/test/user_id/user_id_service.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -26,8 +25,6 @@
   request_context_getter_ = new ShellURLRequestContextGetter(
       GetStatePath(),
       base::CreateSingleThreadTaskRunnerWithTraits({web::WebThread::IO}));
-
-  BrowserState::Initialize(this, path_);
 }
 
 ShellBrowserState::~ShellBrowserState() {
@@ -45,14 +42,4 @@
   return request_context_getter_.get();
 }
 
-std::unique_ptr<service_manager::Service>
-ShellBrowserState::HandleServiceRequest(
-    const std::string& service_name,
-    service_manager::mojom::ServiceRequest request) {
-  if (service_name == "user_id")
-    return std::make_unique<user_id::UserIdService>(std::move(request));
-
-  return nullptr;
-}
-
 }  // namespace web
diff --git a/ios/web/shell/shell_web_client.h b/ios/web/shell/shell_web_client.h
index 6988330..3a616f57 100644
--- a/ios/web/shell/shell_web_client.h
+++ b/ios/web/shell/shell_web_client.h
@@ -10,7 +10,6 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #import "ios/web/public/web_client.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
 
 namespace web {
 class ShellBrowserState;
@@ -29,12 +28,9 @@
       ui::ScaleFactor scale_factor) const override;
   base::RefCountedMemory* GetDataResourceBytes(int resource_id) const override;
   bool IsDataResourceGzipped(int resource_id) const override;
-  base::Optional<service_manager::Manifest> GetServiceManifestOverlay(
-      base::StringPiece name) override;
-  void BindInterfaceRequestFromMainFrame(
+  void BindInterfaceReceiverFromMainFrame(
       WebState* web_state,
-      const std::string& interface_name,
-      mojo::ScopedMessagePipeHandle interface_pipe) override;
+      mojo::GenericPendingReceiver receiver) override;
   void AllowCertificateError(
       WebState* web_state,
       int cert_error,
@@ -46,18 +42,8 @@
   ShellBrowserState* browser_state() const;
 
  private:
-  void InitMainFrameInterfaces();
-
   ShellWebMainParts* web_main_parts_;
 
-  // Interfaces exposed to the main frame whose implementations do not need the
-  // WebState associated with that main frame as a creation argument.
-  std::unique_ptr<service_manager::BinderRegistry> main_frame_interfaces_;
-  // Interfaces exposed to the main frame whose implementations *do* need the
-  // WebState associated with that main frame as a creation argument.
-  std::unique_ptr<service_manager::BinderRegistryWithArgs<WebState*>>
-      main_frame_interfaces_parameterized_;
-
   DISALLOW_COPY_AND_ASSIGN(ShellWebClient);
 };
 
diff --git a/ios/web/shell/shell_web_client.mm b/ios/web/shell/shell_web_client.mm
index 52e4133..0f8b952 100644
--- a/ios/web/shell/shell_web_client.mm
+++ b/ios/web/shell/shell_web_client.mm
@@ -8,13 +8,11 @@
 
 #include "base/bind.h"
 #include "ios/web/common/user_agent.h"
-#include "ios/web/public/service/service_names.mojom.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ios/web/shell/shell_web_main_parts.h"
 #import "ios/web/shell/web_usage_controller.mojom.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/service_manager/public/cpp/manifest_builder.h"
-#include "services/test/user_id/public/cpp/manifest.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "ui/base/resource/resource_bundle.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -32,12 +30,6 @@
   explicit WebUsageController(WebState* web_state) : web_state_(web_state) {}
   ~WebUsageController() override {}
 
-  static void Create(mojo::InterfaceRequest<mojom::WebUsageController> request,
-                     WebState* web_state) {
-    mojo::MakeStrongBinding(std::make_unique<WebUsageController>(web_state),
-                            std::move(request));
-  }
-
  private:
   void SetWebUsageEnabled(bool enabled,
                           SetWebUsageEnabledCallback callback) override {
@@ -86,30 +78,12 @@
   return ui::ResourceBundle::GetSharedInstance().IsGzipped(resource_id);
 }
 
-base::Optional<service_manager::Manifest>
-ShellWebClient::GetServiceManifestOverlay(base::StringPiece name) {
-  if (name == mojom::kBrowserServiceName) {
-    return service_manager::ManifestBuilder()
-        .RequireCapability("user_id", "user_id")
-        .PackageService(user_id::GetManifest())
-        .Build();
-  }
-
-  return base::nullopt;
-}
-
-void ShellWebClient::BindInterfaceRequestFromMainFrame(
+void ShellWebClient::BindInterfaceReceiverFromMainFrame(
     WebState* web_state,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle interface_pipe) {
-  if (!main_frame_interfaces_.get() &&
-      !main_frame_interfaces_parameterized_.get()) {
-    InitMainFrameInterfaces();
-  }
-
-  if (!main_frame_interfaces_parameterized_->TryBindInterface(
-          interface_name, &interface_pipe, web_state)) {
-    main_frame_interfaces_->TryBindInterface(interface_name, &interface_pipe);
+    mojo::GenericPendingReceiver receiver) {
+  if (auto web_usage_receiver = receiver.As<mojom::WebUsageController>()) {
+    mojo::MakeSelfOwnedReceiver(std::make_unique<WebUsageController>(web_state),
+                                std::move(web_usage_receiver));
   }
 }
 
@@ -144,12 +118,4 @@
                  completion:nil];
 }
 
-void ShellWebClient::InitMainFrameInterfaces() {
-  main_frame_interfaces_ = std::make_unique<service_manager::BinderRegistry>();
-  main_frame_interfaces_parameterized_ =
-      std::make_unique<service_manager::BinderRegistryWithArgs<WebState*>>();
-  main_frame_interfaces_parameterized_->AddInterface(
-      base::Bind(WebUsageController::Create));
-}
-
 }  // namespace web
diff --git a/ios/web/shell/test/BUILD.gn b/ios/web/shell/test/BUILD.gn
index 18567be..6bf2fcd 100644
--- a/ios/web/shell/test/BUILD.gn
+++ b/ios/web/shell/test/BUILD.gn
@@ -21,7 +21,6 @@
   sources = [
     "context_menu_egtest.mm",
     "page_state_egtest.mm",
-    "service_manager_egtest.mm",
   ]
 
   deps = [
@@ -61,9 +60,6 @@
     "//ios/web/public/test:element_selector",
     "//ios/web/shell",
     "//ios/web/shell:shell_interfaces",
-    "//services/service_manager/public/cpp",
-    "//services/test/echo/public/mojom",
-    "//services/test/user_id/public/mojom",
     "//testing/gtest:gtest",
     "//url",
   ]
@@ -79,8 +75,6 @@
     "app/web_shell_test_util.mm",
     "app/web_view_interaction_test_util.h",
     "app/web_view_interaction_test_util.mm",
-    "earl_grey/service_manager_app_interface.h",
-    "earl_grey/service_manager_app_interface.mm",
     "earl_grey/shell_actions.h",
     "earl_grey/shell_actions.mm",
     "earl_grey/shell_actions_app_interface.h",
@@ -118,8 +112,6 @@
     "app/web_shell_test_util.mm",
     "app/web_view_interaction_test_util.h",
     "app/web_view_interaction_test_util.mm",
-    "earl_grey/service_manager_app_interface.h",
-    "earl_grey/service_manager_app_interface.mm",
     "earl_grey/shell_actions_app_interface.h",
     "earl_grey/shell_actions_app_interface.mm",
     "earl_grey/shell_earl_grey_app_interface.h",
@@ -140,9 +132,6 @@
     "//ios/web/public/test/http_server",
     "//ios/web/shell",
     "//ios/web/shell:shell_interfaces",
-    "//services/service_manager/public/cpp",
-    "//services/test/echo/public/mojom",
-    "//services/test/user_id/public/mojom",
     "//url",
   ]
 }
@@ -156,7 +145,6 @@
   testonly = true
 
   sources = [
-    "earl_grey/service_manager_app_interface.h",
     "earl_grey/shell_actions.h",
     "earl_grey/shell_actions.mm",
     "earl_grey/shell_actions_app_interface.h",
@@ -179,9 +167,6 @@
     "//ios/third_party/earl_grey2:test_lib",
     "//ios/web/public/test:element_selector",
     "//ios/web/shell:shell_interfaces",
-    "//services/service_manager/public/cpp",
-    "//services/test/echo/public/mojom",
-    "//services/test/user_id/public/mojom",
     "//url",
   ]
 }
@@ -197,7 +182,6 @@
   sources = [
     "context_menu_egtest.mm",
     "page_state_egtest.mm",
-    "service_manager_egtest.mm",
   ]
 
   deps = [
diff --git a/ios/web/shell/test/earl_grey/service_manager_app_interface.h b/ios/web/shell/test/earl_grey/service_manager_app_interface.h
deleted file mode 100644
index 783beec..0000000
--- a/ios/web/shell/test/earl_grey/service_manager_app_interface.h
+++ /dev/null
@@ -1,31 +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 IOS_WEB_SHELL_TEST_EARL_GREY_SERVICE_MANAGER_APP_INTERFACE_H_
-#define IOS_WEB_SHELL_TEST_EARL_GREY_SERVICE_MANAGER_APP_INTERFACE_H_
-
-#import <Foundation/Foundation.h>
-
-// Test methods that perform actions on Web Shell using Mojo Service API. These
-// methods may alter Web Shell's internal state programmatically, but in both
-// cases will properly synchronize the UI for Earl Grey tests.
-@interface ServiceManagerTestAppInterface : NSObject
-
-// Asynchronously logs instance group name via "user_id" Mojo service. Logs are
-// accessible via +logs method. eDO does not support asynchronous communication,
-// but clients can poll +logs to get instance group.
-+ (void)logInstanceGroup;
-
-// Returns logs from various Mojo methods.
-+ (NSArray*)logs;
-
-// Clears logs from various Mojo methods.
-+ (void)clearLogs;
-
-// Sets web usage flag for the current WebState using Mojo API.
-+ (void)setWebUsageEnabled:(BOOL)enabled;
-
-@end
-
-#endif  // IOS_WEB_SHELL_TEST_EARL_GREY_SERVICE_MANAGER_APP_INTERFACE_H_
diff --git a/ios/web/shell/test/earl_grey/service_manager_app_interface.mm b/ios/web/shell/test/earl_grey/service_manager_app_interface.mm
deleted file mode 100644
index c11b300..0000000
--- a/ios/web/shell/test/earl_grey/service_manager_app_interface.mm
+++ /dev/null
@@ -1,75 +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.
-
-#import "ios/web/shell/test/earl_grey/service_manager_app_interface.h"
-
-#import "base/bind.h"
-#import "base/bind_helpers.h"
-#import "base/strings/sys_string_conversions.h"
-#import "ios/testing/earl_grey/earl_grey_app.h"
-#include "ios/web/public/browser_state.h"
-#include "ios/web/public/service/service_manager_connection.h"
-#import "ios/web/public/web_state/web_state.h"
-#import "ios/web/shell/test/app/web_shell_test_util.h"
-#import "ios/web/shell/web_usage_controller.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/test/user_id/public/mojom/user_id.mojom.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-using web::shell_test_util::GetCurrentWebState;
-
-@implementation ServiceManagerTestAppInterface
-
-+ (void)logInstanceGroup {
-  // Connect to the user ID service once and bind a UserId instance.
-  static user_id::mojom::UserIdPtr userID;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    web::BrowserState::GetConnectorFor(GetCurrentWebState()->GetBrowserState())
-        ->BindInterface("user_id", mojo::MakeRequest(&userID));
-  });
-
-  // Call GetInstanceGroup(), making sure to keep this end of the connection
-  // alive until the callback is received.
-  userID->GetInstanceGroup(base::BindOnce(^(const base::Token& token) {
-    [[self mutableLogs] addObject:base::SysUTF8ToNSString(token.ToString())];
-  }));
-}
-
-+ (void)setWebUsageEnabled:(BOOL)enabled {
-  // Connect to a mojom::WebUsageController instance associated with
-  // current WebState.
-  static web::mojom::WebUsageControllerPtr webUsageController;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    GetCurrentWebState()->BindInterfaceRequestFromMainFrame(
-        mojo::MakeRequest(&webUsageController));
-  });
-
-  webUsageController->SetWebUsageEnabled(
-      enabled, base::BindOnce(base::DoNothing::Once()));
-}
-
-+ (NSArray*)logs {
-  return [[self mutableLogs] copy];
-}
-
-+ (void)clearLogs {
-  [[self mutableLogs] removeAllObjects];
-}
-#pragma mark - Private
-
-+ (NSMutableArray*)mutableLogs {
-  static NSMutableArray* logs = nil;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    logs = [[NSMutableArray alloc] init];
-  });
-  return logs;
-}
-
-@end
diff --git a/ios/web/shell/test/earl_grey/shell_earl_grey.h b/ios/web/shell/test/earl_grey/shell_earl_grey.h
index fa70097..0a7fba55 100644
--- a/ios/web/shell/test/earl_grey/shell_earl_grey.h
+++ b/ios/web/shell/test/earl_grey/shell_earl_grey.h
@@ -39,12 +39,6 @@
 // if the content does not show up within a timeout.
 - (void)waitForWebStateContainingText:(NSString*)text;
 
-// Returns YES if the current WebState's WebUsage is enabled.
-- (BOOL)webUsageEnabledForCurrentWebState WARN_UNUSED_RESULT;
-
-// Returns Mojo instance group name for current WebState.
-- (NSString*)instanceGroupForCurrentBrowserState WARN_UNUSED_RESULT;
-
 @end
 
 #endif  // IOS_WEB_SHELL_TEST_EARL_GREY_SHELL_EARL_GREY_H_
diff --git a/ios/web/shell/test/earl_grey/shell_earl_grey.mm b/ios/web/shell/test/earl_grey/shell_earl_grey.mm
index 3bb01c6..30034973 100644
--- a/ios/web/shell/test/earl_grey/shell_earl_grey.mm
+++ b/ios/web/shell/test/earl_grey/shell_earl_grey.mm
@@ -60,12 +60,4 @@
   EG_TEST_HELPER_ASSERT_TRUE(containsText, description);
 }
 
-- (BOOL)webUsageEnabledForCurrentWebState {
-  return [ShellEarlGreyAppInterface webUsageEnabledForCurrentWebState];
-}
-
-- (NSString*)instanceGroupForCurrentBrowserState {
-  return [ShellEarlGreyAppInterface instanceGroupForCurrentBrowserState];
-}
-
 @end
diff --git a/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.h b/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.h
index bacaf64..b8234a3 100644
--- a/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.h
+++ b/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.h
@@ -30,12 +30,6 @@
 // Returns YES if the current WebState contains the given |text|.
 + (BOOL)currentWebStateContainsText:(NSString*)text WARN_UNUSED_RESULT;
 
-// Returns YES if the current WebState's WebUsage is enabled.
-+ (BOOL)webUsageEnabledForCurrentWebState WARN_UNUSED_RESULT;
-
-// Returns Mojo instance group name for current WebState.
-+ (NSString*)instanceGroupForCurrentBrowserState WARN_UNUSED_RESULT;
-
 @end
 
 #endif  // IOS_WEB_SHELL_TEST_EARL_GREY_SHELL_EARL_GREY_APP_INTERFACE_H_
diff --git a/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.mm b/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.mm
index 37d21e3..b5c5425 100644
--- a/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.mm
+++ b/ios/web/shell/test/earl_grey/shell_earl_grey_app_interface.mm
@@ -48,14 +48,4 @@
                                             base::SysNSStringToUTF8(text));
 }
 
-+ (BOOL)webUsageEnabledForCurrentWebState {
-  return GetCurrentWebState()->IsWebUsageEnabled();
-}
-
-+ (NSString*)instanceGroupForCurrentBrowserState {
-  web::BrowserState* browserState = GetCurrentWebState()->GetBrowserState();
-  return base::SysUTF8ToNSString(
-      web::BrowserState::GetServiceInstanceGroupFor(browserState).ToString());
-}
-
 @end
diff --git a/ios/web/shell/test/service_manager_egtest.mm b/ios/web/shell/test/service_manager_egtest.mm
deleted file mode 100644
index 6d9f26a..0000000
--- a/ios/web/shell/test/service_manager_egtest.mm
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "base/test/ios/wait_util.h"
-#import "ios/testing/earl_grey/earl_grey_test.h"
-#import "ios/web/shell/test/earl_grey/service_manager_app_interface.h"
-#import "ios/web/shell/test/earl_grey/shell_earl_grey.h"
-#import "ios/web/shell/test/earl_grey/web_shell_test_case.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-#if defined(CHROME_EARL_GREY_2)
-GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(ServiceManagerTestAppInterface)
-#endif
-
-using base::test::ios::kWaitForActionTimeout;
-using base::test::ios::WaitUntilConditionOrTimeout;
-
-namespace {
-
-// Asynchronously logs instance group name via "user_id" Mojo service. Logs are
-// accessible via +logs method.
-void MojoLogInstanceGroup() {
-  [ServiceManagerTestAppInterface logInstanceGroup];
-}
-
-// Returns logs from |MojoLogInstanceGroup| and  methods.
-NSArray* MojoGetLogs() {
-  return [ServiceManagerTestAppInterface logs];
-}
-
-// Clears all Mojo logs.
-void MojoClearLogs() {
-  [ServiceManagerTestAppInterface clearLogs];
-}
-
-// Sets web usage flag for the current WebState using mojo API.
-void MojoSetWebUsageEnabled(bool enabled) {
-  [ServiceManagerTestAppInterface setWebUsageEnabled:enabled];
-}
-
-// Returns Mojo instance group name for current WebState.
-NSString* GetInstanceGroup() {
-  return [ShellEarlGrey instanceGroupForCurrentBrowserState];
-}
-
-}  // namespace
-
-// Service Manager test cases for the web shell.
-@interface ServiceManagerTestCase : WebShellTestCase
-@end
-
-@implementation ServiceManagerTestCase
-
-- (void)setUp {
-  [super setUp];
-  MojoClearLogs();
-}
-
-- (void)tearDown {
-  MojoClearLogs();
-  [super tearDown];
-}
-
-// Tests that it is possible to connect to a per-user embedded service that
-// was registered by web_shell.
-- (void)testConnectionToPerUserEmbeddedService {
-  MojoLogInstanceGroup();
-
-  // Wait for log to appear.
-  bool has_log = WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^{
-    return MojoGetLogs().count == 1;
-  });
-  GREYAssert(has_log, @"No log appeared");
-  GREYAssertEqualObjects(MojoGetLogs().firstObject, GetInstanceGroup(),
-                         @"Different group names from Mojo and WebState");
-}
-
-// Tests that it is possible to connect to a per-WebState interface that is
-// provided by web_shell.
-- (void)testConnectionToWebStateInterface {
-  // Ensure that web usage is enabled to start with.
-  GREYAssert([ShellEarlGrey webUsageEnabledForCurrentWebState],
-             @"WebState did not have expected initial state");
-
-  MojoSetWebUsageEnabled(false);
-
-  // Wait until the call altered |webState| as expected.
-  bool disabled = WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^{
-    return ![ShellEarlGrey webUsageEnabledForCurrentWebState];
-  });
-  GREYAssert(disabled, @"Failed to disable web usage");
-}
-
-@end
diff --git a/ios/web/web_client.mm b/ios/web/web_client.mm
index 5e01909..86e520e 100644
--- a/ios/web/web_client.mm
+++ b/ios/web/web_client.mm
@@ -80,11 +80,6 @@
   return @"";
 }
 
-base::Optional<service_manager::Manifest> WebClient::GetServiceManifestOverlay(
-    base::StringPiece name) {
-  return base::nullopt;
-}
-
 void WebClient::AllowCertificateError(
     WebState* web_state,
     int cert_error,
diff --git a/ios/web/web_state/ui/crw_wk_ui_handler.mm b/ios/web/web_state/ui/crw_wk_ui_handler.mm
index 89f657b1..ff102ea 100644
--- a/ios/web/web_state/ui/crw_wk_ui_handler.mm
+++ b/ios/web/web_state/ui/crw_wk_ui_handler.mm
@@ -7,7 +7,6 @@
 #include "base/strings/sys_string_conversions.h"
 #import "ios/web/navigation/wk_navigation_action_util.h"
 #import "ios/web/navigation/wk_navigation_util.h"
-#include "ios/web/public/service/web_state_interface_provider.h"
 #import "ios/web/public/ui/java_script_dialog_type.h"
 #import "ios/web/public/web_client.h"
 #import "ios/web/web_state/ui/crw_context_menu_controller.h"
@@ -50,12 +49,8 @@
 }
 
 - (web::MojoFacade*)mojoFacade {
-  if (!_mojoFacade) {
-    service_manager::mojom::InterfaceProvider* interfaceProvider =
-        self.webStateImpl->GetWebStateInterfaceProvider();
-    _mojoFacade =
-        std::make_unique<web::MojoFacade>(interfaceProvider, self.webStateImpl);
-  }
+  if (!_mojoFacade)
+    _mojoFacade = std::make_unique<web::MojoFacade>(self.webStateImpl);
   return _mojoFacade.get();
 }
 
diff --git a/ios/web/web_state/web_state.mm b/ios/web/web_state/web_state.mm
index 201e489..a411323 100644
--- a/ios/web/web_state/web_state.mm
+++ b/ios/web/web_state/web_state.mm
@@ -4,6 +4,8 @@
 
 #import "ios/web/public/web_state/web_state.h"
 
+#import "ios/web/public/web_client.h"
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -50,4 +52,29 @@
 
 WebState::OpenURLParams::~OpenURLParams() {}
 
+WebState::InterfaceBinder::InterfaceBinder(WebState* web_state)
+    : web_state_(web_state) {}
+
+WebState::InterfaceBinder::~InterfaceBinder() = default;
+
+void WebState::InterfaceBinder::AddInterface(base::StringPiece interface_name,
+                                             Callback callback) {
+  callbacks_.emplace(interface_name.as_string(), std::move(callback));
+}
+
+void WebState::InterfaceBinder::BindInterface(
+    mojo::GenericPendingReceiver receiver) {
+  DCHECK(receiver.is_valid());
+  auto it = callbacks_.find(*receiver.interface_name());
+  if (it != callbacks_.end())
+    it->second.Run(&receiver);
+
+  GetWebClient()->BindInterfaceReceiverFromMainFrame(web_state_,
+                                                     std::move(receiver));
+}
+
+WebState::InterfaceBinder* WebState::GetInterfaceBinderForMainFrame() {
+  return nullptr;
+}
+
 }  // namespace web
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index 9f16f0c..33621e4a 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -51,7 +51,6 @@
 class NavigationManager;
 class SessionCertificatePolicyCacheImpl;
 class WebInterstitialImpl;
-class WebStateInterfaceProvider;
 class WebUIIOS;
 
 // Implementation of WebState.
@@ -222,11 +221,8 @@
       const ScriptCommandCallback& callback,
       const std::string& command_prefix) override;
   id<CRWWebViewProxy> GetWebViewProxy() const override;
-  WebStateInterfaceProvider* GetWebStateInterfaceProvider() override;
   void DidChangeVisibleSecurityState() override;
-  void BindInterfaceRequestFromMainFrame(
-      const std::string& interface_name,
-      mojo::ScopedMessagePipeHandle interface_pipe) override;
+  InterfaceBinder* GetInterfaceBinderForMainFrame() override;
   bool HasOpener() const override;
   void SetHasOpener(bool has_opener) override;
   bool CanTakeSnapshot() const override;
@@ -384,9 +380,6 @@
   // WebState::CreateParams::created_with_opener_ for more details.
   bool created_with_opener_;
 
-  // Mojo interface registry for this WebState.
-  std::unique_ptr<WebStateInterfaceProvider> web_state_interface_provider_;
-
   // The most recently restored session history that has not yet committed in
   // the WKWebView. This is reset in OnNavigationItemCommitted().
   CRWSessionStorage* restored_session_storage_;
@@ -400,6 +393,10 @@
   // Whether a JavaScript dialog is currently being presented.
   bool running_javascript_dialog_ = false;
 
+  // The InterfaceBinder exposed by WebStateImpl. Used to handle Mojo interface
+  // requests from the main frame.
+  InterfaceBinder interface_binder_{this};
+
   base::WeakPtrFactory<WebStateImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(WebStateImpl);
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 4fbda36..8b03539 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -29,7 +29,6 @@
 #include "ios/web/public/favicon/favicon_url.h"
 #import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/navigation/web_state_policy_decider.h"
-#include "ios/web/public/service/web_state_interface_provider.h"
 #import "ios/web/public/session/crw_navigation_item_storage.h"
 #import "ios/web/public/session/crw_session_storage.h"
 #import "ios/web/public/session/serializable_user_data_manager.h"
@@ -527,27 +526,13 @@
 
 #pragma mark - RequestTracker management
 
-WebStateInterfaceProvider* WebStateImpl::GetWebStateInterfaceProvider() {
-  if (!web_state_interface_provider_) {
-    web_state_interface_provider_ =
-        std::make_unique<WebStateInterfaceProvider>();
-  }
-  return web_state_interface_provider_.get();
-}
-
 void WebStateImpl::DidChangeVisibleSecurityState() {
   for (auto& observer : observers_)
     observer.DidChangeVisibleSecurityState(this);
 }
 
-void WebStateImpl::BindInterfaceRequestFromMainFrame(
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle interface_pipe) {
-  if (!GetWebStateInterfaceProvider()->registry()->TryBindInterface(
-          interface_name, &interface_pipe)) {
-    GetWebClient()->BindInterfaceRequestFromMainFrame(
-        this, interface_name, std::move(interface_pipe));
-  }
+WebState::InterfaceBinder* WebStateImpl::GetInterfaceBinderForMainFrame() {
+  return &interface_binder_;
 }
 
 #pragma mark - WebFrame management
diff --git a/ios/web/webui/BUILD.gn b/ios/web/webui/BUILD.gn
index 3ae7ea0..14aa5ef 100644
--- a/ios/web/webui/BUILD.gn
+++ b/ios/web/webui/BUILD.gn
@@ -15,7 +15,6 @@
     "//ios/web/web_state:web_state_impl_header",
     "//mojo/public/cpp/system",
     "//net",
-    "//services/service_manager/public/mojom",
     "//ui/base",
     "//ui/resources",
     "//url",
diff --git a/ios/web/webui/mojo_facade.h b/ios/web/webui/mojo_facade.h
index b6631b9..7d138612 100644
--- a/ios/web/webui/mojo_facade.h
+++ b/ios/web/webui/mojo_facade.h
@@ -9,15 +9,11 @@
 #include <memory>
 #include <string>
 
+#include "base/callback.h"
 #include "base/values.h"
+#include "mojo/public/cpp/system/message_pipe.h"
 #include "mojo/public/cpp/system/simple_watcher.h"
 
-namespace service_manager {
-namespace mojom {
-class InterfaceProvider;
-}  // mojom
-}  // service_manager
-
 namespace web {
 
 class WebState;
@@ -27,10 +23,9 @@
 // destroyed on UI thread.
 class MojoFacade {
  public:
-  // Constructs MojoFacade. The calling code must retain the ownership of
-  // |interface_provider| and |web_state|, both can not be null.
-  MojoFacade(service_manager::mojom::InterfaceProvider* interface_provider,
-             WebState* web_state);
+  // Constructs MojoFacade. The calling code must retain ownership of
+  // |web_state|, which cannot be null.
+  explicit MojoFacade(WebState* web_state);
   ~MojoFacade();
 
   // Handles Mojo message received from WebUI page. Returns a valid JSON string
@@ -112,8 +107,6 @@
   // returned from "MojoHandle.watch").
   void HandleMojoWatcherCancel(base::Value args);
 
-  // Provides interfaces.
-  service_manager::mojom::InterfaceProvider* interface_provider_;
   // Runs JavaScript on WebUI page.
   WebState* web_state_ = nil;
   //  __weak id<CRWJSInjectionEvaluator> script_evaluator_ = nil;
diff --git a/ios/web/webui/mojo_facade.mm b/ios/web/webui/mojo_facade.mm
index 4146e18d..e359b0d 100644
--- a/ios/web/webui/mojo_facade.mm
+++ b/ios/web/webui/mojo_facade.mm
@@ -21,8 +21,8 @@
 #include "base/values.h"
 #include "ios/web/public/thread/web_thread.h"
 #include "ios/web/public/web_state/web_state.h"
+#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
 #include "mojo/public/cpp/system/core.h"
-#include "services/service_manager/public/mojom/interface_provider.mojom.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -30,12 +30,8 @@
 
 namespace web {
 
-MojoFacade::MojoFacade(
-    service_manager::mojom::InterfaceProvider* interface_provider,
-    WebState* web_state)
-    : interface_provider_(interface_provider), web_state_(web_state) {
+MojoFacade::MojoFacade(WebState* web_state) : web_state_(web_state) {
   DCHECK_CURRENTLY_ON(WebThread::UI);
-  DCHECK(interface_provider_);
   DCHECK(web_state_);
 }
 
@@ -106,10 +102,8 @@
 
   mojo::ScopedMessagePipeHandle handle(
       static_cast<mojo::MessagePipeHandle>(*raw_handle));
-
-  // By design interface_provider.getInterface either succeeds or crashes, so
-  // check if interface name is a valid string is intentionally omitted.
-  interface_provider_->GetInterface(*interface_name, std::move(handle));
+  web_state_->GetInterfaceBinderForMainFrame()->BindInterface(
+      mojo::GenericPendingReceiver(*interface_name, std::move(handle)));
 }
 
 void MojoFacade::HandleMojoHandleClose(base::Value args) {
diff --git a/ios/web/webui/mojo_facade_unittest.mm b/ios/web/webui/mojo_facade_unittest.mm
index f7a02719..f398752 100644
--- a/ios/web/webui/mojo_facade_unittest.mm
+++ b/ios/web/webui/mojo_facade_unittest.mm
@@ -11,7 +11,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
-#include "ios/web/public/service/web_state_interface_provider.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/web_test.h"
 #include "ios/web/test/mojo_test.mojom.h"
@@ -69,9 +68,14 @@
     EXPECT_TRUE(facade_->HandleMojoMessage(GetJson(cancel_watch)).empty());
   }
 
+  InterfaceBinder* GetInterfaceBinderForMainFrame() override {
+    return &interface_binder_;
+  }
+
  private:
   int watch_id_;
   MojoFacade* facade_;  // weak
+  InterfaceBinder interface_binder_{this};
 };
 
 }  // namespace
@@ -80,11 +84,7 @@
 class MojoFacadeTest : public WebTest {
  protected:
   MojoFacadeTest() {
-    interface_provider_ = std::make_unique<WebStateInterfaceProvider>();
-    interface_provider_->registry()->AddInterface(base::Bind(
-        &MojoFacadeTest::BindTestUIHandlerMojoRequest, base::Unretained(this)));
-    facade_ =
-        std::make_unique<MojoFacade>(interface_provider_.get(), &web_state_);
+    facade_ = std::make_unique<MojoFacade>(&web_state_);
     web_state_.SetFacade(facade_.get());
   }
 
@@ -120,9 +120,6 @@
   }
 
  private:
-  void BindTestUIHandlerMojoRequest(TestUIHandlerMojoRequest request) {}
-
-  std::unique_ptr<WebStateInterfaceProvider> interface_provider_;
   FakeWebState web_state_;
   std::unique_ptr<MojoFacade> facade_;
 };
diff --git a/ios/web/webui/web_ui_mojo_inttest.mm b/ios/web/webui/web_ui_mojo_inttest.mm
index c09d77b3..3ae8791 100644
--- a/ios/web/webui/web_ui_mojo_inttest.mm
+++ b/ios/web/webui/web_ui_mojo_inttest.mm
@@ -10,7 +10,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "ios/web/grit/ios_web_resources.h"
 #import "ios/web/public/navigation/navigation_manager.h"
-#include "ios/web/public/service/web_state_interface_provider.h"
 #import "ios/web/public/test/navigation_test_util.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "ios/web/public/webui/web_ui_ios_controller.h"
@@ -20,7 +19,7 @@
 #include "ios/web/test/mojo_test.mojom.h"
 #include "ios/web/test/test_url_constants.h"
 #import "ios/web/test/web_int_test.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "url/gurl.h"
 #include "url/scheme_host_port.h"
 
@@ -76,12 +75,12 @@
     }
   }
 
-  void BindTestUIHandlerMojoRequest(TestUIHandlerMojoRequest request) {
-    bindings_.AddBinding(this, std::move(request));
+  void BindTestHandler(mojo::PendingReceiver<TestUIHandlerMojo> receiver) {
+    receivers_.Add(this, std::move(receiver));
   }
 
  private:
-  mojo::BindingSet<TestUIHandlerMojo> bindings_;
+  mojo::ReceiverSet<TestUIHandlerMojo> receivers_;
   TestPagePtr page_ = nullptr;
   // |true| if "syn" has been received.
   bool syn_received_ = false;
@@ -107,10 +106,12 @@
     web::WebState* web_state = web_ui->GetWebState();
     web::WebUIIOSDataSource::Add(web_state->GetBrowserState(), source);
 
-    web_state->GetWebStateInterfaceProvider()->registry()->AddInterface(
-        base::Bind(&TestUIHandler::BindTestUIHandlerMojoRequest,
-                   base::Unretained(ui_handler)));
+    web_state->GetInterfaceBinderForMainFrame()->AddInterface(
+        base::BindRepeating(&TestUIHandler::BindTestHandler,
+                            base::Unretained(ui_handler)));
   }
+
+  ~TestUI() override = default;
 };
 
 // Factory that creates TestUI controller.
diff --git a/ios/web_view/internal/web_view_browser_state.mm b/ios/web_view/internal/web_view_browser_state.mm
index 67baf03..28cc0343 100644
--- a/ios/web_view/internal/web_view_browser_state.mm
+++ b/ios/web_view/internal/web_view_browser_state.mm
@@ -89,8 +89,6 @@
       GetStatePath(), ApplicationContext::GetInstance()->GetNetLog(),
       base::CreateSingleThreadTaskRunnerWithTraits({web::WebThread::IO}));
 
-  BrowserState::Initialize(this, path_);
-
   // Initialize prefs.
   scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry =
       new user_prefs::PrefRegistrySyncable;
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn
index fbc1b52..f6eb17e 100644
--- a/media/capture/BUILD.gn
+++ b/media/capture/BUILD.gn
@@ -290,7 +290,7 @@
       "//components/chromeos_camera:mojo_mjpeg_decode_accelerator",
       "//components/chromeos_camera/common",
       "//gpu/ipc/common:common",
-      "//media/capture/video/chromeos/mojo:cros_camera",
+      "//media/capture/video/chromeos/mojom:cros_camera",
       "//third_party/libsync",
     ]
   }
@@ -433,7 +433,7 @@
       ":chromeos_test_utils",
       "//build/config/linux/libdrm",
       "//chromeos/dbus/power",
-      "//media/capture/video/chromeos/mojo:cros_camera",
+      "//media/capture/video/chromeos/mojom:cros_camera",
       "//media/capture/video/chromeos/public",
       "//mojo/core/embedder",
       "//third_party/libsync",
diff --git a/media/capture/mojom/BUILD.gn b/media/capture/mojom/BUILD.gn
index 9e1c763..ebadbd0 100644
--- a/media/capture/mojom/BUILD.gn
+++ b/media/capture/mojom/BUILD.gn
@@ -16,6 +16,10 @@
     "//ui/gfx/geometry/mojom",
     "//ui/gfx/mojom",
   ]
+
+  export_class_attribute_blink = "BLINK_PLATFORM_EXPORT"
+  export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1"
+  export_header_blink = "third_party/blink/public/platform/web_common.h"
 }
 
 mojom("image_capture") {
diff --git a/media/capture/video/chromeos/camera_3a_controller.h b/media/capture/video/chromeos/camera_3a_controller.h
index 681638aa..e7aad96 100644
--- a/media/capture/video/chromeos/camera_3a_controller.h
+++ b/media/capture/video/chromeos/camera_3a_controller.h
@@ -9,7 +9,7 @@
 
 #include "base/cancelable_callback.h"
 #include "media/base/media_export.h"
-#include "media/capture/video/chromeos/mojo/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
 #include "media/capture/video/chromeos/request_manager.h"
 
 namespace media {
diff --git a/media/capture/video/chromeos/camera_buffer_factory.h b/media/capture/video/chromeos/camera_buffer_factory.h
index f17893b..ded3d31 100644
--- a/media/capture/video/chromeos/camera_buffer_factory.h
+++ b/media/capture/video/chromeos/camera_buffer_factory.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <unordered_map>
 
-#include "media/capture/video/chromeos/mojo/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
 #include "media/capture/video/chromeos/pixel_format_utils.h"
 #include "media/capture/video_capture_types.h"
 #include "ui/gfx/buffer_types.h"
diff --git a/media/capture/video/chromeos/camera_device_delegate.h b/media/capture/video/chromeos/camera_device_delegate.h
index b1cca24..ee9a891 100644
--- a/media/capture/video/chromeos/camera_device_delegate.h
+++ b/media/capture/video/chromeos/camera_device_delegate.h
@@ -11,8 +11,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
-#include "media/capture/video/chromeos/mojo/camera3.mojom.h"
-#include "media/capture/video/chromeos/mojo/camera_common.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
 #include "media/capture/video/video_capture_device.h"
 #include "media/capture/video_capture_types.h"
 #include "ui/gfx/geometry/size.h"
diff --git a/media/capture/video/chromeos/camera_hal_delegate.h b/media/capture/video/chromeos/camera_hal_delegate.h
index f8034c7..3f02f7f 100644
--- a/media/capture/video/chromeos/camera_hal_delegate.h
+++ b/media/capture/video/chromeos/camera_hal_delegate.h
@@ -15,8 +15,8 @@
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
-#include "media/capture/video/chromeos/mojo/camera3.mojom.h"
-#include "media/capture/video/chromeos/mojo/camera_common.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
 #include "media/capture/video/chromeos/vendor_tag_ops_delegate.h"
 #include "media/capture/video/video_capture_device_factory.h"
 #include "media/capture/video_capture_types.h"
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
index bb42d28c..ba1634c 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -21,7 +21,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/trace_event/trace_event.h"
-#include "media/capture/video/chromeos/mojo/camera_common.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
 #include "mojo/public/cpp/platform/named_platform_channel.h"
 #include "mojo/public/cpp/platform/platform_channel.h"
 #include "mojo/public/cpp/platform/socket_utils_posix.h"
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
index 828a9d3..07d57e20 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
@@ -15,7 +15,7 @@
 #include "components/chromeos_camera/common/jpeg_encode_accelerator.mojom.h"
 #include "components/chromeos_camera/common/mjpeg_decode_accelerator.mojom.h"
 #include "media/capture/capture_export.h"
-#include "media/capture/video/chromeos/mojo/cros_camera_service.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h"
 #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
 #include "media/capture/video/video_capture_device_factory.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
index e558eb4..e3ec27c 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
@@ -11,8 +11,8 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/scoped_task_environment.h"
-#include "media/capture/video/chromeos/mojo/camera_common.mojom.h"
-#include "media/capture/video/chromeos/mojo/cros_camera_service.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/media/capture/video/chromeos/camera_metadata_utils.h b/media/capture/video/chromeos/camera_metadata_utils.h
index fcf7b87..43fe76d 100644
--- a/media/capture/video/chromeos/camera_metadata_utils.h
+++ b/media/capture/video/chromeos/camera_metadata_utils.h
@@ -6,7 +6,7 @@
 #define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_METADATA_UTILS_H_
 
 #include "media/capture/capture_export.h"
-#include "media/capture/video/chromeos/mojo/camera_metadata.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_metadata.mojom.h"
 
 namespace media {
 
diff --git a/media/capture/video/chromeos/cros_image_capture_impl.h b/media/capture/video/chromeos/cros_image_capture_impl.h
index c122c2e..6c93866dd 100644
--- a/media/capture/video/chromeos/cros_image_capture_impl.h
+++ b/media/capture/video/chromeos/cros_image_capture_impl.h
@@ -7,8 +7,8 @@
 
 #include <string>
 
-#include "media/capture/video/chromeos/mojo/camera_common.mojom.h"
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #include "media/capture/video/chromeos/reprocess_manager.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 
diff --git a/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc b/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc
index ef82d69..0f13455 100644
--- a/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc
+++ b/media/capture/video/chromeos/local_gpu_memory_buffer_manager.cc
@@ -10,6 +10,8 @@
 #include <stdint.h>
 #include <xf86drm.h>
 
+#include <vector>
+
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/trace_event/memory_allocator_dump_guid.h"
@@ -74,6 +76,19 @@
   }
 }
 
+uint32_t GetGbmUsage(gfx::BufferUsage usage) {
+  switch (usage) {
+    case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE:
+    case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE:
+      return GBM_BO_USE_LINEAR | GBM_BO_USE_CAMERA_READ |
+             GBM_BO_USE_CAMERA_WRITE;
+    case gfx::BufferUsage::SCANOUT_CPU_READ_WRITE:
+      return GBM_BO_USE_LINEAR;
+    default:
+      return 0;
+  }
+}
+
 class GpuMemoryBufferImplGbm : public gfx::GpuMemoryBuffer {
  public:
   GpuMemoryBufferImplGbm(gfx::BufferFormat format, gbm_bo* buffer_object)
@@ -223,35 +238,33 @@
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
     gpu::SurfaceHandle surface_handle) {
-  if (usage != gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE &&
-      usage != gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE) {
-    LOG(ERROR) << "Unsupported usage " << gfx::BufferUsageToString(usage);
-    return std::unique_ptr<gfx::GpuMemoryBuffer>();
-  }
   if (!gbm_device_) {
     LOG(ERROR) << "Invalid GBM device";
-    return std::unique_ptr<gfx::GpuMemoryBuffer>();
+    return nullptr;
   }
 
-  uint32_t drm_format = GetDrmFormat(format);
-  uint32_t camera_gbm_usage =
-      GBM_BO_USE_LINEAR | GBM_BO_USE_CAMERA_READ | GBM_BO_USE_CAMERA_WRITE;
+  const uint32_t drm_format = GetDrmFormat(format);
   if (!drm_format) {
     LOG(ERROR) << "Unable to convert gfx::BufferFormat "
                << static_cast<int>(format) << " to DRM format";
-    return std::unique_ptr<gfx::GpuMemoryBuffer>();
+    return nullptr;
   }
 
-  if (!gbm_device_is_format_supported(gbm_device_, drm_format,
-                                      camera_gbm_usage)) {
-    return std::unique_ptr<gfx::GpuMemoryBuffer>();
+  const uint32_t gbm_usage = GetGbmUsage(usage);
+  if (gbm_usage == 0) {
+    LOG(ERROR) << "Unsupported usage " << gfx::BufferUsageToString(usage);
+    return nullptr;
   }
 
-  gbm_bo* buffer_object = gbm_bo_create(
-      gbm_device_, size.width(), size.height(), drm_format, camera_gbm_usage);
+  if (!gbm_device_is_format_supported(gbm_device_, drm_format, gbm_usage)) {
+    return nullptr;
+  }
+
+  gbm_bo* buffer_object = gbm_bo_create(gbm_device_, size.width(),
+                                        size.height(), drm_format, gbm_usage);
   if (!buffer_object) {
     LOG(ERROR) << "Failed to create GBM buffer object";
-    return std::unique_ptr<gfx::GpuMemoryBuffer>();
+    return nullptr;
   }
 
   return std::make_unique<GpuMemoryBufferImplGbm>(format, buffer_object);
@@ -305,4 +318,16 @@
   return std::make_unique<GpuMemoryBufferImplGbm>(format, buffer_object);
 }
 
+bool LocalGpuMemoryBufferManager::IsFormatAndUsageSupported(
+    gfx::BufferFormat format,
+    gfx::BufferUsage usage) {
+  const uint32_t drm_format = GetDrmFormat(format);
+  if (!drm_format)
+    return false;
+  const uint32_t gbm_usage = GetGbmUsage(usage);
+  if (gbm_usage == 0)
+    return false;
+  return gbm_device_is_format_supported(gbm_device_, drm_format, gbm_usage);
+}
+
 }  // namespace media
diff --git a/media/capture/video/chromeos/local_gpu_memory_buffer_manager.h b/media/capture/video/chromeos/local_gpu_memory_buffer_manager.h
index b7a1552..93cf0f13 100644
--- a/media/capture/video/chromeos/local_gpu_memory_buffer_manager.h
+++ b/media/capture/video/chromeos/local_gpu_memory_buffer_manager.h
@@ -51,6 +51,11 @@
       const gfx::Size& size,
       gfx::BufferFormat format);
 
+  // Returns true if the combination of |format| and |usage| is supported by
+  // CreateGpuMemoryBuffer().
+  bool IsFormatAndUsageSupported(gfx::BufferFormat format,
+                                 gfx::BufferUsage usage);
+
  private:
   gbm_device* gbm_device_;
 
diff --git a/media/capture/video/chromeos/mock_camera_module.h b/media/capture/video/chromeos/mock_camera_module.h
index f10d2b7..d8f3d47 100644
--- a/media/capture/video/chromeos/mock_camera_module.h
+++ b/media/capture/video/chromeos/mock_camera_module.h
@@ -9,8 +9,8 @@
 #include <stdint.h>
 
 #include "base/threading/thread.h"
-#include "media/capture/video/chromeos/mojo/camera3.mojom.h"
-#include "media/capture/video/chromeos/mojo/camera_common.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
diff --git a/media/capture/video/chromeos/mock_vendor_tag_ops.h b/media/capture/video/chromeos/mock_vendor_tag_ops.h
index b39a9384..1c45c3272a 100644
--- a/media/capture/video/chromeos/mock_vendor_tag_ops.h
+++ b/media/capture/video/chromeos/mock_vendor_tag_ops.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/threading/thread.h"
-#include "media/capture/video/chromeos/mojo/camera_common.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
diff --git a/media/capture/video/chromeos/mojo/BUILD.gn b/media/capture/video/chromeos/mojom/BUILD.gn
similarity index 100%
rename from media/capture/video/chromeos/mojo/BUILD.gn
rename to media/capture/video/chromeos/mojom/BUILD.gn
diff --git a/media/capture/video/chromeos/mojo/OWNERS b/media/capture/video/chromeos/mojom/OWNERS
similarity index 100%
rename from media/capture/video/chromeos/mojo/OWNERS
rename to media/capture/video/chromeos/mojom/OWNERS
diff --git a/media/capture/video/chromeos/mojo/camera3.mojom b/media/capture/video/chromeos/mojom/camera3.mojom
similarity index 99%
rename from media/capture/video/chromeos/mojo/camera3.mojom
rename to media/capture/video/chromeos/mojom/camera3.mojom
index 3d103348..5092b16a 100644
--- a/media/capture/video/chromeos/mojo/camera3.mojom
+++ b/media/capture/video/chromeos/mojom/camera3.mojom
@@ -6,7 +6,7 @@
 
 module cros.mojom;
 
-import "media/capture/video/chromeos/mojo/camera_metadata.mojom";
+import "media/capture/video/chromeos/mojom/camera_metadata.mojom";
 
 // These usages flags are defined in gralloc.h. They determine the nature of
 // the buffers allocated by gralloc. Read more on:
diff --git a/media/capture/video/chromeos/mojo/camera_common.mojom b/media/capture/video/chromeos/mojom/camera_common.mojom
similarity index 96%
rename from media/capture/video/chromeos/mojo/camera_common.mojom
rename to media/capture/video/chromeos/mojom/camera_common.mojom
index 65689d6..fadf3937 100644
--- a/media/capture/video/chromeos/mojo/camera_common.mojom
+++ b/media/capture/video/chromeos/mojom/camera_common.mojom
@@ -6,8 +6,8 @@
 
 module cros.mojom;
 
-import "media/capture/video/chromeos/mojo/camera3.mojom";
-import "media/capture/video/chromeos/mojo/camera_metadata.mojom";
+import "media/capture/video/chromeos/mojom/camera3.mojom";
+import "media/capture/video/chromeos/mojom/camera_metadata.mojom";
 
 enum CameraFacing {
   CAMERA_FACING_BACK = 0,
diff --git a/media/capture/video/chromeos/mojo/camera_metadata.mojom b/media/capture/video/chromeos/mojom/camera_metadata.mojom
similarity index 93%
rename from media/capture/video/chromeos/mojo/camera_metadata.mojom
rename to media/capture/video/chromeos/mojom/camera_metadata.mojom
index 9769760..269dcc9d 100644
--- a/media/capture/video/chromeos/mojo/camera_metadata.mojom
+++ b/media/capture/video/chromeos/mojom/camera_metadata.mojom
@@ -4,7 +4,7 @@
 
 module cros.mojom;
 
-import "media/capture/video/chromeos/mojo/camera_metadata_tags.mojom";
+import "media/capture/video/chromeos/mojom/camera_metadata_tags.mojom";
 
 enum EntryType {
   TYPE_BYTE = 0,
diff --git a/media/capture/video/chromeos/mojo/camera_metadata_tags.mojom b/media/capture/video/chromeos/mojom/camera_metadata_tags.mojom
similarity index 100%
rename from media/capture/video/chromeos/mojo/camera_metadata_tags.mojom
rename to media/capture/video/chromeos/mojom/camera_metadata_tags.mojom
diff --git a/media/capture/video/chromeos/mojo/cros_camera_service.mojom b/media/capture/video/chromeos/mojom/cros_camera_service.mojom
similarity index 97%
rename from media/capture/video/chromeos/mojo/cros_camera_service.mojom
rename to media/capture/video/chromeos/mojom/cros_camera_service.mojom
index 1bcd8c9..be4da55 100644
--- a/media/capture/video/chromeos/mojo/cros_camera_service.mojom
+++ b/media/capture/video/chromeos/mojom/cros_camera_service.mojom
@@ -8,7 +8,7 @@
 
 import "components/chromeos_camera/common/jpeg_encode_accelerator.mojom";
 import "components/chromeos_camera/common/mjpeg_decode_accelerator.mojom";
-import "media/capture/video/chromeos/mojo/camera_common.mojom";
+import "media/capture/video/chromeos/mojom/camera_common.mojom";
 
 // The CrOS camera HAL v3 Mojo dispatcher.  The dispatcher acts as a proxy and
 // waits for the server and the clients to register.  There can only be one
diff --git a/media/capture/video/chromeos/mojo/cros_image_capture.mojom b/media/capture/video/chromeos/mojom/cros_image_capture.mojom
similarity index 97%
rename from media/capture/video/chromeos/mojo/cros_image_capture.mojom
rename to media/capture/video/chromeos/mojom/cros_image_capture.mojom
index 3679647..77043457 100644
--- a/media/capture/video/chromeos/mojo/cros_image_capture.mojom
+++ b/media/capture/video/chromeos/mojom/cros_image_capture.mojom
@@ -5,7 +5,7 @@
 module cros.mojom;
 
 import "media/capture/mojom/image_capture.mojom";
-import "media/capture/video/chromeos/mojo/camera_common.mojom";
+import "media/capture/video/chromeos/mojom/camera_common.mojom";
 
 // Effect that recognized by Chrome OS.
 enum Effect {
diff --git a/media/capture/video/chromeos/pixel_format_utils.h b/media/capture/video/chromeos/pixel_format_utils.h
index 0a40d2a..be43491 100644
--- a/media/capture/video/chromeos/pixel_format_utils.h
+++ b/media/capture/video/chromeos/pixel_format_utils.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/optional.h"
-#include "media/capture/video/chromeos/mojo/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
 #include "media/capture/video_capture_types.h"
 #include "ui/gfx/buffer_types.h"
 
diff --git a/media/capture/video/chromeos/renderer_facing_cros_image_capture.cc b/media/capture/video/chromeos/renderer_facing_cros_image_capture.cc
index db146bf..b6a3a94 100644
--- a/media/capture/video/chromeos/renderer_facing_cros_image_capture.cc
+++ b/media/capture/video/chromeos/renderer_facing_cros_image_capture.cc
@@ -14,7 +14,7 @@
 #include "base/task/post_task.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/capture/mojom/image_capture.mojom.h"
-#include "media/capture/video/chromeos/mojo/camera_common.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
 
 namespace media {
 
diff --git a/media/capture/video/chromeos/renderer_facing_cros_image_capture.h b/media/capture/video/chromeos/renderer_facing_cros_image_capture.h
index 21f8e10..60cf8a95 100644
--- a/media/capture/video/chromeos/renderer_facing_cros_image_capture.h
+++ b/media/capture/video/chromeos/renderer_facing_cros_image_capture.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "media/capture/capture_export.h"
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 
 namespace media {
diff --git a/media/capture/video/chromeos/reprocess_manager.h b/media/capture/video/chromeos/reprocess_manager.h
index ac2add5..831ee69 100644
--- a/media/capture/video/chromeos/reprocess_manager.h
+++ b/media/capture/video/chromeos/reprocess_manager.h
@@ -15,9 +15,9 @@
 #include "base/task/post_task.h"
 #include "media/capture/capture_export.h"
 #include "media/capture/mojom/image_capture.mojom.h"
-#include "media/capture/video/chromeos/mojo/camera3.mojom.h"
-#include "media/capture/video/chromeos/mojo/camera_common.mojom.h"
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/range/range.h"
diff --git a/media/capture/video/chromeos/request_builder.h b/media/capture/video/chromeos/request_builder.h
index 2127adba..a23ef6a 100644
--- a/media/capture/video/chromeos/request_builder.h
+++ b/media/capture/video/chromeos/request_builder.h
@@ -11,7 +11,7 @@
 
 #include "base/optional.h"
 #include "media/capture/video/chromeos/camera_device_delegate.h"
-#include "media/capture/video/chromeos/mojo/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
 #include "media/capture/video_capture_types.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
diff --git a/media/capture/video/chromeos/request_manager.cc b/media/capture/video/chromeos/request_manager.cc
index 26efe679..1f05655 100644
--- a/media/capture/video/chromeos/request_manager.cc
+++ b/media/capture/video/chromeos/request_manager.cc
@@ -20,7 +20,7 @@
 #include "media/capture/video/chromeos/camera_buffer_factory.h"
 #include "media/capture/video/chromeos/camera_device_context.h"
 #include "media/capture/video/chromeos/camera_metadata_utils.h"
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #include "mojo/public/cpp/platform/platform_handle.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 
diff --git a/media/capture/video/chromeos/request_manager.h b/media/capture/video/chromeos/request_manager.h
index 99651fe..b632df7 100644
--- a/media/capture/video/chromeos/request_manager.h
+++ b/media/capture/video/chromeos/request_manager.h
@@ -16,7 +16,7 @@
 #include "base/optional.h"
 #include "media/capture/mojom/image_capture.mojom.h"
 #include "media/capture/video/chromeos/camera_device_delegate.h"
-#include "media/capture/video/chromeos/mojo/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
 #include "media/capture/video/chromeos/reprocess_manager.h"
 #include "media/capture/video/chromeos/request_builder.h"
 #include "media/capture/video/chromeos/stream_buffer_manager.h"
diff --git a/media/capture/video/chromeos/stream_buffer_manager.h b/media/capture/video/chromeos/stream_buffer_manager.h
index 5aea056..51616747 100644
--- a/media/capture/video/chromeos/stream_buffer_manager.h
+++ b/media/capture/video/chromeos/stream_buffer_manager.h
@@ -19,7 +19,7 @@
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
 #include "media/capture/video/chromeos/camera_device_delegate.h"
-#include "media/capture/video/chromeos/mojo/camera3.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera3.mojom.h"
 #include "media/capture/video_capture_types.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
diff --git a/media/capture/video/chromeos/vendor_tag_ops_delegate.h b/media/capture/video/chromeos/vendor_tag_ops_delegate.h
index c343b6c6..3920435 100644
--- a/media/capture/video/chromeos/vendor_tag_ops_delegate.h
+++ b/media/capture/video/chromeos/vendor_tag_ops_delegate.h
@@ -9,7 +9,7 @@
 #include <string>
 #include <vector>
 
-#include "media/capture/video/chromeos/mojo/camera_common.mojom.h"
+#include "media/capture/video/chromeos/mojom/camera_common.mojom.h"
 
 namespace media {
 
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.h b/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
index cee840f..d4766db 100644
--- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
+++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
@@ -11,7 +11,7 @@
 #include "base/single_thread_task_runner.h"
 #include "components/chromeos_camera/common/mjpeg_decode_accelerator.mojom.h"
 #include "media/capture/video/chromeos/camera_hal_delegate.h"
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #include "media/capture/video/video_capture_device_factory.h"
 
 namespace media {
diff --git a/media/capture/video/video_capture_system.h b/media/capture/video/video_capture_system.h
index c4cdaaf..90078fbe 100644
--- a/media/capture/video/video_capture_system.h
+++ b/media/capture/video/video_capture_system.h
@@ -9,7 +9,7 @@
 #include "media/capture/video/video_capture_device_info.h"
 
 #if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #endif  // defined(OS_CHROMEOS)
 
 namespace media {
diff --git a/media/capture/video/video_capture_system_impl.h b/media/capture/video/video_capture_system_impl.h
index 0cbd5c8..198b6db 100644
--- a/media/capture/video/video_capture_system_impl.h
+++ b/media/capture/video/video_capture_system_impl.h
@@ -8,7 +8,7 @@
 #include "media/capture/video/video_capture_system.h"
 
 #if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #endif  // defined(OS_CHROMEOS)
 
 namespace media {
diff --git a/media/filters/fuchsia/OWNERS b/media/filters/fuchsia/OWNERS
index e7034ea..c1b5845 100644
--- a/media/filters/fuchsia/OWNERS
+++ b/media/filters/fuchsia/OWNERS
@@ -1 +1,4 @@
 file://build/fuchsia/OWNERS
+# COMPONENT: Fuchsia
+# OS: Fuchsia
+# TEAM: cr-fuchsia@chromium.org
diff --git a/media/gpu/v4l2/BUILD.gn b/media/gpu/v4l2/BUILD.gn
index 3bb250a..54187ba 100644
--- a/media/gpu/v4l2/BUILD.gn
+++ b/media/gpu/v4l2/BUILD.gn
@@ -96,6 +96,7 @@
     deps += [
       "//components/chromeos_camera:jpeg_encode_accelerator",
       "//components/chromeos_camera:mjpeg_decode_accelerator",
+      "//media/gpu:video_frame_mapper_common",
       "//media/parsers",
     ]
   }
diff --git a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc
index 6f9e7c79..9422499f 100644
--- a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.cc
@@ -9,14 +9,24 @@
 #include <string.h>
 #include <sys/mman.h>
 
+#include <array>
 #include <memory>
+#include <utility>
 
 #include "base/big_endian.h"
 #include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_types.h"
+#include "media/gpu/format_utils.h"
+#include "media/gpu/linux/platform_video_frame_utils.h"
 #include "media/gpu/macros.h"
+#include "media/gpu/video_frame_mapper.h"
+#include "media/gpu/video_frame_mapper_factory.h"
 #include "media/parsers/jpeg_parser.h"
 #include "third_party/libyuv/include/libyuv.h"
 
@@ -256,24 +266,12 @@
             << ", size=" << bitstream_buffer.size();
   DCHECK(io_task_runner_->BelongsToCurrentThread());
 
-  if (video_frame->HasDmaBufs()) {
-    VLOGF(1) << "Decoding to dmabuf-backed video frame is not supported, id: "
-             << bitstream_buffer.id();
-    PostNotifyError(bitstream_buffer.id(), INVALID_ARGUMENT);
-    return;
-  }
-
   if (bitstream_buffer.id() < 0) {
     VLOGF(1) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id();
     PostNotifyError(bitstream_buffer.id(), INVALID_ARGUMENT);
     return;
   }
 
-  if (video_frame->format() != PIXEL_FORMAT_I420) {
-    PostNotifyError(bitstream_buffer.id(), UNSUPPORTED_JPEG);
-    return;
-  }
-
   std::unique_ptr<JobRecord> job_record(
       new JobRecord(std::move(bitstream_buffer), std::move(video_frame)));
 
@@ -443,9 +441,8 @@
   output_buffer_coded_size_.SetSize(format.fmt.pix_mp.width,
                                     format.fmt.pix_mp.height);
   output_buffer_num_planes_ = format.fmt.pix_mp.num_planes;
-  for (size_t i = 0; i < output_buffer_num_planes_; ++i) {
-    output_bytesperlines_[i] = format.fmt.pix_mp.plane_fmt[i].bytesperline;
-  }
+  for (size_t i = 0; i < output_buffer_num_planes_; ++i)
+    output_strides_[i] = format.fmt.pix_mp.plane_fmt[i].bytesperline;
 
   VideoPixelFormat output_format =
       V4L2Device::V4L2PixFmtToVideoPixelFormat(output_buffer_pixelformat_);
@@ -682,75 +679,153 @@
 
 bool V4L2MjpegDecodeAccelerator::ConvertOutputImage(
     const BufferRecord& output_buffer,
-    VideoFrame* dst_frame) {
-  uint8_t* dst_y = dst_frame->data(VideoFrame::kYPlane);
-  uint8_t* dst_u = dst_frame->data(VideoFrame::kUPlane);
-  uint8_t* dst_v = dst_frame->data(VideoFrame::kVPlane);
-  size_t dst_y_stride = dst_frame->stride(VideoFrame::kYPlane);
-  size_t dst_u_stride = dst_frame->stride(VideoFrame::kUPlane);
-  size_t dst_v_stride = dst_frame->stride(VideoFrame::kVPlane);
-
-  // It is assumed that |dst_frame| is backed by enough memory that it is safe
-  // to store an I420 frame of |dst_width|x|dst_height| in it using the data
-  // pointers and strides from above.
-  int dst_width = dst_frame->coded_size().width();
-  int dst_height = dst_frame->coded_size().height();
-
-  // The video frame's coded dimensions should be even for the I420 format.
-  DCHECK_EQ(0, dst_width % 2);
-  DCHECK_EQ(0, dst_height % 2);
-
+    scoped_refptr<VideoFrame> dst_frame) {
   // The coded size of the hardware buffer should be at least as large as the
-  // video frame's coded size.
+  // video frame's visible size.
+  const int dst_width = dst_frame->visible_rect().width();
+  const int dst_height = dst_frame->visible_rect().height();
   DCHECK_GE(output_buffer_coded_size_.width(), dst_width);
   DCHECK_GE(output_buffer_coded_size_.height(), dst_height);
 
-  if (output_buffer_num_planes_ == 1) {
-    // Use ConvertToI420 to convert all splane buffers.
-    // If the source format is I420, ConvertToI420 will simply copy the frame.
-    VideoPixelFormat format =
+  // Dmabuf-backed frame needs to be mapped for SW access.
+  if (dst_frame->HasDmaBufs()) {
+    std::unique_ptr<VideoFrameMapper> frame_mapper =
+        VideoFrameMapperFactory::CreateMapper(dst_frame->format());
+    if (!frame_mapper) {
+      VLOGF(1) << "Failed to create video frame mapper";
+      return false;
+    }
+    dst_frame = frame_mapper->Map(std::move(dst_frame));
+    if (!dst_frame) {
+      VLOGF(1) << "Failed to map DMA-buf video frame";
+      return false;
+    }
+  }
+
+  // Extract destination pointers and strides.
+  std::array<uint8_t*, VideoFrame::kMaxPlanes> dst_ptrs{};
+  std::array<int, VideoFrame::kMaxPlanes> dst_strides{};
+  for (size_t i = 0; i < dst_frame->layout().num_planes(); i++) {
+    dst_ptrs[i] = dst_frame->visible_data(i);
+    dst_strides[i] = base::checked_cast<int>(dst_frame->stride(i));
+  }
+
+  // Use ConvertToI420 to convert all splane formats to I420.
+  if (output_buffer_num_planes_ == 1 &&
+      dst_frame->format() == PIXEL_FORMAT_I420) {
+    DCHECK_EQ(dst_frame->layout().num_planes(), 3u);
+    const VideoPixelFormat format =
         V4L2Device::V4L2PixFmtToVideoPixelFormat(output_buffer_pixelformat_);
-    size_t src_size =
+    if (format == PIXEL_FORMAT_UNKNOWN) {
+      VLOGF(1) << "Unknown V4L2 format: "
+               << FourccToString(output_buffer_pixelformat_);
+      return false;
+    }
+    const size_t src_size =
         VideoFrame::AllocationSize(format, output_buffer_coded_size_);
     if (libyuv::ConvertToI420(
-            static_cast<uint8_t*>(output_buffer.address[0]), src_size, dst_y,
-            dst_y_stride, dst_u, dst_u_stride, dst_v, dst_v_stride, 0, 0,
+            static_cast<uint8_t*>(output_buffer.address[0]), src_size,
+            dst_ptrs[0], dst_strides[0], dst_ptrs[1], dst_strides[1],
+            dst_ptrs[2], dst_strides[2], 0 /*x*/, 0 /*y*/,
             output_buffer_coded_size_.width(),
             output_buffer_coded_size_.height(), dst_width, dst_height,
             libyuv::kRotate0, output_buffer_pixelformat_)) {
       VLOGF(1) << "ConvertToI420 failed. Source format: "
-               << output_buffer_pixelformat_;
+               << FourccToString(output_buffer_pixelformat_);
       return false;
     }
-  } else if (output_buffer_pixelformat_ == V4L2_PIX_FMT_YUV420M ||
-             output_buffer_pixelformat_ == V4L2_PIX_FMT_YUV422M) {
-    DCHECK(output_buffer_num_planes_ == 3);
-    uint8_t* src_y = static_cast<uint8_t*>(output_buffer.address[0]);
-    uint8_t* src_u = static_cast<uint8_t*>(output_buffer.address[1]);
-    uint8_t* src_v = static_cast<uint8_t*>(output_buffer.address[2]);
-    size_t src_y_stride = output_bytesperlines_[0];
-    size_t src_u_stride = output_bytesperlines_[1];
-    size_t src_v_stride = output_bytesperlines_[2];
-    if (output_buffer_pixelformat_ == V4L2_PIX_FMT_YUV420M) {
-      if (libyuv::I420Copy(src_y, src_y_stride, src_u, src_u_stride, src_v,
-                           src_v_stride, dst_y, dst_y_stride, dst_u,
-                           dst_u_stride, dst_v, dst_v_stride, dst_width,
-                           dst_height)) {
-        VLOGF(1) << "I420Copy failed";
+    return true;
+  }
+
+  // Extract source pointers and strides.
+  std::array<const uint8_t*, VideoFrame::kMaxPlanes> src_ptrs{};
+  std::array<int, VideoFrame::kMaxPlanes> src_strides{};
+  for (size_t i = 0; i < output_buffer_num_planes_; i++) {
+    src_ptrs[i] = static_cast<uint8_t*>(output_buffer.address[i]);
+    src_strides[i] = output_strides_[i];
+  }
+
+  if (output_buffer_pixelformat_ == V4L2_PIX_FMT_YUV420M) {
+    DCHECK_EQ(output_buffer_num_planes_, 3u);
+    switch (dst_frame->format()) {
+      case PIXEL_FORMAT_I420:
+        DCHECK_EQ(dst_frame->layout().num_planes(), 3u);
+        if (libyuv::I420Copy(src_ptrs[0], src_strides[0], src_ptrs[1],
+                             src_strides[1], src_ptrs[2], src_strides[2],
+                             dst_ptrs[0], dst_strides[0], dst_ptrs[1],
+                             dst_strides[1], dst_ptrs[2], dst_strides[2],
+                             dst_width, dst_height)) {
+          VLOGF(1) << "I420Copy failed";
+          return false;
+        }
+        break;
+      case PIXEL_FORMAT_YV12:
+        DCHECK_EQ(dst_frame->layout().num_planes(), 3u);
+        if (libyuv::I420Copy(src_ptrs[0], src_strides[0], src_ptrs[1],
+                             src_strides[1], src_ptrs[2], src_strides[2],
+                             dst_ptrs[0], dst_strides[0], dst_ptrs[2],
+                             dst_strides[2], dst_ptrs[1], dst_strides[1],
+                             dst_width, dst_height)) {
+          VLOGF(1) << "I420Copy failed";
+          return false;
+        }
+        break;
+      case PIXEL_FORMAT_NV12:
+        DCHECK_EQ(dst_frame->layout().num_planes(), 2u);
+        if (libyuv::I420ToNV12(src_ptrs[0], src_strides[0], src_ptrs[1],
+                               src_strides[1], src_ptrs[2], src_strides[2],
+                               dst_ptrs[0], dst_strides[0], dst_ptrs[1],
+                               dst_strides[1], dst_width, dst_height)) {
+          VLOGF(1) << "I420ToNV12 failed";
+          return false;
+        }
+        break;
+      default:
+        VLOGF(1) << "Can't convert image from I420 to " << dst_frame->format();
         return false;
-      }
-    } else {  // output_buffer_pixelformat_ == V4L2_PIX_FMT_YUV422M
-      if (libyuv::I422ToI420(src_y, src_y_stride, src_u, src_u_stride, src_v,
-                             src_v_stride, dst_y, dst_y_stride, dst_u,
-                             dst_u_stride, dst_v, dst_v_stride, dst_width,
-                             dst_height)) {
-        VLOGF(1) << "I422ToI420 failed";
+    }
+  } else if (output_buffer_pixelformat_ == V4L2_PIX_FMT_YUV422M) {
+    DCHECK_EQ(output_buffer_num_planes_, 3u);
+    switch (dst_frame->format()) {
+      case PIXEL_FORMAT_I420:
+        DCHECK_EQ(dst_frame->layout().num_planes(), 3u);
+        if (libyuv::I422ToI420(src_ptrs[0], src_strides[0], src_ptrs[1],
+                               src_strides[1], src_ptrs[2], src_strides[2],
+                               dst_ptrs[0], dst_strides[0], dst_ptrs[1],
+                               dst_strides[1], dst_ptrs[2], dst_strides[2],
+                               dst_width, dst_height)) {
+          VLOGF(1) << "I422ToI420 failed";
+          return false;
+        }
+        break;
+      case PIXEL_FORMAT_YV12:
+        DCHECK_EQ(dst_frame->layout().num_planes(), 3u);
+        if (libyuv::I422ToI420(src_ptrs[0], src_strides[0], src_ptrs[1],
+                               src_strides[1], src_ptrs[2], src_strides[2],
+                               dst_ptrs[0], dst_strides[0], dst_ptrs[2],
+                               dst_strides[2], dst_ptrs[1], dst_strides[1],
+                               dst_width, dst_height)) {
+          VLOGF(1) << "I422ToI420 failed";
+          return false;
+        }
+        break;
+      case PIXEL_FORMAT_NV12:
+        DCHECK_EQ(dst_frame->layout().num_planes(), 2u);
+        if (libyuv::I422ToNV21(src_ptrs[0], src_strides[0], src_ptrs[2],
+                               src_strides[2], src_ptrs[1], src_strides[1],
+                               dst_ptrs[0], dst_strides[0], dst_ptrs[1],
+                               dst_strides[1], dst_width, dst_height)) {
+          VLOGF(1) << "I422ToNV21 failed";
+          return false;
+        }
+        break;
+      default:
+        VLOGF(1) << "Can't convert image from I422 to " << dst_frame->format();
         return false;
-      }
     }
   } else {
     VLOGF(1) << "Unsupported source buffer format: "
-             << output_buffer_pixelformat_;
+             << FourccToString(output_buffer_pixelformat_);
     return false;
   }
   return true;
@@ -833,7 +908,8 @@
       // Copy the decoded data from output buffer to the buffer provided by the
       // client. Do format conversion when output format is not
       // V4L2_PIX_FMT_YUV420.
-      if (!ConvertOutputImage(output_record, job_record->out_frame.get())) {
+      if (!ConvertOutputImage(output_record,
+                              std::move(job_record->out_frame))) {
         PostNotifyError(job_record->bitstream_buffer_id, PLATFORM_FAILURE);
         return;
       }
@@ -959,11 +1035,11 @@
   qbuf.m.planes = planes;
   IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_QBUF, &qbuf);
   input_record.at_device = true;
-  running_jobs_.push(std::move(job_record));
-  free_input_buffers_.pop_back();
 
   DVLOGF(3) << "enqueued frame id=" << job_record->bitstream_buffer_id
             << " to device.";
+  running_jobs_.push(std::move(job_record));
+  free_input_buffers_.pop_back();
   return true;
 }
 
diff --git a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h
index 3cdc97e..acff2f6 100644
--- a/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h
+++ b/media/gpu/v4l2/v4l2_mjpeg_decode_accelerator.h
@@ -20,12 +20,13 @@
 #include "components/chromeos_camera/mjpeg_decode_accelerator.h"
 #include "media/base/bitstream_buffer.h"
 #include "media/base/unaligned_shared_memory.h"
-#include "media/base/video_frame.h"
 #include "media/gpu/media_gpu_export.h"
 #include "media/gpu/v4l2/v4l2_device.h"
 
 namespace media {
 
+class VideoFrame;
+
 class MEDIA_GPU_EXPORT V4L2MjpegDecodeAccelerator
     : public chromeos_camera::MjpegDecodeAccelerator {
  public:
@@ -84,13 +85,12 @@
   void DestroyInputBuffers();
   void DestroyOutputBuffers();
 
-  // Convert |output_buffer| to I420 and copy the result to |dst_frame|.
-  // The function can convert to I420 from the following formats:
-  //   - All splane formats that libyuv::ConvertToI420 can handle.
-  //   - V4L2_PIX_FMT_YUV_420M
-  //   - V4L2_PIX_FMT_YUV_422M
+  // Convert |output_buffer| to |dst_frame|. The function supports the following
+  // formats:
+  //   - All formats that libyuv::ConvertToI420 can handle.
+  //   - V4L2_PIX_FMT_YUV_420M, V4L2_PIX_FMT_YUV_422M to I420, YV12, and NV12.
   bool ConvertOutputImage(const BufferRecord& output_buffer,
-                          VideoFrame* dst_frame);
+                          scoped_refptr<VideoFrame> dst_frame);
 
   // Return the number of input/output buffers enqueued to the device.
   size_t InputBufferQueuedCount();
@@ -139,7 +139,9 @@
 
   // Number of physical planes the output buffers have.
   size_t output_buffer_num_planes_;
-  size_t output_bytesperlines_[VIDEO_MAX_PLANES];
+
+  // Strides of the output buffers.
+  size_t output_strides_[VIDEO_MAX_PLANES];
 
   // ChildThread's task runner.
   scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
diff --git a/media/mojo/clients/mojo_video_decoder.cc b/media/mojo/clients/mojo_video_decoder.cc
index b924556..1d615b6 100644
--- a/media/mojo/clients/mojo_video_decoder.cc
+++ b/media/mojo/clients/mojo_video_decoder.cc
@@ -118,6 +118,7 @@
     : task_runner_(task_runner),
       remote_decoder_info_(remote_decoder.PassInterface()),
       gpu_factories_(gpu_factories),
+      timestamps_(128),
       writer_capacity_(
           GetDefaultDecoderBufferConverterCapacity(DemuxerStream::VIDEO)),
       client_binding_(this),
@@ -223,11 +224,9 @@
     return;
   }
 
-  int64_t timestamp = 0ll;
   if (!buffer->end_of_stream()) {
-    timestamp = buffer->timestamp().InMilliseconds();
-    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("media", "MojoVideoDecoder::Decode",
-                                      timestamp, "timestamp", timestamp);
+    timestamps_.Put(buffer->timestamp().InMilliseconds(),
+                    base::TimeTicks::Now());
   }
 
   mojom::DecoderBufferPtr mojo_buffer =
@@ -241,10 +240,9 @@
 
   uint64_t decode_id = decode_counter_++;
   pending_decodes_[decode_id] = std::move(bound_decode_cb);
-  remote_decoder_->Decode(
-      std::move(mojo_buffer),
-      base::Bind(&MojoVideoDecoder::OnDecodeDone, base::Unretained(this),
-                 decode_id, timestamp));
+  remote_decoder_->Decode(std::move(mojo_buffer),
+                          base::Bind(&MojoVideoDecoder::OnDecodeDone,
+                                     base::Unretained(this), decode_id));
 }
 
 void MojoVideoDecoder::OnVideoFrameDecoded(
@@ -265,15 +263,24 @@
             release_token.value()));
   }
   const int64_t timestamp = frame->timestamp().InMilliseconds();
-  TRACE_EVENT_NESTABLE_ASYNC_END1("media", "MojoVideoDecoder::Decode",
-                                  timestamp, "timestamp", timestamp);
+  const auto timestamp_it = timestamps_.Peek(timestamp);
+  if (timestamp_it != timestamps_.end()) {
+    const auto decode_start_time = timestamp_it->second;
+    const auto decode_end_time = base::TimeTicks::Now();
+
+    TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
+        "media", "MojoVideoDecoder::Decode", timestamp, decode_start_time);
+    TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP1(
+        "media", "MojoVideoDecoder::Decode", timestamp, decode_end_time,
+        "timestamp", timestamp);
+    UMA_HISTOGRAM_TIMES("Media.MojoVideoDecoder.Decode",
+                        decode_end_time - decode_start_time);
+  }
 
   output_cb_.Run(frame);
 }
 
-void MojoVideoDecoder::OnDecodeDone(uint64_t decode_id,
-                                    int64_t timestamp,
-                                    DecodeStatus status) {
+void MojoVideoDecoder::OnDecodeDone(uint64_t decode_id, DecodeStatus status) {
   DVLOG(3) << __func__;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
@@ -283,10 +290,6 @@
     Stop();
     return;
   }
-  if (status != DecodeStatus::OK) {
-    TRACE_EVENT_NESTABLE_ASYNC_END1("media", "MojoVideoDecoder::Decode",
-                                    timestamp, "timestamp", timestamp);
-  }
 
   DecodeCB decode_cb = std::move(it->second);
   pending_decodes_.erase(it);
diff --git a/media/mojo/clients/mojo_video_decoder.h b/media/mojo/clients/mojo_video_decoder.h
index d6030b0..52bc2b8 100644
--- a/media/mojo/clients/mojo_video_decoder.h
+++ b/media/mojo/clients/mojo_video_decoder.h
@@ -5,6 +5,7 @@
 #ifndef MEDIA_MOJO_CLIENTS_MOJO_VIDEO_DECODER_H_
 #define MEDIA_MOJO_CLIENTS_MOJO_VIDEO_DECODER_H_
 
+#include "base/containers/mru_cache.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -74,7 +75,7 @@
   void OnInitializeDone(bool status,
                         bool needs_bitstream_conversion,
                         int32_t max_decode_requests);
-  void OnDecodeDone(uint64_t decode_id, int64_t timestamp, DecodeStatus status);
+  void OnDecodeDone(uint64_t decode_id, DecodeStatus status);
   void OnResetDone();
 
   void BindRemoteDecoder();
@@ -104,6 +105,10 @@
   std::map<uint64_t, DecodeCB> pending_decodes_;
   base::OnceClosure reset_cb_;
 
+  // DecodeBuffer/VideoFrame timestamps for histogram/tracing purposes. Must be
+  // large enough to account for any amount of frame reordering.
+  base::MRUCache<int64_t, base::TimeTicks> timestamps_;
+
   mojom::VideoDecoderPtr remote_decoder_;
   std::unique_ptr<MojoDecoderBufferWriter> mojo_decoder_buffer_writer_;
 
diff --git a/media/test/data/player.html b/media/test/data/player.html
index 1f891b0..b3171c19 100644
--- a/media/test/data/player.html
+++ b/media/test/data/player.html
@@ -8,21 +8,54 @@
 // <audio> or <video> player element.
 var player;
 var logs = document.getElementById('logs');
+var heartbeatCount = 0;
 
 function Log(message) {
   logs.innerHTML = message + '<br>' + logs.innerHTML;
   console.log(message);
 }
 
+function onLogEvent(e) {
+  Log('Event: ' + e.type);
+}
+
+function getTimeRanges(range) {
+  const result = [];
+  for (let i = 0; i < range.length; i++) {
+    result.push(`[${range.start(i)},${range.end(i)}]`);
+  }
+  return '[' + result.join(', ') + ']';
+}
+
+function getVideoStatus(video) {
+  if (video == null) {
+    return 'null';
+  }
+  const result = [];
+  result.push(`paused: ${video.paused}`);
+  result.push(`ended: ${video.ended}`);
+  result.push(`currentTime: ${video.currentTime}`);
+  result.push(`duration: ${video.duration}`);
+  result.push(`buffered: ${getTimeRanges(video.buffered)}`);
+  result.push(`played: ${getTimeRanges(video.played)}`);
+  if (video.error) {
+    result.push(`error: {${video.error.code},${video.error.message}}`);
+  }
+  return result.join(', ');
+}
+
 // Listen for |event| from |element|, set document.title = |event| upon event.
 function InstallTitleEventHandler(element, event) {
   element.addEventListener(event, function(e) {
+    onLogEvent(e);
     document.title = event.toUpperCase();
   }, false);
 }
 
 function InstallTitleErrorEventHandler(element, error_substr) {
   element.addEventListener('error', function(e) {
+    onLogEvent(e);
+
     // Element's error attribute must be populated.
     var mediaError = element.error;
     if (mediaError == null) {
@@ -49,16 +82,22 @@
 }
 
 function SeekTestStep(e) {
+  if (e) onLogEvent(e);
   player.removeEventListener('ended', SeekTestStep, false);
 
   // Test completes on the next ended event.
   InstallTitleEventHandler(player, 'ended');
 
   player.currentTime = 0.9 * player.duration;
-  player.play();
+  Log('Seeking back to ' + 0.9 * player.duration);
+  player.play().catch(function(error) {
+    Log(error);
+  });
+
 }
 
 function SeekTestTimeoutSetup() {
+  Log('timeupdate @ ' + player.currentTime);
   if (player.currentTime < 2)
     return;
 
@@ -136,6 +175,19 @@
   player.addEventListener('ended', SeekTestStep, false);
   player.addEventListener('timeupdate', SeekTestTimeoutSetup, false);
 
+  // Log events.
+  player.addEventListener('canplay', onLogEvent);
+  player.addEventListener('load', onLogEvent);
+  player.addEventListener('playing', onLogEvent);
+  player.addEventListener('play', onLogEvent);
+  player.addEventListener('canplaythrough', onLogEvent);
+  player.addEventListener('stalled', onLogEvent);
+  player.addEventListener('waiting', onLogEvent);
+  setInterval(function () {
+    Log('heartbeat #' + ++heartbeatCount +
+    ' video: ' + getVideoStatus(player));
+  }, 1000);
+
   // Ensure we percolate up any error events, and optionally verify they contain
   // the expected error substring in their message.
   InstallTitleErrorEventHandler(player, error_substr);
@@ -143,7 +195,10 @@
   // Starts the player.
   player.loop = loop;
   player.src = media_url;
-  player.play();
+  Log('Starting by calling play()');
+  player.play().catch(function(error) {
+    Log(error);
+  });
 }
 </script>
 </html>
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index fb7cd00b..2119e01d 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -2830,13 +2830,29 @@
                         right.height(), client_->GetBackgroundColor());
   }
 
-  pp::Rect bottom =
-      draw_utils::GetBottomFillRect(page_rect, inset_sizes, kBottomSeparator);
-  bottom = GetScreenRect(bottom).Intersect(dirty_in_screen);
+  pp::Rect bottom_in_screen;
+  if (two_up_view_) {
+    pp::Rect page_in_screen = GetScreenRect(page_rect);
+    bottom_in_screen = draw_utils::GetBottomGapBetweenRects(
+        page_in_screen.bottom(), dirty_in_screen);
 
-  FPDFBitmap_FillRect(bitmap, bottom.x() - dirty_in_screen.x(),
-                      bottom.y() - dirty_in_screen.y(), bottom.width(),
-                      bottom.height(), client_->GetBackgroundColor());
+    if (page_index % 2 == 1) {
+      // Only draw over the right two-up view column with empty space.
+      bottom_in_screen.set_width(bottom_in_screen.width() / 2);
+      bottom_in_screen.set_x(page_in_screen.x());
+    }
+
+    bottom_in_screen = bottom_in_screen.Intersect(dirty_in_screen);
+  } else {
+    bottom_in_screen = GetScreenRect(draw_utils::GetBottomFillRect(
+        page_rect, inset_sizes, kBottomSeparator));
+    bottom_in_screen = bottom_in_screen.Intersect(dirty_in_screen);
+  }
+
+  FPDFBitmap_FillRect(bitmap, bottom_in_screen.x() - dirty_in_screen.x(),
+                      bottom_in_screen.y() - dirty_in_screen.y(),
+                      bottom_in_screen.width(), bottom_in_screen.height(),
+                      client_->GetBackgroundColor());
 }
 
 void PDFiumEngine::PaintPageShadow(int progressive_index,
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index 428da182..565e088 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -586,17 +586,6 @@
 void ClientSession::OnDesktopDisplayChanged(
     std::unique_ptr<protocol::VideoLayout> displays) {
   LOG(INFO) << "ClientSession::OnDesktopDisplayChanged";
-
-#if defined(OS_MACOSX)
-  // Don't send pixel based TrackLayout info to the client.  There are several
-  // bugs related to cursor position and desktop selection (for multi-mon) which
-  // prevent the user from interacting with their machine.  For now, we return
-  // early which will provide the same experience as the Chrome app used to and
-  // the iOS and Android apps currently do.
-  // TODO(crbug.com/987513): Investigate to figure out why the cursor offset and
-  // display selection issues are occurring and then re-enable this for MacOS.
-  return;
-#else
   // Scan display list to calculate the full desktop size.
   int min_x = 0;
   int max_x = 0;
@@ -687,7 +676,6 @@
   }
 
   connection_->client_stub()->SetVideoLayout(layout);
-#endif  // defined(OS_MACOSX)
 }
 
 void ClientSession::CreateFileTransferMessageHandler(
diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc
index 2cfa4c16..c813625 100644
--- a/remoting/host/client_session_unittest.cc
+++ b/remoting/host/client_session_unittest.cc
@@ -48,15 +48,6 @@
 #define MAYBE_RestoreEventState DISABLED_RestoreEventState
 #define MAYBE_MultiMonMouseMove DISABLED_MultiMonMouseMove
 #define MAYBE_DisconnectOnLocalInputTest DISABLED_DisconnectOnLocalInputTest
-#elif OS_MACOSX
-// TODO(crbug.com/987513): Reenable tests for MacOS.
-#define MAYBE_MultiMonMouseMove_SameSize DISABLED_MultiMonMouseMove_SameSize
-#define MAYBE_MultiMonMouseMove DISABLED_MultiMonMouseMove
-#define MAYBE_ClampMouseEvents DISABLED_ClampMouseEvents
-#define MAYBE_DisableInputs DISABLED_DisableInputs
-#define MAYBE_DisconnectOnLocalInputTest DISABLED_DisconnectOnLocalInputTest
-#define MAYBE_LocalInputTest DISABLED_LocalInputTest
-#define MAYBE_RestoreEventState DISABLED_RestoreEventState
 #else
 #define MAYBE_LocalInputTest LocalInputTest
 #define MAYBE_ClampMouseEvents ClampMouseEvents
diff --git a/services/identity/README.md b/services/identity/README.md
index f5ece0f4..96ed8b6 100644
--- a/services/identity/README.md
+++ b/services/identity/README.md
@@ -42,11 +42,11 @@
 
 ## Obtaining an Access Token
 
-Where you would have called OAuth2TokenService::StartRequest(), you should
+Where you would have called ProfileOAuth2TokenService::StartRequest(), you should
 instead call IdentityManager::GetAccessToken(). This interface is a 1:1
 correspondence that should transparently work in all use cases, although there
 are currently still some input parameters that need to be added to its API to
-match esoteric variants of the OAuth2TokenService API. Here is an [example
+match esoteric variants of the ProfileOAuth2TokenService API. Here is an [example
 CL](https://chromium-review.googlesource.com/c/514047/) that illustrates
 conversion of a client.
 
@@ -58,7 +58,7 @@
 ## Being Notified on Signin of the Primary Account
 
 If you were previously listening to PrimaryAccountManager::GoogleSigninSucceeded()
-or OAuth2TokenService::OnRefreshTokenIsAvailable() to determine when the primary
+or ProfileOAuth2TokenService::OnRefreshTokenIsAvailable() to determine when the primary
 account is available, you should call
 IdentityManager::GetPrimaryAccountWhenAvailable(). This method will fire when
 the authenticated account is signed in, has a refresh token available, and the
@@ -73,7 +73,7 @@
 ## Determining if an Account Has a Refresh Token Available
 
 There is no way to determine this information synchronously, i.e., there is no
-literal equivalent to OAuth2TokenService::IsRefreshTokenAvailable().  To date,
+literal equivalent to ProfileOAuth2TokenService::IsRefreshTokenAvailable().  To date,
 all use cases of this method that we have seen have been part of a larger
 asynchronous flow (e.g., determining whether the user needs to sign in before we
 can obtain an access token in response to an invocation of the chrome.identity
@@ -89,7 +89,7 @@
 
 ## Being Notified When An Account Has a Refresh Token Available
 
-All of the use cases of OAuth2TokenService::OnRefreshTokenAvailable() that we
+All of the use cases of ProfileOAuth2TokenService::OnRefreshTokenAvailable() that we
 have seen to date have been for the purpose of knowing when the authenticated
 account is available (i.e., signed in with a refresh token available). For this
 purpose, you should call IdentityManager::GetPrimaryAccountWhenAvailable(). Here
@@ -101,7 +101,7 @@
 ## Observing Signin-Related Events
 
 There are plans to build a unified Observer interface that will supersede the
-various current Observer interfaces (AccountTracker, OAuth2TokenService,
+various current Observer interfaces (AccountTracker, ProfileOAuth2TokenService,
 PrimaryAccountManager, AccountTrackerService). However, this functionality has
 not yet been built. Contact blundell@chromium.org with your use case, which can
 help drive the bringup of this interface.
diff --git a/services/identity/public/mojom/identity_accessor.mojom b/services/identity/public/mojom/identity_accessor.mojom
index 7007a41..c359808 100644
--- a/services/identity/public/mojom/identity_accessor.mojom
+++ b/services/identity/public/mojom/identity_accessor.mojom
@@ -40,7 +40,7 @@
   // |error| will give information detailing the reason for the failure, and
   // |expiration_time| is undefined. |consumer_id| is an arbitrary string used
   // to identity the consumer (e.g., in about:://signin-internals).
-  // NOTE: |account_id| corresponds to that used by OAuth2TokenService.
+  // NOTE: |account_id| corresponds to that used by IdentityManager.
   GetAccessToken(CoreAccountId account_id, ScopeSet scopes, string consumer_id)
       => (string? token,
          mojo_base.mojom.Time expiration_time,
diff --git a/services/video_capture/BUILD.gn b/services/video_capture/BUILD.gn
index 3a0ba30..aef23c4 100644
--- a/services/video_capture/BUILD.gn
+++ b/services/video_capture/BUILD.gn
@@ -51,7 +51,7 @@
   ]
 
   if (is_chromeos) {
-    public_deps += [ "//media/capture/video/chromeos/mojo:cros_camera" ]
+    public_deps += [ "//media/capture/video/chromeos/mojom:cros_camera" ]
   }
 }
 
diff --git a/services/video_capture/device_factory.h b/services/video_capture/device_factory.h
index 0898a1a..bc410f6f 100644
--- a/services/video_capture/device_factory.h
+++ b/services/video_capture/device_factory.h
@@ -8,7 +8,7 @@
 #include "services/video_capture/public/mojom/device_factory.mojom.h"
 
 #if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #endif  // defined(OS_CHROMEOS)
 
 namespace video_capture {
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.h b/services/video_capture/device_factory_media_to_mojo_adapter.h
index 28095f25..ff2260ca 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.h
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.h
@@ -14,7 +14,7 @@
 #include "services/video_capture/public/mojom/devices_changed_observer.mojom.h"
 
 #if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
 #endif  // defined(OS_CHROMEOS)
 
diff --git a/services/video_capture/public/mojom/BUILD.gn b/services/video_capture/public/mojom/BUILD.gn
index 00197126..519d5b84 100644
--- a/services/video_capture/public/mojom/BUILD.gn
+++ b/services/video_capture/public/mojom/BUILD.gn
@@ -29,7 +29,7 @@
   if (is_chromeos) {
     deps += [
       "//components/chromeos_camera/common",
-      "//media/capture/video/chromeos/mojo:cros_camera",
+      "//media/capture/video/chromeos/mojom:cros_camera",
     ]
   }
 }
diff --git a/services/video_capture/public/mojom/video_capture_service.mojom b/services/video_capture/public/mojom/video_capture_service.mojom
index 916e8ef..5b4cc56 100644
--- a/services/video_capture/public/mojom/video_capture_service.mojom
+++ b/services/video_capture/public/mojom/video_capture_service.mojom
@@ -11,7 +11,7 @@
 import "services/video_capture/public/mojom/video_source_provider.mojom";
 
 [EnableIf=is_chromeos]
-import "media/capture/video/chromeos/mojo/cros_image_capture.mojom";
+import "media/capture/video/chromeos/mojom/cros_image_capture.mojom";
 
 [EnableIf=is_chromeos]
 interface AcceleratorFactory {
diff --git a/services/video_capture/video_capture_service_impl.h b/services/video_capture/video_capture_service_impl.h
index e98751c..ef83ff12 100644
--- a/services/video_capture/video_capture_service_impl.h
+++ b/services/video_capture/video_capture_service_impl.h
@@ -16,7 +16,7 @@
 #include "services/video_capture/public/mojom/video_capture_service.mojom.h"
 
 #if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #endif  // defined(OS_CHROMEOS)
 
 namespace video_capture {
diff --git a/services/video_capture/virtual_device_enabled_device_factory.h b/services/video_capture/virtual_device_enabled_device_factory.h
index 8c812c2..4b42dd2 100644
--- a/services/video_capture/virtual_device_enabled_device_factory.h
+++ b/services/video_capture/virtual_device_enabled_device_factory.h
@@ -15,7 +15,7 @@
 #include "services/video_capture/public/mojom/virtual_device.mojom.h"
 
 #if defined(OS_CHROMEOS)
-#include "media/capture/video/chromeos/mojo/cros_image_capture.mojom.h"
+#include "media/capture/video/chromeos/mojom/cros_image_capture.mojom.h"
 #endif  // defined(OS_CHROMEOS)
 
 namespace video_capture {
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn
index d5ed4000..fdd3766 100644
--- a/storage/browser/BUILD.gn
+++ b/storage/browser/BUILD.gn
@@ -105,10 +105,6 @@
     "fileapi/file_system_quota_util.h",
     "fileapi/file_system_url.cc",
     "fileapi/file_system_url.h",
-    "fileapi/file_system_url_request_job.cc",
-    "fileapi/file_system_url_request_job.h",
-    "fileapi/file_system_url_request_job_factory.cc",
-    "fileapi/file_system_url_request_job_factory.h",
     "fileapi/file_system_usage_cache.cc",
     "fileapi/file_system_usage_cache.h",
     "fileapi/file_writer_delegate.cc",
@@ -282,7 +278,6 @@
     "fileapi/file_system_operation_impl_unittest.cc",
     "fileapi/file_system_operation_impl_write_unittest.cc",
     "fileapi/file_system_quota_client_unittest.cc",
-    "fileapi/file_system_url_request_job_unittest.cc",
     "fileapi/file_system_url_unittest.cc",
     "fileapi/file_system_usage_cache_unittest.cc",
     "fileapi/file_writer_delegate_unittest.cc",
diff --git a/storage/browser/fileapi/file_system_url_request_job.cc b/storage/browser/fileapi/file_system_url_request_job.cc
deleted file mode 100644
index 0edc3dd3..0000000
--- a/storage/browser/fileapi/file_system_url_request_job.cc
+++ /dev/null
@@ -1,258 +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 "storage/browser/fileapi/file_system_url_request_job.h"
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "net/base/file_stream.h"
-#include "net/base/io_buffer.h"
-#include "net/base/mime_util.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_response_info.h"
-#include "net/http/http_util.h"
-#include "net/url_request/url_request.h"
-#include "storage/browser/fileapi/file_stream_reader.h"
-#include "storage/browser/fileapi/file_system_context.h"
-#include "storage/browser/fileapi/file_system_operation_runner.h"
-#include "storage/common/fileapi/file_system_util.h"
-#include "url/gurl.h"
-
-using net::NetworkDelegate;
-using net::URLRequest;
-using net::URLRequestJob;
-using net::URLRequestStatus;
-
-namespace storage {
-
-static net::HttpResponseHeaders* CreateHttpResponseHeaders() {
-  // HttpResponseHeaders expects its input string to be terminated by two NULs.
-  static const char kStatus[] = "HTTP/1.1 200 OK\0";
-  static const size_t kStatusLen = base::size(kStatus);
-
-  net::HttpResponseHeaders* headers =
-      new net::HttpResponseHeaders(std::string(kStatus, kStatusLen));
-
-  // Tell WebKit never to cache this content.
-  std::string cache_control(net::HttpRequestHeaders::kCacheControl);
-  cache_control.append(": no-cache");
-  headers->AddHeader(cache_control);
-
-  return headers;
-}
-
-FileSystemURLRequestJob::FileSystemURLRequestJob(
-    URLRequest* request,
-    NetworkDelegate* network_delegate,
-    const std::string& storage_domain,
-    FileSystemContext* file_system_context)
-    : URLRequestJob(request, network_delegate),
-      storage_domain_(storage_domain),
-      file_system_context_(file_system_context),
-      is_directory_(false),
-      remaining_bytes_(0),
-      range_parse_result_(net::OK),
-      weak_factory_(this) {}
-
-FileSystemURLRequestJob::~FileSystemURLRequestJob() = default;
-
-void FileSystemURLRequestJob::Start() {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&FileSystemURLRequestJob::StartAsync,
-                                weak_factory_.GetWeakPtr()));
-}
-
-void FileSystemURLRequestJob::Kill() {
-  reader_.reset();
-  URLRequestJob::Kill();
-  weak_factory_.InvalidateWeakPtrs();
-}
-
-int FileSystemURLRequestJob::ReadRawData(net::IOBuffer* dest, int dest_size) {
-  DCHECK_NE(dest_size, 0);
-  DCHECK_GE(remaining_bytes_, 0);
-
-  if (reader_.get() == nullptr)
-    return net::ERR_FAILED;
-
-  if (remaining_bytes_ < dest_size)
-    dest_size = remaining_bytes_;
-
-  if (!dest_size)
-    return 0;
-
-  const int rv = reader_->Read(dest, dest_size,
-                               base::BindOnce(&FileSystemURLRequestJob::DidRead,
-                                              weak_factory_.GetWeakPtr()));
-  if (rv >= 0) {
-    remaining_bytes_ -= rv;
-    DCHECK_GE(remaining_bytes_, 0);
-  }
-
-  return rv;
-}
-
-bool FileSystemURLRequestJob::GetMimeType(std::string* mime_type) const {
-  DCHECK(request_);
-  DCHECK(url_.is_valid());
-  base::FilePath::StringType extension = url_.path().Extension();
-  if (!extension.empty())
-    extension = extension.substr(1);
-  return net::GetWellKnownMimeTypeFromExtension(extension, mime_type);
-}
-
-void FileSystemURLRequestJob::SetExtraRequestHeaders(
-    const net::HttpRequestHeaders& headers) {
-  std::string range_header;
-  // Currently this job only cares about the Range header. Note that validation
-  // is deferred to DidGetMetaData(), because NotifyStartError is not legal to
-  // call since the job has not started.
-  if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
-    std::vector<net::HttpByteRange> ranges;
-
-    if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
-      if (ranges.size() == 1) {
-        byte_range_ = ranges[0];
-      } else {
-        // We don't support multiple range requests in one single URL request.
-        // TODO(adamk): decide whether we want to support multiple range
-        // requests.
-        range_parse_result_ = net::ERR_REQUEST_RANGE_NOT_SATISFIABLE;
-      }
-    }
-  }
-}
-
-void FileSystemURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
-  if (response_info_)
-    *info = *response_info_;
-}
-
-void FileSystemURLRequestJob::StartAsync() {
-  if (!request_)
-    return;
-  DCHECK(!reader_.get());
-  url_ = file_system_context_->CrackURL(request_->url());
-  if (!url_.is_valid()) {
-    const FileSystemRequestInfo& request_info = {request_->url(), request_,
-                                                 storage_domain_, 0};
-    file_system_context_->AttemptAutoMountForURLRequest(
-        request_info,
-        base::BindOnce(&FileSystemURLRequestJob::DidAttemptAutoMount,
-                       weak_factory_.GetWeakPtr()));
-    return;
-  }
-  if (!file_system_context_->CanServeURLRequest(url_)) {
-    // In incognito mode the API is not usable and there should be no data.
-    NotifyStartError(URLRequestStatus::FromError(net::ERR_FILE_NOT_FOUND));
-    return;
-  }
-  file_system_context_->operation_runner()->GetMetadata(
-      url_,
-      FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY |
-          FileSystemOperation::GET_METADATA_FIELD_SIZE,
-      base::BindOnce(&FileSystemURLRequestJob::DidGetMetadata,
-                     weak_factory_.GetWeakPtr()));
-}
-
-void FileSystemURLRequestJob::DidAttemptAutoMount(base::File::Error result) {
-  if (result >= 0 &&
-      file_system_context_->CrackURL(request_->url()).is_valid()) {
-    StartAsync();
-  } else {
-    NotifyStartError(URLRequestStatus::FromError(net::ERR_FILE_NOT_FOUND));
-  }
-}
-
-void FileSystemURLRequestJob::DidGetMetadata(
-    base::File::Error error_code,
-    const base::File::Info& file_info) {
-  if (error_code != base::File::FILE_OK) {
-    NotifyStartError(URLRequestStatus::FromError(
-        error_code == base::File::FILE_ERROR_INVALID_URL
-            ? net::ERR_INVALID_URL
-            : net::ERR_FILE_NOT_FOUND));
-    return;
-  }
-
-  // We may have been orphaned...
-  if (!request_)
-    return;
-
-  is_directory_ = file_info.is_directory;
-
-  if (range_parse_result_ != net::OK) {
-    NotifyStartError(URLRequestStatus::FromError(range_parse_result_));
-    return;
-  }
-
-  if (!byte_range_.ComputeBounds(file_info.size)) {
-    NotifyStartError(
-        URLRequestStatus::FromError(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
-    return;
-  }
-
-  if (is_directory_) {
-    NotifyHeadersComplete();
-    return;
-  }
-
-  remaining_bytes_ = byte_range_.last_byte_position() -
-                     byte_range_.first_byte_position() + 1;
-  DCHECK_GE(remaining_bytes_, 0);
-
-  DCHECK(!reader_.get());
-  reader_ = file_system_context_->CreateFileStreamReader(
-      url_, byte_range_.first_byte_position(), remaining_bytes_, base::Time());
-
-  set_expected_content_size(remaining_bytes_);
-  response_info_.reset(new net::HttpResponseInfo());
-  response_info_->headers = CreateHttpResponseHeaders();
-  NotifyHeadersComplete();
-}
-
-void FileSystemURLRequestJob::DidRead(int result) {
-  if (result >= 0) {
-    remaining_bytes_ -= result;
-    DCHECK_GE(remaining_bytes_, 0);
-  }
-
-  ReadRawDataComplete(result);
-}
-
-bool FileSystemURLRequestJob::IsRedirectResponse(
-    GURL* location,
-    int* http_status_code,
-    bool* insecure_scheme_was_upgraded) {
-  if (is_directory_) {
-    // This happens when we discovered the file is a directory, so needs a
-    // slash at the end of the path.
-    std::string new_path = request_->url().path();
-    new_path.push_back('/');
-    GURL::Replacements replacements;
-    replacements.SetPathStr(new_path);
-    *insecure_scheme_was_upgraded = false;
-    *location = request_->url().ReplaceComponents(replacements);
-    *http_status_code = 301;  // simulate a permanent redirect
-    return true;
-  }
-
-  return false;
-}
-
-}  // namespace storage
diff --git a/storage/browser/fileapi/file_system_url_request_job.h b/storage/browser/fileapi/file_system_url_request_job.h
deleted file mode 100644
index 97929c3..0000000
--- a/storage/browser/fileapi/file_system_url_request_job.h
+++ /dev/null
@@ -1,82 +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 STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_URL_REQUEST_JOB_H_
-#define STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_URL_REQUEST_JOB_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/component_export.h"
-#include "base/files/file.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_byte_range.h"
-#include "net/url_request/url_request_job.h"
-#include "storage/browser/fileapi/file_system_url.h"
-
-class GURL;
-
-namespace storage {
-class FileStreamReader;
-}
-
-namespace storage {
-class FileSystemContext;
-
-// A request job that handles reading filesystem: URLs
-class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemURLRequestJob
-    : public net::URLRequestJob {
- public:
-  FileSystemURLRequestJob(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate,
-      const std::string& storage_domain,
-      FileSystemContext* file_system_context);
-
-  // URLRequestJob methods:
-  void Start() override;
-  void Kill() override;
-  int ReadRawData(net::IOBuffer* buf, int buf_size) override;
-  bool IsRedirectResponse(GURL* location,
-                          int* http_status_code,
-                          bool* insecure_scheme_was_upgraded) override;
-  void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
-  void GetResponseInfo(net::HttpResponseInfo* info) override;
-
-  // FilterContext methods (via URLRequestJob):
-  bool GetMimeType(std::string* mime_type) const override;
-
- private:
-  class CallbackDispatcher;
-
-  ~FileSystemURLRequestJob() override;
-
-  void StartAsync();
-  void DidAttemptAutoMount(base::File::Error result);
-  void DidGetMetadata(base::File::Error error_code,
-                      const base::File::Info& file_info);
-  void DidRead(int result);
-
-  const std::string storage_domain_;
-  FileSystemContext* file_system_context_;
-  std::unique_ptr<storage::FileStreamReader> reader_;
-  FileSystemURL url_;
-  bool is_directory_;
-  std::unique_ptr<net::HttpResponseInfo> response_info_;
-  int64_t remaining_bytes_;
-  net::Error range_parse_result_;
-  net::HttpByteRange byte_range_;
-  base::WeakPtrFactory<FileSystemURLRequestJob> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(FileSystemURLRequestJob);
-};
-
-}  // namespace storage
-
-#endif  // STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_URL_REQUEST_JOB_H_
diff --git a/storage/browser/fileapi/file_system_url_request_job_factory.cc b/storage/browser/fileapi/file_system_url_request_job_factory.cc
deleted file mode 100644
index e3775e1..0000000
--- a/storage/browser/fileapi/file_system_url_request_job_factory.cc
+++ /dev/null
@@ -1,76 +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 "storage/browser/fileapi/file_system_url_request_job_factory.h"
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "net/url_request/url_request.h"
-#include "storage/browser/fileapi/file_system_dir_url_request_job.h"
-#include "storage/browser/fileapi/file_system_url_request_job.h"
-
-namespace storage {
-
-namespace {
-
-class FileSystemProtocolHandler
-    : public net::URLRequestJobFactory::ProtocolHandler {
- public:
-  FileSystemProtocolHandler(const std::string& storage_domain,
-                            FileSystemContext* context);
-  ~FileSystemProtocolHandler() override;
-
-  net::URLRequestJob* MaybeCreateJob(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override;
-
-  bool IsSafeRedirectTarget(const GURL& location) const override {
-    return false;
-  }
-
- private:
-  const std::string storage_domain_;
-
-  // No scoped_refptr because |file_system_context_| is owned by the
-  // ProfileIOData, which also owns this ProtocolHandler.
-  FileSystemContext* const file_system_context_;
-
-  DISALLOW_COPY_AND_ASSIGN(FileSystemProtocolHandler);
-};
-
-FileSystemProtocolHandler::FileSystemProtocolHandler(
-    const std::string& storage_domain,
-    FileSystemContext* context)
-    : storage_domain_(storage_domain),
-      file_system_context_(context) {
-  DCHECK(file_system_context_);
-}
-
-FileSystemProtocolHandler::~FileSystemProtocolHandler() = default;
-
-net::URLRequestJob* FileSystemProtocolHandler::MaybeCreateJob(
-    net::URLRequest* request, net::NetworkDelegate* network_delegate) const {
-  const std::string path = request->url().path();
-
-  // If the path ends with a /, we know it's a directory. If the path refers
-  // to a directory and gets dispatched to FileSystemURLRequestJob, that class
-  // redirects back here, by adding a / to the URL.
-  if (!path.empty() && path.back() == '/') {
-    return new FileSystemDirURLRequestJob(
-        request, network_delegate, storage_domain_, file_system_context_);
-  }
-  return new FileSystemURLRequestJob(
-      request, network_delegate, storage_domain_, file_system_context_);
-}
-
-}  // anonymous namespace
-
-std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>
-CreateFileSystemProtocolHandler(const std::string& storage_domain,
-                                FileSystemContext* context) {
-  DCHECK(context);
-  return std::make_unique<FileSystemProtocolHandler>(storage_domain, context);
-}
-
-}  // namespace storage
diff --git a/storage/browser/fileapi/file_system_url_request_job_factory.h b/storage/browser/fileapi/file_system_url_request_job_factory.h
deleted file mode 100644
index 61e1448..0000000
--- a/storage/browser/fileapi/file_system_url_request_job_factory.h
+++ /dev/null
@@ -1,29 +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 STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_URL_REQUEST_JOB_FACTORY_H_
-#define STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_URL_REQUEST_JOB_FACTORY_H_
-
-#include <memory>
-#include <string>
-
-#include "net/url_request/url_request_job_factory.h"
-
-#include "base/component_export.h"
-
-namespace storage {
-
-class FileSystemContext;
-
-// |context|'s lifetime should exceed the lifetime of the ProtocolHandler.
-// Currently, this is only used by ProfileIOData which owns |context| and the
-// ProtocolHandler.
-COMPONENT_EXPORT(STORAGE_BROWSER)
-std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>
-CreateFileSystemProtocolHandler(const std::string& storage_domain,
-                                FileSystemContext* context);
-
-}  // namespace storage
-
-#endif  // STORAGE_BROWSER_FILEAPI_FILE_SYSTEM_URL_REQUEST_JOB_FACTORY_H_
diff --git a/storage/browser/fileapi/file_system_url_request_job_unittest.cc b/storage/browser/fileapi/file_system_url_request_job_unittest.cc
deleted file mode 100644
index d231a1e..0000000
--- a/storage/browser/fileapi/file_system_url_request_job_unittest.cc
+++ /dev/null
@@ -1,488 +0,0 @@
-// 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.
-
-#include <stddef.h>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/format_macros.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/rand_util.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "net/base/load_flags.h"
-#include "net/base/mime_util.h"
-#include "net/base/net_errors.h"
-#include "net/base/request_priority.h"
-#include "net/http/http_byte_range.h"
-#include "net/http/http_request_headers.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_test_util.h"
-#include "storage/browser/fileapi/external_mount_points.h"
-#include "storage/browser/fileapi/file_system_context.h"
-#include "storage/browser/fileapi/file_system_file_util.h"
-#include "storage/browser/fileapi/file_system_url_request_job.h"
-#include "storage/browser/test/async_file_test_helper.h"
-#include "storage/browser/test/test_file_system_backend.h"
-#include "storage/browser/test/test_file_system_context.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using content::AsyncFileTestHelper;
-using storage::FileSystemContext;
-using storage::FileSystemURL;
-using storage::FileSystemURLRequestJob;
-
-namespace content {
-namespace {
-
-// We always use the TEMPORARY FileSystem in this test.
-const char kFileSystemURLPrefix[] = "filesystem:http://remote/temporary/";
-const char kTestFileData[] = "0123456789";
-
-void FillBuffer(char* buffer, size_t len) {
-  base::RandBytes(buffer, len);
-}
-
-const char kValidExternalMountPoint[] = "mnt_name";
-
-// An auto mounter that will try to mount anything for |storage_domain| =
-// "automount", but will only succeed for the mount point "mnt_name".
-bool TestAutoMountForURLRequest(
-    const storage::FileSystemRequestInfo& request_info,
-    const storage::FileSystemURL& filesystem_url,
-    base::OnceCallback<void(base::File::Error result)> callback) {
-  if (request_info.storage_domain != "automount")
-    return false;
-  std::vector<base::FilePath::StringType> components;
-  filesystem_url.path().GetComponents(&components);
-  std::string mount_point = base::FilePath(components[0]).AsUTF8Unsafe();
-
-  if (mount_point == kValidExternalMountPoint) {
-    storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
-        kValidExternalMountPoint,
-        storage::kFileSystemTypeTest,
-        storage::FileSystemMountOption(),
-        base::FilePath());
-    std::move(callback).Run(base::File::FILE_OK);
-  } else {
-    std::move(callback).Run(base::File::FILE_ERROR_NOT_FOUND);
-  }
-  return true;
-}
-
-class FileSystemURLRequestJobFactory : public net::URLRequestJobFactory {
- public:
-  FileSystemURLRequestJobFactory(const std::string& storage_domain,
-                                 FileSystemContext* context)
-      : storage_domain_(storage_domain), file_system_context_(context) {
-  }
-
-  net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
-      const std::string& scheme,
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return new storage::FileSystemURLRequestJob(
-        request, network_delegate, storage_domain_, file_system_context_);
-  }
-
-  net::URLRequestJob* MaybeInterceptRedirect(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate,
-      const GURL& location) const override {
-    return nullptr;
-  }
-
-  net::URLRequestJob* MaybeInterceptResponse(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    return nullptr;
-  }
-
-  bool IsHandledProtocol(const std::string& scheme) const override {
-    return true;
-  }
-
-  bool IsSafeRedirectTarget(const GURL& location) const override {
-    return false;
-  }
-
- private:
-  std::string storage_domain_;
-  FileSystemContext* file_system_context_;
-};
-
-}  // namespace
-
-class FileSystemURLRequestJobTest : public testing::Test {
- protected:
-  FileSystemURLRequestJobTest() : weak_factory_(this) {
-  }
-
-  void SetUp() override {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-    // We use the main thread so that we can get the root path synchronously.
-    // TODO(adamk): Run this on the FILE thread we've created as well.
-    file_system_context_ =
-        CreateFileSystemContextForTesting(nullptr, temp_dir_.GetPath());
-
-    file_system_context_->OpenFileSystem(
-        GURL("http://remote/"), storage::kFileSystemTypeTemporary,
-        storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
-        base::BindOnce(&FileSystemURLRequestJobTest::OnOpenFileSystem,
-                       weak_factory_.GetWeakPtr()));
-    base::RunLoop().RunUntilIdle();
-  }
-
-  void TearDown() override {
-    // FileReader posts a task to close the file in destructor.
-    base::RunLoop().RunUntilIdle();
-  }
-
-  void SetUpAutoMountContext() {
-    base::FilePath mnt_point =
-        temp_dir_.GetPath().AppendASCII("auto_mount_dir");
-    ASSERT_TRUE(base::CreateDirectory(mnt_point));
-
-    std::vector<std::unique_ptr<storage::FileSystemBackend>>
-        additional_providers;
-    additional_providers.push_back(std::make_unique<TestFileSystemBackend>(
-        base::ThreadTaskRunnerHandle::Get().get(), mnt_point));
-
-    std::vector<storage::URLRequestAutoMountHandler> handlers;
-    handlers.push_back(base::BindRepeating(&TestAutoMountForURLRequest));
-
-    file_system_context_ = CreateFileSystemContextWithAutoMountersForTesting(
-        base::ThreadTaskRunnerHandle::Get(),
-        base::ThreadTaskRunnerHandle::Get(), nullptr,
-        std::move(additional_providers), handlers, temp_dir_.GetPath());
-
-    ASSERT_EQ(static_cast<int>(sizeof(kTestFileData)) - 1,
-              base::WriteFile(mnt_point.AppendASCII("foo"), kTestFileData,
-                              sizeof(kTestFileData) - 1));
-  }
-
-  void OnOpenFileSystem(const GURL& root_url,
-                        const std::string& name,
-                        base::File::Error result) {
-    ASSERT_EQ(base::File::FILE_OK, result);
-  }
-
-  void TestRequestHelper(const GURL& url,
-                         const net::HttpRequestHeaders* headers,
-                         bool run_to_completion,
-                         FileSystemContext* file_system_context) {
-    delegate_.reset(new net::TestDelegate());
-
-    job_factory_.reset(new FileSystemURLRequestJobFactory(
-        url.GetOrigin().host(), file_system_context));
-    empty_context_.set_job_factory(job_factory_.get());
-
-    request_ = empty_context_.CreateRequest(url, net::DEFAULT_PRIORITY,
-                                            delegate_.get(),
-                                            TRAFFIC_ANNOTATION_FOR_TESTS);
-    if (headers)
-      request_->SetExtraRequestHeaders(*headers);
-
-    request_->Start();
-    ASSERT_TRUE(request_->is_pending());  // verify that we're starting async
-    if (run_to_completion)
-      delegate_->RunUntilComplete();
-  }
-
-  void TestRequest(const GURL& url) {
-    TestRequestHelper(url, nullptr, true, file_system_context_.get());
-  }
-
-  void TestRequestWithContext(const GURL& url,
-                              FileSystemContext* file_system_context) {
-    TestRequestHelper(url, nullptr, true, file_system_context);
-  }
-
-  void TestRequestWithHeaders(const GURL& url,
-                              const net::HttpRequestHeaders* headers) {
-    TestRequestHelper(url, headers, true, file_system_context_.get());
-  }
-
-  void TestRequestNoRun(const GURL& url) {
-    TestRequestHelper(url, nullptr, false, file_system_context_.get());
-  }
-
-  void CreateDirectory(const base::StringPiece& dir_name) {
-    FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
-        GURL("http://remote"),
-        storage::kFileSystemTypeTemporary,
-        base::FilePath().AppendASCII(dir_name));
-    ASSERT_EQ(
-        base::File::FILE_OK,
-        AsyncFileTestHelper::CreateDirectory(file_system_context_.get(), url));
-  }
-
-  void WriteFile(const base::StringPiece& file_name,
-                 const char* buf, int buf_size) {
-    FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
-        GURL("http://remote"),
-        storage::kFileSystemTypeTemporary,
-        base::FilePath().AppendASCII(file_name));
-    ASSERT_EQ(base::File::FILE_OK,
-              AsyncFileTestHelper::CreateFileWithData(
-                  file_system_context_.get(), url, buf, buf_size));
-  }
-
-  GURL CreateFileSystemURL(const std::string& path) {
-    return GURL(kFileSystemURLPrefix + path);
-  }
-
-  // Temp directory is at the top because it must be deleted last.
-  base::ScopedTempDir temp_dir_;
-
-  // The message loop must be deleted second to last.
-  base::MessageLoopForIO message_loop_;
-
-  scoped_refptr<storage::FileSystemContext> file_system_context_;
-
-  net::URLRequestContext empty_context_;
-  std::unique_ptr<FileSystemURLRequestJobFactory> job_factory_;
-
-  // NOTE: order matters, request must die before delegate
-  std::unique_ptr<net::TestDelegate> delegate_;
-  std::unique_ptr<net::URLRequest> request_;
-
-  base::WeakPtrFactory<FileSystemURLRequestJobTest> weak_factory_;
-};
-
-namespace {
-
-TEST_F(FileSystemURLRequestJobTest, FileTest) {
-  WriteFile("file1.dat", kTestFileData, base::size(kTestFileData) - 1);
-  TestRequest(CreateFileSystemURL("file1.dat"));
-
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_EQ(1, delegate_->response_started_count());
-  EXPECT_FALSE(delegate_->received_data_before_response());
-  EXPECT_EQ(kTestFileData, delegate_->data_received());
-  EXPECT_EQ(200, request_->GetResponseCode());
-  std::string cache_control;
-  request_->GetResponseHeaderByName("cache-control", &cache_control);
-  EXPECT_EQ("no-cache", cache_control);
-}
-
-TEST_F(FileSystemURLRequestJobTest, FileTestFullSpecifiedRange) {
-  const size_t buffer_size = 4000;
-  std::unique_ptr<char[]> buffer(new char[buffer_size]);
-  FillBuffer(buffer.get(), buffer_size);
-  WriteFile("bigfile", buffer.get(), buffer_size);
-
-  const size_t first_byte_position = 500;
-  const size_t last_byte_position = buffer_size - first_byte_position;
-  std::string partial_buffer_string(buffer.get() + first_byte_position,
-                                    buffer.get() + last_byte_position + 1);
-
-  net::HttpRequestHeaders headers;
-  headers.SetHeader(
-      net::HttpRequestHeaders::kRange,
-      net::HttpByteRange::Bounded(
-          first_byte_position, last_byte_position).GetHeaderValue());
-  TestRequestWithHeaders(CreateFileSystemURL("bigfile"), &headers);
-
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_EQ(1, delegate_->response_started_count());
-  EXPECT_FALSE(delegate_->received_data_before_response());
-  EXPECT_TRUE(partial_buffer_string == delegate_->data_received());
-}
-
-TEST_F(FileSystemURLRequestJobTest, FileTestHalfSpecifiedRange) {
-  const size_t buffer_size = 4000;
-  std::unique_ptr<char[]> buffer(new char[buffer_size]);
-  FillBuffer(buffer.get(), buffer_size);
-  WriteFile("bigfile", buffer.get(), buffer_size);
-
-  const size_t first_byte_position = 500;
-  std::string partial_buffer_string(buffer.get() + first_byte_position,
-                                    buffer.get() + buffer_size);
-
-  net::HttpRequestHeaders headers;
-  headers.SetHeader(
-      net::HttpRequestHeaders::kRange,
-      net::HttpByteRange::RightUnbounded(first_byte_position).GetHeaderValue());
-  TestRequestWithHeaders(CreateFileSystemURL("bigfile"), &headers);
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_EQ(1, delegate_->response_started_count());
-  EXPECT_FALSE(delegate_->received_data_before_response());
-  // Don't use EXPECT_EQ, it will print out a lot of garbage if check failed.
-  EXPECT_TRUE(partial_buffer_string == delegate_->data_received());
-}
-
-TEST_F(FileSystemURLRequestJobTest, FileTestMultipleRangesNotSupported) {
-  WriteFile("file1.dat", kTestFileData, base::size(kTestFileData) - 1);
-  net::HttpRequestHeaders headers;
-  headers.SetHeader(net::HttpRequestHeaders::kRange,
-                    "bytes=0-5,10-200,200-300");
-  TestRequestWithHeaders(CreateFileSystemURL("file1.dat"), &headers);
-  EXPECT_TRUE(delegate_->request_failed());
-  EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE,
-            delegate_->request_status());
-}
-
-TEST_F(FileSystemURLRequestJobTest, RangeOutOfBounds) {
-  WriteFile("file1.dat", kTestFileData, base::size(kTestFileData) - 1);
-  net::HttpRequestHeaders headers;
-  headers.SetHeader(
-      net::HttpRequestHeaders::kRange,
-      net::HttpByteRange::Bounded(500, 1000).GetHeaderValue());
-  TestRequestWithHeaders(CreateFileSystemURL("file1.dat"), &headers);
-
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_TRUE(delegate_->request_failed());
-  EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE,
-            delegate_->request_status());
-}
-
-TEST_F(FileSystemURLRequestJobTest, FileDirRedirect) {
-  CreateDirectory("dir");
-  TestRequestNoRun(CreateFileSystemURL("dir"));
-  delegate_->RunUntilRedirect();
-
-  EXPECT_EQ(1, delegate_->received_redirect_count());
-  EXPECT_FALSE(delegate_->request_failed());
-
-  // We've deferred the redirect; now cancel the request to avoid following it.
-  request_->Cancel();
-  delegate_->RunUntilComplete();
-}
-
-TEST_F(FileSystemURLRequestJobTest, InvalidURL) {
-  TestRequest(GURL("filesystem:/foo/bar/baz"));
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_TRUE(delegate_->request_failed());
-  EXPECT_EQ(net::ERR_INVALID_URL, delegate_->request_status());
-}
-
-TEST_F(FileSystemURLRequestJobTest, NoSuchRoot) {
-  TestRequest(GURL("filesystem:http://remote/persistent/somefile"));
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_TRUE(delegate_->request_failed());
-  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, delegate_->request_status());
-}
-
-TEST_F(FileSystemURLRequestJobTest, NoSuchFile) {
-  TestRequest(CreateFileSystemURL("somefile"));
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_TRUE(delegate_->request_failed());
-  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, delegate_->request_status());
-}
-
-TEST_F(FileSystemURLRequestJobTest, Cancel) {
-  WriteFile("file1.dat", kTestFileData, base::size(kTestFileData) - 1);
-  TestRequestNoRun(CreateFileSystemURL("file1.dat"));
-
-  // Run StartAsync() and only StartAsync().
-  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
-                                                  request_.release());
-  base::RunLoop().RunUntilIdle();
-  // If we get here, success! we didn't crash!
-}
-
-TEST_F(FileSystemURLRequestJobTest, GetMimeType) {
-  const char kFilename[] = "hoge.html";
-
-  std::string mime_type_direct;
-  base::FilePath::StringType extension =
-      base::FilePath().AppendASCII(kFilename).Extension();
-  if (!extension.empty())
-    extension = extension.substr(1);
-  EXPECT_TRUE(net::GetWellKnownMimeTypeFromExtension(
-      extension, &mime_type_direct));
-
-  TestRequest(CreateFileSystemURL(kFilename));
-
-  std::string mime_type_from_job;
-  request_->GetMimeType(&mime_type_from_job);
-  EXPECT_EQ(mime_type_direct, mime_type_from_job);
-}
-
-TEST_F(FileSystemURLRequestJobTest, Incognito) {
-  WriteFile("file", kTestFileData, base::size(kTestFileData) - 1);
-
-  // Creates a new filesystem context for incognito mode.
-  scoped_refptr<FileSystemContext> file_system_context =
-      CreateIncognitoFileSystemContextForTesting(
-          base::ThreadTaskRunnerHandle::Get(),
-          base::ThreadTaskRunnerHandle::Get(), nullptr, temp_dir_.GetPath());
-
-  // The request should return NOT_FOUND error if it's in incognito mode.
-  TestRequestWithContext(CreateFileSystemURL("file"),
-                         file_system_context.get());
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_TRUE(delegate_->request_failed());
-  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, delegate_->request_status());
-
-  // Make sure it returns success with regular (non-incognito) context.
-  TestRequest(CreateFileSystemURL("file"));
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_EQ(kTestFileData, delegate_->data_received());
-  EXPECT_EQ(200, request_->GetResponseCode());
-}
-
-TEST_F(FileSystemURLRequestJobTest, AutoMountFileTest) {
-  SetUpAutoMountContext();
-  TestRequest(GURL("filesystem:http://automount/external/mnt_name/foo"));
-
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_EQ(1, delegate_->response_started_count());
-  EXPECT_FALSE(delegate_->received_data_before_response());
-  EXPECT_EQ(kTestFileData, delegate_->data_received());
-  EXPECT_EQ(200, request_->GetResponseCode());
-  std::string cache_control;
-  request_->GetResponseHeaderByName("cache-control", &cache_control);
-  EXPECT_EQ("no-cache", cache_control);
-
-  ASSERT_TRUE(
-      storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
-          kValidExternalMountPoint));
-}
-
-TEST_F(FileSystemURLRequestJobTest, AutoMountInvalidRoot) {
-  SetUpAutoMountContext();
-  TestRequest(GURL("filesystem:http://automount/external/invalid/foo"));
-
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_TRUE(delegate_->request_failed());
-  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, delegate_->request_status());
-
-  ASSERT_FALSE(
-      storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
-          "invalid"));
-}
-
-TEST_F(FileSystemURLRequestJobTest, AutoMountNoHandler) {
-  SetUpAutoMountContext();
-  TestRequest(GURL("filesystem:http://noauto/external/mnt_name/foo"));
-
-  ASSERT_FALSE(request_->is_pending());
-  EXPECT_TRUE(delegate_->request_failed());
-  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, delegate_->request_status());
-
-  ASSERT_FALSE(
-      storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
-          kValidExternalMountPoint));
-}
-
-}  // namespace
-}  // namespace content
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index a07f9bb..5519adc 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -24075,1992 +24075,6 @@
       }
     ]
   },
-  "Win10 FYI Exp Release (Intel HD 630)": {
-    "isolated_scripts": [
-      {
-        "args": [
-          "noop_sleep",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "noop_sleep_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:5912-24.20.100.6286",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      }
-    ]
-  },
-  "Win10 FYI Exp Release (NVIDIA)": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 4
-        },
-        "test": "angle_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "angle_gles1_conformance_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "angle_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-retry-limit=0"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "angle_white_box_tests"
-      },
-      {
-        "args": [
-          "--enable-gpu",
-          "--test-launcher-bot-mode",
-          "--test-launcher-jobs=1",
-          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "tab_capture_end2end_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-cmd-decoder=validating"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gl_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-cmd-decoder=passthrough"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gl_tests_passthrough",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gl_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gl_unittests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gles2_conform_test"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-angle=d3d9"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gles2_conform_d3d9_test",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gles2_conform_test"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-angle=gl",
-          "--disable-gpu-sandbox"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gles2_conform_gl_test",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gles2_conform_test"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gpu_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "swiftshader_unittests"
-      },
-      {
-        "args": [
-          "--use-angle=d3d11",
-          "--use-test-data-path",
-          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "video_decode_accelerator_d3d11_unittest",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "video_decode_accelerator_unittest"
-      },
-      {
-        "args": [
-          "--use-angle=d3d9",
-          "--use-test-data-path",
-          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "video_decode_accelerator_d3d9_unittest",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "video_decode_accelerator_unittest"
-      },
-      {
-        "args": [
-          "--use-angle=gl",
-          "--use-test-data-path",
-          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "video_decode_accelerator_gl_unittest",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "video_decode_accelerator_unittest"
-      },
-      {
-        "args": [
-          "--ignore-runtime-requirements=*"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "xr_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "xr_browser_tests"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "args": [
-          "--gtest-benchmark-name=angle_perftests",
-          "-v",
-          "--one-frame-only"
-        ],
-        "isolate_name": "angle_perftests",
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "angle_perftests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        }
-      },
-      {
-        "args": [
-          "context_lost",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "context_lost_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "depth_capture",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "depth_capture_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "gpu_process",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "gpu_process_launch_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "hardware_accelerated_feature",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "hardware_accelerated_feature_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "info_collection",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--expected-vendor-id",
-          "10de",
-          "--expected-device-id",
-          "1cb3"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "info_collection_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "maps",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--dont-restore-color-profile-after-test",
-          "--os-type",
-          "win",
-          "--build-revision",
-          "${got_revision}",
-          "--test-machine-name",
-          "${buildername}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "maps_pixel_test",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=passthrough_command_buffer_perftests",
-          "-v",
-          "--use-cmd-decoder=passthrough",
-          "--use-angle=gl-null",
-          "--fast-run"
-        ],
-        "isolate_name": "command_buffer_perftests",
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "passthrough_command_buffer_perftests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        }
-      },
-      {
-        "args": [
-          "pixel",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--dont-restore-color-profile-after-test",
-          "--os-type",
-          "win",
-          "--build-revision",
-          "${got_revision}",
-          "--test-machine-name",
-          "${buildername}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "pixel_skia_gold_test",
-        "precommit_args": [
-          "--review-patch-issue",
-          "${patch_issue}",
-          "--review-patch-set",
-          "${patch_set}",
-          "--buildbucket-build-id",
-          "${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        }
-      },
-      {
-        "args": [
-          "../../tools/perf/run_benchmark",
-          "--benchmarks=rendering.desktop"
-        ],
-        "experiment_percentage": 100,
-        "isolate_name": "rendering_representative_perf_tests",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "rendering_representative_perf_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        }
-      },
-      {
-        "args": [
-          "screenshot_sync",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--dont-restore-color-profile-after-test"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "screenshot_sync_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "trace_test",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "trace_test",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=validating_command_buffer_perftests",
-          "-v",
-          "--use-cmd-decoder=validating",
-          "--use-stub",
-          "--fast-run"
-        ],
-        "isolate_name": "command_buffer_perftests",
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "validating_command_buffer_perftests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough",
-          "--webgl-conformance-version=2.0.1",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl2_conformance_gl_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 20
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--webgl-conformance-version=2.0.1",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl2_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 20
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d11 --use-cmd-decoder=validating"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_d3d11_validating_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=d3d9 --use-cmd-decoder=passthrough"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_d3d9_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d9 --use-cmd-decoder=validating"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_d3d9_validating_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_gl_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=vulkan --use-cmd-decoder=passthrough"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_vulkan_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-26.21.14.3102",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      }
-    ]
-  },
-  "Win10 FYI Release (AMD RX 550)": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 4
-        },
-        "test": "angle_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "angle_gles1_conformance_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "angle_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-retry-limit=0"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "angle_white_box_tests"
-      },
-      {
-        "args": [
-          "--enable-gpu",
-          "--test-launcher-bot-mode",
-          "--test-launcher-jobs=1",
-          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "tab_capture_end2end_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-cmd-decoder=validating"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gl_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-cmd-decoder=passthrough"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gl_tests_passthrough",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gl_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gl_unittests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gles2_conform_test"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-angle=d3d9"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gles2_conform_d3d9_test",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gles2_conform_test"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-angle=gl",
-          "--disable-gpu-sandbox"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gles2_conform_gl_test",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gles2_conform_test"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gpu_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "swiftshader_unittests"
-      },
-      {
-        "args": [
-          "--use-angle=d3d11",
-          "--use-test-data-path",
-          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "video_decode_accelerator_d3d11_unittest",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "video_decode_accelerator_unittest"
-      },
-      {
-        "args": [
-          "--use-angle=d3d9",
-          "--use-test-data-path",
-          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "video_decode_accelerator_d3d9_unittest",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "video_decode_accelerator_unittest"
-      },
-      {
-        "args": [
-          "--use-angle=gl",
-          "--use-test-data-path",
-          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "video_decode_accelerator_gl_unittest",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "video_decode_accelerator_unittest"
-      },
-      {
-        "args": [
-          "--ignore-runtime-requirements=*"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "xr_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "xr_browser_tests"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "args": [
-          "context_lost",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "context_lost_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "depth_capture",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "depth_capture_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "gpu_process",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "gpu_process_launch_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "hardware_accelerated_feature",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "hardware_accelerated_feature_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "info_collection",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--expected-vendor-id",
-          "1002",
-          "--expected-device-id",
-          "699f"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "info_collection_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "maps",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--dont-restore-color-profile-after-test",
-          "--os-type",
-          "win",
-          "--build-revision",
-          "${got_revision}",
-          "--test-machine-name",
-          "${buildername}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "maps_pixel_test",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "pixel",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--dont-restore-color-profile-after-test",
-          "--os-type",
-          "win",
-          "--build-revision",
-          "${got_revision}",
-          "--test-machine-name",
-          "${buildername}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "pixel_skia_gold_test",
-        "precommit_args": [
-          "--review-patch-issue",
-          "${patch_issue}",
-          "--review-patch-set",
-          "${patch_set}",
-          "--buildbucket-build-id",
-          "${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        }
-      },
-      {
-        "args": [
-          "screenshot_sync",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--dont-restore-color-profile-after-test"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "screenshot_sync_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "trace_test",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "trace_test",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--webgl-conformance-version=2.0.1",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl2_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 20
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=d3d9 --use-cmd-decoder=passthrough"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_d3d9_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d9 --use-cmd-decoder=validating"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_d3d9_validating_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_gl_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=vulkan --use-cmd-decoder=passthrough"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_vulkan_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      }
-    ]
-  },
   "Win10 FYI Release (Intel HD 630)": {
     "gtest_tests": [
       {
@@ -27006,1031 +25020,6 @@
       }
     ]
   },
-  "Win10 FYI Release (NVIDIA GeForce GTX 1660)": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 4
-        },
-        "test": "angle_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "angle_gles1_conformance_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "angle_unittests"
-      },
-      {
-        "args": [
-          "--test-launcher-retry-limit=0"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "angle_white_box_tests"
-      },
-      {
-        "args": [
-          "--enable-gpu",
-          "--test-launcher-bot-mode",
-          "--test-launcher-jobs=1",
-          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "tab_capture_end2end_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0",
-          "--enable-backend-validation"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "dawn_end2end_validation_layers_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0",
-          "--use-wire"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "dawn_end2end_wire_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-cmd-decoder=validating"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gl_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-cmd-decoder=passthrough"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gl_tests_passthrough",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gl_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gl_unittests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gles2_conform_test"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-angle=d3d9"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gles2_conform_d3d9_test",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gles2_conform_test"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
-          "--use-angle=gl",
-          "--disable-gpu-sandbox"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gles2_conform_gl_test",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gles2_conform_test"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "gpu_unittests"
-      },
-      {
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "swiftshader_unittests"
-      },
-      {
-        "args": [
-          "--use-angle=d3d11",
-          "--use-test-data-path",
-          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "video_decode_accelerator_d3d11_unittest",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "video_decode_accelerator_unittest"
-      },
-      {
-        "args": [
-          "--use-angle=d3d9",
-          "--use-test-data-path",
-          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "video_decode_accelerator_d3d9_unittest",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "video_decode_accelerator_unittest"
-      },
-      {
-        "args": [
-          "--use-angle=gl",
-          "--use-test-data-path",
-          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "video_decode_accelerator_gl_unittest",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "video_decode_accelerator_unittest"
-      },
-      {
-        "args": [
-          "--ignore-runtime-requirements=*"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "xr_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600
-        },
-        "test": "xr_browser_tests"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "args": [
-          "context_lost",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "context_lost_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "depth_capture",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "depth_capture_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "gpu_process",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "gpu_process_launch_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "hardware_accelerated_feature",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "hardware_accelerated_feature_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "info_collection",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--expected-vendor-id",
-          "10de",
-          "--expected-device-id",
-          "2184"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "info_collection_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "maps",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--dont-restore-color-profile-after-test",
-          "--os-type",
-          "win",
-          "--build-revision",
-          "${got_revision}",
-          "--test-machine-name",
-          "${buildername}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "maps_pixel_test",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "pixel",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--dont-restore-color-profile-after-test",
-          "--os-type",
-          "win",
-          "--build-revision",
-          "${got_revision}",
-          "--test-machine-name",
-          "${buildername}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "pixel_skia_gold_test",
-        "precommit_args": [
-          "--review-patch-issue",
-          "${patch_issue}",
-          "--review-patch-set",
-          "${patch_set}",
-          "--buildbucket-build-id",
-          "${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        }
-      },
-      {
-        "args": [
-          "screenshot_sync",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--dont-restore-color-profile-after-test"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "screenshot_sync_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "trace_test",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "trace_test",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough",
-          "--webgl-conformance-version=2.0.1",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl2_conformance_gl_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 20
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
-          "--webgl-conformance-version=2.0.1",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl2_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 20
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d11 --use-cmd-decoder=validating"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_d3d11_validating_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=d3d9 --use-cmd-decoder=passthrough"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_d3d9_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d9 --use-cmd-decoder=validating"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_d3d9_validating_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_gl_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=vulkan --use-cmd-decoder=passthrough"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_vulkan_passthrough_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "idempotent": false,
-          "shards": 2
-        }
-      }
-    ]
-  },
   "Win10 FYI Release (NVIDIA)": {
     "gtest_tests": [
       {
@@ -29971,6 +26960,3963 @@
       }
     ]
   },
+  "Win10 FYI x64 Exp Release (Intel HD 630)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "shards": 4
+        },
+        "test": "angle_end2end_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_gles1_conformance_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_white_box_tests"
+      },
+      {
+        "args": [
+          "--enable-gpu",
+          "--test-launcher-bot-mode",
+          "--test-launcher-jobs=1",
+          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "tab_capture_end2end_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=validating"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=passthrough"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gl_tests_passthrough",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_unittests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-angle=d3d9"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gles2_conform_d3d9_test",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-angle=gl",
+          "--disable-gpu-sandbox"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gles2_conform_gl_test",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gpu_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "swiftshader_unittests"
+      },
+      {
+        "args": [
+          "--use-angle=d3d11",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d11_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--use-angle=d3d9",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d9_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--ignore-runtime-requirements=*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "xr_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "xr_browser_tests"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "--gtest-benchmark-name=angle_perftests",
+          "-v",
+          "--one-frame-only"
+        ],
+        "isolate_name": "angle_perftests",
+        "merge": {
+          "args": [
+            "--smoke-test-mode"
+          ],
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "angle_perftests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        }
+      },
+      {
+        "args": [
+          "context_lost",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "context_lost_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "depth_capture",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "depth_capture_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "gpu_process",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "gpu_process_launch_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "hardware_accelerated_feature_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "info_collection",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--expected-vendor-id",
+          "8086",
+          "--expected-device-id",
+          "5912"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "info_collection_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "maps",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "maps_pixel_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "pixel_skia_gold_test",
+        "precommit_args": [
+          "--review-patch-issue",
+          "${patch_issue}",
+          "--review-patch-set",
+          "${patch_set}",
+          "--buildbucket-build-id",
+          "${buildbucket_build_id}"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
+        }
+      },
+      {
+        "args": [
+          "power",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "power_measurement_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "../../tools/perf/run_benchmark",
+          "--benchmarks=rendering.desktop"
+        ],
+        "experiment_percentage": 100,
+        "isolate_name": "rendering_representative_perf_tests",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "rendering_representative_perf_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        }
+      },
+      {
+        "args": [
+          "screenshot_sync",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "screenshot_sync_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "trace_test",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "trace_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=d3d11 --use-cmd-decoder=validating",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_d3d11_validating_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=d3d9 --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_d3d9_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=vulkan --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_vulkan_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "8086:5912-24.20.100.6286",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      }
+    ]
+  },
+  "Win10 FYI x64 Exp Release (NVIDIA)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "shards": 4
+        },
+        "test": "angle_end2end_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_gles1_conformance_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_white_box_tests"
+      },
+      {
+        "args": [
+          "--enable-gpu",
+          "--test-launcher-bot-mode",
+          "--test-launcher-jobs=1",
+          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "tab_capture_end2end_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=validating"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=passthrough"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gl_tests_passthrough",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_unittests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-angle=d3d9"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gles2_conform_d3d9_test",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-angle=gl",
+          "--disable-gpu-sandbox"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gles2_conform_gl_test",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gpu_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "swiftshader_unittests"
+      },
+      {
+        "args": [
+          "--use-angle=d3d11",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d11_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--use-angle=d3d9",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d9_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--use-angle=gl",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_gl_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--ignore-runtime-requirements=*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "xr_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "xr_browser_tests"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "--gtest-benchmark-name=angle_perftests",
+          "-v",
+          "--one-frame-only"
+        ],
+        "isolate_name": "angle_perftests",
+        "merge": {
+          "args": [
+            "--smoke-test-mode"
+          ],
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "angle_perftests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        }
+      },
+      {
+        "args": [
+          "context_lost",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "context_lost_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "depth_capture",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "depth_capture_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "gpu_process",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "gpu_process_launch_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "hardware_accelerated_feature_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "info_collection",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--expected-vendor-id",
+          "10de",
+          "--expected-device-id",
+          "1cb3"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "info_collection_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "maps",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "maps_pixel_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "--gtest-benchmark-name=passthrough_command_buffer_perftests",
+          "-v",
+          "--use-cmd-decoder=passthrough",
+          "--use-angle=gl-null",
+          "--fast-run"
+        ],
+        "isolate_name": "command_buffer_perftests",
+        "merge": {
+          "args": [
+            "--smoke-test-mode"
+          ],
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "passthrough_command_buffer_perftests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        }
+      },
+      {
+        "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "pixel_skia_gold_test",
+        "precommit_args": [
+          "--review-patch-issue",
+          "${patch_issue}",
+          "--review-patch-set",
+          "${patch_set}",
+          "--buildbucket-build-id",
+          "${buildbucket_build_id}"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
+        }
+      },
+      {
+        "args": [
+          "../../tools/perf/run_benchmark",
+          "--benchmarks=rendering.desktop"
+        ],
+        "experiment_percentage": 100,
+        "isolate_name": "rendering_representative_perf_tests",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "rendering_representative_perf_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        }
+      },
+      {
+        "args": [
+          "screenshot_sync",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "screenshot_sync_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "trace_test",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "trace_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "--gtest-benchmark-name=validating_command_buffer_perftests",
+          "-v",
+          "--use-cmd-decoder=validating",
+          "--use-stub",
+          "--fast-run"
+        ],
+        "isolate_name": "command_buffer_perftests",
+        "merge": {
+          "args": [
+            "--smoke-test-mode"
+          ],
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "validating_command_buffer_perftests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d11 --use-cmd-decoder=validating"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_d3d11_validating_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=d3d9 --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_d3d9_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d9 --use-cmd-decoder=validating"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_d3d9_validating_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=vulkan --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_vulkan_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:1cb3-26.21.14.3102",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      }
+    ]
+  },
+  "Win10 FYI x64 Release (AMD RX 550)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "shards": 4
+        },
+        "test": "angle_end2end_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_gles1_conformance_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_white_box_tests"
+      },
+      {
+        "args": [
+          "--enable-gpu",
+          "--test-launcher-bot-mode",
+          "--test-launcher-jobs=1",
+          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "tab_capture_end2end_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=validating"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=passthrough"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gl_tests_passthrough",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_unittests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-angle=d3d9"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gles2_conform_d3d9_test",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-angle=gl",
+          "--disable-gpu-sandbox"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gles2_conform_gl_test",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gpu_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "swiftshader_unittests"
+      },
+      {
+        "args": [
+          "--use-angle=d3d11",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d11_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--use-angle=d3d9",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d9_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--use-angle=gl",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_gl_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--ignore-runtime-requirements=*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "xr_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "xr_browser_tests"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "context_lost",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "context_lost_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "depth_capture",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "depth_capture_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "gpu_process",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "gpu_process_launch_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "hardware_accelerated_feature_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "info_collection",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--expected-vendor-id",
+          "1002",
+          "--expected-device-id",
+          "699f"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "info_collection_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "maps",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "maps_pixel_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "pixel_skia_gold_test",
+        "precommit_args": [
+          "--review-patch-issue",
+          "${patch_issue}",
+          "--review-patch-set",
+          "${patch_set}",
+          "--buildbucket-build-id",
+          "${buildbucket_build_id}"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
+        }
+      },
+      {
+        "args": [
+          "screenshot_sync",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "screenshot_sync_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "trace_test",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "trace_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=d3d9 --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_d3d9_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d9 --use-cmd-decoder=validating"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_d3d9_validating_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=vulkan --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_vulkan_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "1002:699f",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      }
+    ]
+  },
+  "Win10 FYI x64 Release (NVIDIA GeForce GTX 1660)": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "shards": 4
+        },
+        "test": "angle_end2end_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_gles1_conformance_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "angle_white_box_tests"
+      },
+      {
+        "args": [
+          "--enable-gpu",
+          "--test-launcher-bot-mode",
+          "--test-launcher-jobs=1",
+          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "tab_capture_end2end_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "dawn_end2end_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0",
+          "--enable-backend-validation"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_validation_layers_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "dawn_end2end_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--test-launcher-retry-limit=0",
+          "--use-wire"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "dawn_end2end_wire_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "dawn_end2end_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=validating"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-cmd-decoder=passthrough"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gl_tests_passthrough",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_tests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gl_unittests"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-angle=d3d9"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gles2_conform_d3d9_test",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "args": [
+          "--use-gpu-in-tests",
+          "--use-angle=gl",
+          "--disable-gpu-sandbox"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "gles2_conform_gl_test",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gles2_conform_test"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "gpu_unittests"
+      },
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "swiftshader_unittests"
+      },
+      {
+        "args": [
+          "--use-angle=d3d11",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d11_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--use-angle=d3d9",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_d3d9_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--use-angle=gl",
+          "--use-test-data-path",
+          "--test_video_data=test-25fps.h264:320:240:250:258:::1"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "video_decode_accelerator_gl_unittest",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "video_decode_accelerator_unittest"
+      },
+      {
+        "args": [
+          "--ignore-runtime-requirements=*"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "name": "xr_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "xr_browser_tests"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "context_lost",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "context_lost_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "depth_capture",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "depth_capture_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "gpu_process",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "gpu_process_launch_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "hardware_accelerated_feature",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "hardware_accelerated_feature_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "info_collection",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--expected-vendor-id",
+          "10de",
+          "--expected-device-id",
+          "2184"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "info_collection_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "maps",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "maps_pixel_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "pixel",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test",
+          "--os-type",
+          "win",
+          "--build-revision",
+          "${got_revision}",
+          "--test-machine-name",
+          "${buildername}"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "pixel_skia_gold_test",
+        "precommit_args": [
+          "--review-patch-issue",
+          "${patch_issue}",
+          "--review-patch-set",
+          "${patch_set}",
+          "--buildbucket-build-id",
+          "${buildbucket_build_id}"
+        ],
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
+        }
+      },
+      {
+        "args": [
+          "screenshot_sync",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--dont-restore-color-profile-after-test"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "screenshot_sync_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "trace_test",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "trace_test",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc",
+          "--webgl-conformance-version=2.0.1",
+          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl2_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d11 --use-cmd-decoder=validating"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_d3d11_validating_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=d3d9 --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_d3d9_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d9 --use-cmd-decoder=validating"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_d3d9_validating_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_gl_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      },
+      {
+        "args": [
+          "webgl_conformance",
+          "--show-stdout",
+          "--browser=release_x64",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=vulkan --use-cmd-decoder=passthrough"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "webgl_conformance_vulkan_passthrough_tests",
+        "should_retry_with_patch": false,
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "containment_type": "AUTO",
+          "dimension_sets": [
+            {
+              "gpu": "10de:2184",
+              "os": "Windows-10",
+              "pool": "Chrome-GPU"
+            }
+          ],
+          "expiration": 21600,
+          "idempotent": false,
+          "shards": 2
+        }
+      }
+    ]
+  },
   "Win7 ANGLE Tryserver (AMD)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 975b6e3..7fe4aa9 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1590,7 +1590,7 @@
       'ANGLE GPU Win10 Release (Intel HD 630)',
       'Optional Win10 Release (Intel HD 630)',
       'Win10 FYI Release (Intel HD 630)',
-      'Win10 FYI Exp Release (Intel HD 630)',
+      'Win10 FYI x64 Exp Release (Intel HD 630)',
     ],
   },
   'viz_unittests': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 09c8fd8..478688d 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -3551,16 +3551,18 @@
       },
     },
 
-    'gpu_noop_sleep_telemetry_test': {
+    # Temporarily disabled, since all experimental bots are active now.
+    # TODO(ynovikov): Re-enable once Win10 Intel is switched to x64 crbug.com/988833
+    #'gpu_noop_sleep_telemetry_test': {
       # The former GPU-specific generator script contained logic to
       # detect whether the so-called "experimental" GPU bots, which test
       # newer driver versions, were identical to the "stable" versions
       # of the bots, and if so to mirror their configurations. We prefer
       # to keep this new script simpler and to just configure this by
       # hand in waterfalls.pyl.
-      'noop_sleep': {
-      }
-    },
+      #'noop_sleep': {
+      #}
+    #},
 
     'gpu_skia_renderer_telemetry_tests': {
       'skia_renderer_pixel_skia_gold_test': {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index d5f424d9..7d44c51 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -3058,49 +3058,6 @@
           'gpu_telemetry_tests': 'gpu_fyi_win_debug_telemetry_tests',
         },
       },
-      'Win10 FYI Exp Release (Intel HD 630)': {
-        'os_type': 'win',
-        'browser_config': 'release',
-        'mixins': [
-          'limited_capacity_bot',
-          'win10_intel_hd_630_experimental',
-        ],
-        # Currently the experimental driver is identical to the stable
-        # driver. If it's upgraded, change these test_suites to be the same as
-        # 'Win10 FYI Release (Intel HD 630)'.
-        'test_suites': {
-          'gpu_telemetry_tests': 'gpu_noop_sleep_telemetry_test',
-        },
-      },
-      # TODO(kbr): "Experimental" caused too-long path names pre-LUCI.
-      # crbug.com/812000
-      'Win10 FYI Exp Release (NVIDIA)': {
-        'os_type': 'win',
-        'browser_config': 'release',
-        'mixins': [
-          'limited_capacity_bot',
-          'win10_nvidia_quadro_p400_experimental',
-        ],
-        'test_suites': {
-          'gtest_tests': 'gpu_fyi_win_gtests',
-          'isolated_scripts': 'gpu_angle_fyi_win_optional_and_representative_perf_isolated_scripts',
-          'gpu_telemetry_tests': 'gpu_fyi_win_release_telemetry_tests',
-        },
-      },
-      'Win10 FYI Release (AMD RX 550)': {
-        # This bot currently only has one piece of hardware behind it,
-        # and is being qualified for potential scale-out.
-        'os_type': 'win',
-        'browser_config': 'release',
-        'mixins': [
-          'limited_capacity_bot',
-          'win10_amd_rx_550',
-        ],
-        'test_suites': {
-          'gtest_tests': 'gpu_fyi_win_gtests',
-          'gpu_telemetry_tests': 'gpu_fyi_win_amd_telemetry_tests',
-        },
-      },
       'Win10 FYI Release (Intel HD 630)': {
         'os_type': 'win',
         'browser_config': 'release',
@@ -3113,20 +3070,6 @@
           'gpu_telemetry_tests': 'gpu_fyi_win_intel_release_telemetry_tests',
         },
       },
-      'Win10 FYI Release (NVIDIA GeForce GTX 1660)': {
-        # This bot currently only has one piece of hardware behind it,
-        # and is being qualified for potential scale-out.
-        'os_type': 'win',
-        'browser_config': 'release',
-        'mixins': [
-          'limited_capacity_bot',
-          'win10_nvidia_geforce_gtx_1660',
-        ],
-        'test_suites': {
-          'gtest_tests': 'gpu_fyi_win_and_dawn_gtests',
-          'gpu_telemetry_tests': 'gpu_fyi_win_release_telemetry_tests',
-        },
-      },
       'Win10 FYI Release (NVIDIA)': {
         'os_type': 'win',
         'browser_config': 'release',
@@ -3170,6 +3113,62 @@
         },
         'use_multi_dimension_trigger_script': True,
       },
+      # TODO(kbr): "Experimental" caused too-long path names pre-LUCI.
+      # crbug.com/812000
+      'Win10 FYI x64 Exp Release (Intel HD 630)': {
+        'os_type': 'win',
+        'browser_config': 'release_x64',
+        'mixins': [
+          'limited_capacity_bot',
+          'win10_intel_hd_630_experimental',
+        ],
+        'test_suites': {
+          'gtest_tests': 'gpu_fyi_win_gtests',
+          'isolated_scripts': 'gpu_angle_and_desktop_representative_perf_fyi_isolated_scripts',
+          'gpu_telemetry_tests': 'gpu_fyi_win_intel_release_telemetry_tests',
+        },
+      },
+      'Win10 FYI x64 Exp Release (NVIDIA)': {
+        'os_type': 'win',
+        'browser_config': 'release_x64',
+        'mixins': [
+          'limited_capacity_bot',
+          'win10_nvidia_quadro_p400_experimental',
+        ],
+        'test_suites': {
+          'gtest_tests': 'gpu_fyi_win_gtests',
+          'isolated_scripts': 'gpu_angle_fyi_win_optional_and_representative_perf_isolated_scripts',
+          'gpu_telemetry_tests': 'gpu_fyi_win_release_telemetry_tests',
+        },
+      },
+      'Win10 FYI x64 Release (AMD RX 550)': {
+        # This bot currently only has one piece of hardware behind it,
+        # and is being qualified for potential scale-out.
+        'os_type': 'win',
+        'browser_config': 'release_x64',
+        'mixins': [
+          'limited_capacity_bot',
+          'win10_amd_rx_550',
+        ],
+        'test_suites': {
+          'gtest_tests': 'gpu_fyi_win_gtests',
+          'gpu_telemetry_tests': 'gpu_fyi_win_amd_telemetry_tests',
+        },
+      },
+      'Win10 FYI x64 Release (NVIDIA GeForce GTX 1660)': {
+        # This bot currently only has one piece of hardware behind it,
+        # and is being qualified for potential scale-out.
+        'os_type': 'win',
+        'browser_config': 'release_x64',
+        'mixins': [
+          'limited_capacity_bot',
+          'win10_nvidia_geforce_gtx_1660',
+        ],
+        'test_suites': {
+          'gtest_tests': 'gpu_fyi_win_and_dawn_gtests',
+          'gpu_telemetry_tests': 'gpu_fyi_win_release_telemetry_tests',
+        },
+      },
       # This tryserver doesn't actually exist; it's a separate
       # configuration from the Win AMD bot on this waterfall because we
       # don't have enough tryserver capacity to run all the tests from
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 9ec2b983..b0ae402 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -155,6 +155,21 @@
             ]
         }
     ],
+    "AndroidIdentityDisc": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "IdentityDisc"
+                    ]
+                }
+            ]
+        }
+    ],
     "AndroidInProductHelpContextualSearchPromotePanelOpen": [
         {
             "platforms": [
diff --git a/third_party/android_protobuf/OWNERS b/third_party/android_protobuf/OWNERS
index 89c37e7..047c73c 100644
--- a/third_party/android_protobuf/OWNERS
+++ b/third_party/android_protobuf/OWNERS
@@ -1,2 +1,4 @@
 meek@chromium.org
 nyquist@chromium.org
+# COMPONENT: Internals
+# TEAM: chromium-dev@chromium.org
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 5bf7ba5..11e64ea 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -167,6 +167,7 @@
     "platform/modules/service_worker/web_service_worker_provider.h",
     "platform/modules/service_worker/web_service_worker_provider_client.h",
     "platform/modules/service_worker/web_service_worker_registration_object_info.h",
+    "platform/modules/video_capture/web_video_capture_impl_manager.h",
     "platform/modules/webrtc/track_observer.h",
     "platform/modules/webrtc/webrtc_logging.h",
     "platform/modules/webrtc/webrtc_source.h",
@@ -197,6 +198,7 @@
     "platform/web_canonical_cookie.h",
     "platform/web_client_hints_type.h",
     "platform/web_coalesced_input_event.h",
+    "platform/web_color_scheme.h",
     "platform/web_common.h",
     "platform/web_computed_ax_tree.h",
     "platform/web_connection_type.h",
diff --git a/third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom b/third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom
index de71c67..0d6aaf8 100644
--- a/third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom
+++ b/third_party/blink/public/mojom/native_file_system/native_file_system_file_handle.mojom
@@ -25,7 +25,8 @@
   AsBlob() => (NativeFileSystemError result, SerializedBlob? blob);
 
   // Returns a FileWriter object. The FileWriter provides write operations on a file.
-  CreateFileWriter() => (NativeFileSystemError result, NativeFileSystemFileWriter? writer);
+  CreateFileWriter(bool keep_existing_data) => (
+      NativeFileSystemError result, NativeFileSystemFileWriter? writer);
 
   // Create a TransferToken for this directory. This token can be used to pass
   // a reference to this directory to other methods, for example to copy or move
diff --git a/third_party/blink/public/platform/modules/video_capture/DEPS b/third_party/blink/public/platform/modules/video_capture/DEPS
new file mode 100644
index 0000000..1a5a47a
--- /dev/null
+++ b/third_party/blink/public/platform/modules/video_capture/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+    "+media/base",
+    "+media/capture",
+]
diff --git a/third_party/blink/public/platform/modules/video_capture/OWNERS b/third_party/blink/public/platform/modules/video_capture/OWNERS
new file mode 100644
index 0000000..36e2699c
--- /dev/null
+++ b/third_party/blink/public/platform/modules/video_capture/OWNERS
@@ -0,0 +1 @@
+file://third_party/blink/renderer/platform/video_capture/OWNERS
diff --git a/content/renderer/media/video_capture/video_capture_impl_manager.h b/third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h
similarity index 79%
rename from content/renderer/media/video_capture/video_capture_impl_manager.h
rename to third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h
index 3ba2837..54ebe12b 100644
--- a/content/renderer/media/video_capture/video_capture_impl_manager.h
+++ b/third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_IMPL_MANAGER_H_
-#define CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_IMPL_MANAGER_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_VIDEO_CAPTURE_WEB_VIDEO_CAPTURE_IMPL_MANAGER_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_VIDEO_CAPTURE_WEB_VIDEO_CAPTURE_IMPL_MANAGER_H_
 
+#include <string.h>
 #include <memory>
-#include <string>
 #include <vector>
 
 #include "base/callback.h"
@@ -16,12 +16,12 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
-#include "content/common/content_export.h"
 #include "media/capture/video_capture_types.h"
 #include "third_party/blink/public/common/media/video_capture.h"
 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
+#include "third_party/blink/public/platform/web_common.h"
 
-namespace content {
+namespace blink {
 
 class VideoCaptureImpl;
 
@@ -33,15 +33,15 @@
 //
 // THREADING
 //
-// VideoCaptureImplManager lives only on the Render Main thread. All methods
+// WebVideoCaptureImplManager lives only on the Render Main thread. All methods
 // must be called on this thread.
 //
 // VideoFrames are delivered on the IO thread. Callbacks provided by
 // a client are also called on the IO thread.
-class CONTENT_EXPORT VideoCaptureImplManager {
+class BLINK_PLATFORM_EXPORT WebVideoCaptureImplManager {
  public:
-  VideoCaptureImplManager();
-  virtual ~VideoCaptureImplManager();
+  WebVideoCaptureImplManager();
+  virtual ~WebVideoCaptureImplManager();
 
   // Open a device associated with the session ID.
   // This method must be called before any methods with the same ID
@@ -70,8 +70,8 @@
   base::OnceClosure StartCapture(
       const media::VideoCaptureSessionId& id,
       const media::VideoCaptureParams& params,
-      const blink::VideoCaptureStateUpdateCB& state_update_cb,
-      const blink::VideoCaptureDeliverFrameCB& deliver_frame_cb);
+      const VideoCaptureStateUpdateCB& state_update_cb,
+      const VideoCaptureDeliverFrameCB& deliver_frame_cb);
 
   // Requests that the video capturer send a frame "soon" (e.g., to resolve
   // picture loss or quality issues).
@@ -84,12 +84,12 @@
   // Get supported formats supported by the device for the given session
   // ID. |callback| will be called on the IO thread.
   void GetDeviceSupportedFormats(const media::VideoCaptureSessionId& id,
-                                 blink::VideoCaptureDeviceFormatsCB callback);
+                                 VideoCaptureDeviceFormatsCB callback);
 
   // Get supported formats currently in use for the given session ID.
   // |callback| will be called on the IO thread.
   void GetDeviceFormatsInUse(const media::VideoCaptureSessionId& id,
-                             blink::VideoCaptureDeviceFormatsCB callback);
+                             VideoCaptureDeviceFormatsCB callback);
 
   // Make all VideoCaptureImpl instances in the input |video_devices|
   // stop/resume delivering video frames to their clients, depends on flag
@@ -97,9 +97,9 @@
   // PageHidden/Shown() event.
   // To suspend/resume an individual session, please call Suspend(id) or
   // Resume(id).
-  void SuspendDevices(const blink::MediaStreamDevices& video_devices,
-                      bool suspend);
+  void SuspendDevices(const MediaStreamDevices& video_devices, bool suspend);
 
+  // TODO(crbug.com/704136): Switch to WebString.
   void OnLog(const media::VideoCaptureSessionId& id,
              const std::string& message);
   void OnFrameDropped(const media::VideoCaptureSessionId& id,
@@ -116,6 +116,8 @@
   void UnrefDevice(const media::VideoCaptureSessionId& id);
 
   // Devices currently in use.
+  //
+  // TODO(crbug.com/704136): Switch to WebVector.
   std::vector<DeviceEntry> devices_;
 
   // This is an internal ID for identifying clients of VideoCaptureImpl.
@@ -133,11 +135,11 @@
 
   // Bound to the render thread.
   // NOTE: Weak pointers must be invalidated before all other member variables.
-  base::WeakPtrFactory<VideoCaptureImplManager> weak_factory_{this};
+  base::WeakPtrFactory<WebVideoCaptureImplManager> weak_factory_{this};
 
-  DISALLOW_COPY_AND_ASSIGN(VideoCaptureImplManager);
+  DISALLOW_COPY_AND_ASSIGN(WebVideoCaptureImplManager);
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_IMPL_MANAGER_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_VIDEO_CAPTURE_WEB_VIDEO_CAPTURE_IMPL_MANAGER_H_
diff --git a/third_party/blink/renderer/platform/graphics/color_scheme.h b/third_party/blink/public/platform/web_color_scheme.h
similarity index 72%
rename from third_party/blink/renderer/platform/graphics/color_scheme.h
rename to third_party/blink/public/platform/web_color_scheme.h
index e8b7915..34f19e7 100644
--- a/third_party/blink/renderer/platform/graphics/color_scheme.h
+++ b/third_party/blink/public/platform/web_color_scheme.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COLOR_SCHEME_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COLOR_SCHEME_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_COLOR_SCHEME_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_COLOR_SCHEME_H_
 
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
@@ -13,11 +13,11 @@
 // the UA style sheet (setting the text color to white instead of black on the
 // root element for kDark), the frame backdrop color (black instead of white for
 // kDark), theming form controls and scrollbars, etc.
-enum ColorScheme {
+enum WebColorScheme {
   kLight = 1,
   kDark = 2,
 };
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COLOR_SCHEME_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_COLOR_SCHEME_H_
diff --git a/third_party/blink/public/platform/web_media_stream_center.h b/third_party/blink/public/platform/web_media_stream_center.h
index 571d245..63b5954 100644
--- a/third_party/blink/public/platform/web_media_stream_center.h
+++ b/third_party/blink/public/platform/web_media_stream_center.h
@@ -47,14 +47,11 @@
   virtual void DidCreateMediaStreamTrack(const WebMediaStreamTrack&) {}
   virtual void DidCloneMediaStreamTrack(const WebMediaStreamTrack& original,
                                         const WebMediaStreamTrack& clone) {}
-  virtual void DidSetContentHint(const WebMediaStreamTrack&) {}
   virtual void DidEnableMediaStreamTrack(const WebMediaStreamTrack&) {}
   virtual void DidDisableMediaStreamTrack(const WebMediaStreamTrack&) {}
 
   // Source functionality.
   virtual void DidStopMediaStreamSource(const WebMediaStreamSource&) {}
-  virtual void GetSourceSettings(const WebMediaStreamSource&,
-                                 WebMediaStreamTrack::Settings&) {}
 
   // Caller must take the ownership of the returned |WebAudioSourceProvider|
   // object.
diff --git a/third_party/blink/public/platform/web_theme_engine.h b/third_party/blink/public/platform/web_theme_engine.h
index 72d5def..899e95e 100644
--- a/third_party/blink/public/platform/web_theme_engine.h
+++ b/third_party/blink/public/platform/web_theme_engine.h
@@ -32,6 +32,7 @@
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_THEME_ENGINE_H_
 
 #include "base/time/time.h"
+#include "third_party/blink/public/platform/web_color_scheme.h"
 #include "third_party/blink/public/platform/web_rect.h"
 #include "third_party/blink/public/platform/web_scrollbar_overlay_color_theme.h"
 #include "third_party/blink/public/platform/web_size.h"
@@ -194,7 +195,8 @@
                      Part,
                      State,
                      const WebRect&,
-                     const ExtraParams*) {}
+                     const ExtraParams*,
+                     blink::WebColorScheme) {}
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index f17c3921..f667910 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -1531,7 +1531,7 @@
       style_builder_custom_functions: ["initial", "inherit", "value"],
       inherited: true,
       runtime_flag: "CSSColorScheme",
-      include_paths: ["third_party/blink/renderer/platform/graphics/color_scheme.h"],
+      include_paths: ["third_party/blink/public/platform/web_color_scheme.h"],
       type_name: "Vector<AtomicString>",
       default_value: "Vector<AtomicString, 0>()",
       field_template: "external",
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index 630ecc7..c473019 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -1773,8 +1773,8 @@
     if (value_id == CSSValueID::kCurrentcolor)
       return value;
     if (StyleColor::IsColorKeyword(value_id)) {
-      ColorScheme scheme =
-          state ? state->Style()->UsedColorScheme() : ColorScheme::kLight;
+      WebColorScheme scheme =
+          state ? state->Style()->UsedColorScheme() : WebColorScheme::kLight;
       Color color = document.GetTextLinkColors().ColorFromCSSValue(
           value, Color(), scheme, false);
       return *CSSColorValue::Create(color.Rgb());
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index 5f88201..178b0073 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -1912,7 +1912,7 @@
     if (auto* root_element = GetDocument().documentElement())
       style = root_element->GetComputedStyle();
     if (style) {
-      if (style->UsedColorScheme() == ColorScheme::kDark)
+      if (style->UsedColorScheme() == WebColorScheme::kDark)
         use_dark_background = true;
     } else if (SupportsDarkColorScheme()) {
       use_dark_background = true;
diff --git a/third_party/blink/renderer/core/dom/text_link_colors.cc b/third_party/blink/renderer/core/dom/text_link_colors.cc
index 230a5511..fa04a05 100644
--- a/third_party/blink/renderer/core/dom/text_link_colors.cc
+++ b/third_party/blink/renderer/core/dom/text_link_colors.cc
@@ -59,7 +59,7 @@
 
 Color TextLinkColors::ColorFromCSSValue(const CSSValue& value,
                                         Color current_color,
-                                        ColorScheme color_scheme,
+                                        WebColorScheme color_scheme,
                                         bool for_visited_link) const {
   if (auto* color_value = DynamicTo<CSSColorValue>(value))
     return color_value->Value();
diff --git a/third_party/blink/renderer/core/dom/text_link_colors.h b/third_party/blink/renderer/core/dom/text_link_colors.h
index 9ce3ff097..f21ebc53 100644
--- a/third_party/blink/renderer/core/dom/text_link_colors.h
+++ b/third_party/blink/renderer/core/dom/text_link_colors.h
@@ -31,8 +31,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_TEXT_LINK_COLORS_H_
 
 #include "base/macros.h"
+#include "third_party/blink/public/platform/web_color_scheme.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
-#include "third_party/blink/renderer/platform/graphics/color_scheme.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
 namespace blink {
@@ -59,7 +59,7 @@
   void ResetActiveLinkColor();
   Color ColorFromCSSValue(const CSSValue&,
                           Color current_color,
-                          ColorScheme color_scheme,
+                          WebColorScheme color_scheme,
                           bool for_visited_link = false) const;
 
  private:
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc
index 90948c5..a313de4 100644
--- a/third_party/blink/renderer/core/frame/frame.cc
+++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -90,7 +90,6 @@
   if (!client_)
     return;
 
-  detach_stack_ = base::debug::StackTrace();
   client_->SetOpener(nullptr);
   // After this, we must no longer talk to the client since this clears
   // its owning reference back to our owning LocalFrame.
@@ -283,8 +282,7 @@
                                 ? inheriting_agent_factory
                                 : MakeGarbageCollected<WindowAgentFactory>()),
       is_loading_(false),
-      devtools_frame_token_(client->GetDevToolsFrameToken()),
-      create_stack_(base::debug::StackTrace()) {
+      devtools_frame_token_(client->GetDevToolsFrameToken()) {
   InstanceCounters::IncrementCounter(InstanceCounters::kFrameCounter);
 }
 
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h
index d421bcf..c90efdbf 100644
--- a/third_party/blink/renderer/core/frame/frame.h
+++ b/third_party/blink/renderer/core/frame/frame.h
@@ -29,7 +29,6 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_H_
 
-#include "base/debug/stack_trace.h"
 #include "base/optional.h"
 #include "base/unguessable_token.h"
 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
@@ -208,14 +207,6 @@
   }
   const std::string& ToTraceValue();
 
-  // TODO(dcheng): temporary for debugging https://crbug.com/838348.
-  const base::debug::StackTrace& CreateStackForDebugging() {
-    return create_stack_;
-  }
-  const base::debug::StackTrace& DetachStackForDebugging() {
-    return detach_stack_;
-  }
-
   NavigationRateLimiter& navigation_rate_limiter() {
     return navigation_rate_limiter_;
   }
@@ -305,9 +296,6 @@
   bool is_loading_;
   base::UnguessableToken devtools_frame_token_;
   base::Optional<std::string> trace_value_;
-
-  base::debug::StackTrace create_stack_;
-  base::debug::StackTrace detach_stack_;
 };
 
 inline FrameClient* Frame::Client() const {
diff --git a/third_party/blink/renderer/core/html/html_meta_element.cc b/third_party/blink/renderer/core/html/html_meta_element.cc
index 35c845e..e763d45 100644
--- a/third_party/blink/renderer/core/html/html_meta_element.cc
+++ b/third_party/blink/renderer/core/html/html_meta_element.cc
@@ -22,6 +22,7 @@
 
 #include "third_party/blink/renderer/core/html/html_meta_element.h"
 
+#include "third_party/blink/public/platform/web_color_scheme.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element_traversal.h"
@@ -36,7 +37,6 @@
 #include "third_party/blink/renderer/core/loader/http_equiv.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/platform/graphics/color_scheme.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_to_number.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 09706b96..fbdf20f 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -7064,8 +7064,8 @@
     parameters
       BaseAudioContext context
 
-  # Notifies that existing BaseAudioContext has been destroyed.
-  event contextDestroyed
+  # Notifies that an existing BaseAudioContext will be destroyed.
+  event contextWillBeDestroyed
     parameters
       ContextId contextId
 
diff --git a/third_party/blink/renderer/core/layout/layout_theme.cc b/third_party/blink/renderer/core/layout/layout_theme.cc
index 1b21da0..206ee6ef 100644
--- a/third_party/blink/renderer/core/layout/layout_theme.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme.cc
@@ -815,8 +815,8 @@
   style.ResetBorder();
 }
 
-Color LayoutTheme::RootElementColor(ColorScheme color_scheme) const {
-  if (color_scheme == ColorScheme::kDark)
+Color LayoutTheme::RootElementColor(WebColorScheme color_scheme) const {
+  if (color_scheme == WebColorScheme::kDark)
     return Color::kWhite;
   return ComputedStyleInitialValues::InitialColor();
 }
diff --git a/third_party/blink/renderer/core/layout/layout_theme.h b/third_party/blink/renderer/core/layout/layout_theme.h
index 5b4338b..c7e4d3ae 100644
--- a/third_party/blink/renderer/core/layout/layout_theme.h
+++ b/third_party/blink/renderer/core/layout/layout_theme.h
@@ -23,6 +23,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_THEME_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_THEME_H_
 
+#include "third_party/blink/public/platform/web_color_scheme.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
 #include "third_party/blink/renderer/core/scroll/scroll_types.h"
@@ -32,7 +33,6 @@
 #include "third_party/blink/renderer/platform/geometry/length_box.h"
 #include "third_party/blink/renderer/platform/geometry/length_size.h"
 #include "third_party/blink/renderer/platform/graphics/color.h"
-#include "third_party/blink/renderer/platform/graphics/color_scheme.h"
 #include "third_party/blink/renderer/platform/theme_types.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
@@ -169,7 +169,7 @@
 
   // Root element text color. It can be different from the initial color in
   // other color schemes than the light theme.
-  Color RootElementColor(ColorScheme) const;
+  Color RootElementColor(WebColorScheme) const;
 
   virtual Color PlatformTapHighlightColor() const {
     return LayoutTheme::kDefaultTapHighlightColor;
diff --git a/third_party/blink/renderer/core/layout/layout_theme_test.cc b/third_party/blink/renderer/core/layout/layout_theme_test.cc
index b699842f..af57d8d 100644
--- a/third_party/blink/renderer/core/layout/layout_theme_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_theme_test.cc
@@ -78,9 +78,9 @@
 
 TEST_F(LayoutThemeTest, RootElementColor) {
   EXPECT_EQ(Color::kBlack,
-            LayoutTheme::GetTheme().RootElementColor(ColorScheme::kLight));
+            LayoutTheme::GetTheme().RootElementColor(WebColorScheme::kLight));
   EXPECT_EQ(Color::kWhite,
-            LayoutTheme::GetTheme().RootElementColor(ColorScheme::kDark));
+            LayoutTheme::GetTheme().RootElementColor(WebColorScheme::kDark));
 }
 
 TEST_F(LayoutThemeTest, RootElementColorChange) {
diff --git a/third_party/blink/renderer/core/paint/fallback_theme.cc b/third_party/blink/renderer/core/paint/fallback_theme.cc
index 3c4a3de..f959486f 100644
--- a/third_party/blink/renderer/core/paint/fallback_theme.cc
+++ b/third_party/blink/renderer/core/paint/fallback_theme.cc
@@ -13,7 +13,8 @@
 
 class FallbackTheme : public ui::NativeThemeBase {
  public:
-  SkColor GetSystemColor(ColorId color_id) const override {
+  SkColor GetSystemColor(ColorId color_id,
+                         ColorScheme color_scheme) const override {
     // The paint routines in NativeThemeBase only use GetSystemColor for
     // button focus colors and the fallback theme is not used for buttons.
     NOTREACHED();
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 0c6b855..a9940e5 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -1502,9 +1502,11 @@
     return ancestor_layer;
   }
 
-  bool found_ancestor_first;
+  bool found_ancestor_first = false;
   PaintLayer* containing_layer =
-      layer->ContainingLayer(ancestor_layer, &found_ancestor_first);
+      ancestor_layer
+          ? layer->ContainingLayer(ancestor_layer, &found_ancestor_first)
+          : layer->ContainingLayer(ancestor_layer, nullptr);
 
   if (found_ancestor_first) {
     // Found ancestorLayer before the containing layer, so compute offset of
diff --git a/third_party/blink/renderer/core/paint/theme_painter.cc b/third_party/blink/renderer/core/paint/theme_painter.cc
index be189f43..83936f0 100644
--- a/third_party/blink/renderer/core/paint/theme_painter.cc
+++ b/third_party/blink/renderer/core/paint/theme_painter.cc
@@ -63,6 +63,16 @@
   return ui::NativeTheme::kNormal;
 }
 
+static ui::NativeTheme::ColorScheme ToNativeColorScheme(
+    WebColorScheme color_scheme) {
+  switch (color_scheme) {
+    case WebColorScheme::kLight:
+      return ui::NativeTheme::ColorScheme::kLight;
+    case WebColorScheme::kDark:
+      return ui::NativeTheme::ColorScheme::kDark;
+  }
+}
+
 bool IsTemporalInput(const AtomicString& type) {
   return type == input_type_names::kDate ||
          type == input_type_names::kDatetimeLocal ||
@@ -548,7 +558,8 @@
 
   GetFallbackTheme().Paint(
       paint_info.context.Canvas(), ui::NativeTheme::kCheckbox,
-      GetFallbackThemeState(node), unzoomed_rect, extra_params);
+      GetFallbackThemeState(node), unzoomed_rect, extra_params,
+      ToNativeColorScheme(style.UsedColorScheme()));
   return false;
 }
 
@@ -572,7 +583,8 @@
 
   GetFallbackTheme().Paint(paint_info.context.Canvas(), ui::NativeTheme::kRadio,
                            GetFallbackThemeState(node), unzoomed_rect,
-                           extra_params);
+                           extra_params,
+                           ToNativeColorScheme(style.UsedColorScheme()));
   return false;
 }
 
diff --git a/third_party/blink/renderer/core/paint/theme_painter_default.cc b/third_party/blink/renderer/core/paint/theme_painter_default.cc
index 26d6351f5..3ba5b9bf 100644
--- a/third_party/blink/renderer/core/paint/theme_painter_default.cc
+++ b/third_party/blink/renderer/core/paint/theme_painter_default.cc
@@ -169,13 +169,13 @@
 
   Platform::Current()->ThemeEngine()->Paint(
       canvas, WebThemeEngine::kPartCheckbox, GetWebThemeState(node),
-      WebRect(unzoomed_rect), &extra_params);
+      WebRect(unzoomed_rect), &extra_params, style.UsedColorScheme());
   return false;
 }
 
 bool ThemePainterDefault::PaintRadio(const Node* node,
                                      const Document&,
-                                     const ComputedStyle&,
+                                     const ComputedStyle& style,
                                      const PaintInfo& paint_info,
                                      const IntRect& rect) {
   WebThemeEngine::ExtraParams extra_params;
@@ -183,9 +183,9 @@
   extra_params.button = WebThemeEngine::ButtonExtraParams();
   extra_params.button.checked = LayoutTheme::IsChecked(node);
 
-  Platform::Current()->ThemeEngine()->Paint(canvas, WebThemeEngine::kPartRadio,
-                                            GetWebThemeState(node),
-                                            WebRect(rect), &extra_params);
+  Platform::Current()->ThemeEngine()->Paint(
+      canvas, WebThemeEngine::kPartRadio, GetWebThemeState(node), WebRect(rect),
+      &extra_params, style.UsedColorScheme());
   return false;
 }
 
@@ -204,9 +204,9 @@
     extra_params.button.background_color =
         style.VisitedDependentColor(GetCSSPropertyBackgroundColor()).Rgb();
   }
-  Platform::Current()->ThemeEngine()->Paint(canvas, WebThemeEngine::kPartButton,
-                                            GetWebThemeState(node),
-                                            WebRect(rect), &extra_params);
+  Platform::Current()->ThemeEngine()->Paint(
+      canvas, WebThemeEngine::kPartButton, GetWebThemeState(node),
+      WebRect(rect), &extra_params, style.UsedColorScheme());
   return false;
 }
 
@@ -242,7 +242,7 @@
 
   Platform::Current()->ThemeEngine()->Paint(
       canvas, WebThemeEngine::kPartTextField, GetWebThemeState(node),
-      WebRect(rect), &extra_params);
+      WebRect(rect), &extra_params, style.UsedColorScheme());
   return false;
 }
 
@@ -276,7 +276,7 @@
   cc::PaintCanvas* canvas = i.context.Canvas();
   Platform::Current()->ThemeEngine()->Paint(
       canvas, WebThemeEngine::kPartMenuList, GetWebThemeState(node),
-      WebRect(rect), &extra_params);
+      WebRect(rect), &extra_params, style.UsedColorScheme());
   return false;
 }
 
@@ -295,7 +295,7 @@
   cc::PaintCanvas* canvas = paint_info.context.Canvas();
   Platform::Current()->ThemeEngine()->Paint(
       canvas, WebThemeEngine::kPartMenuList, GetWebThemeState(node),
-      WebRect(rect), &extra_params);
+      WebRect(rect), &extra_params, style.UsedColorScheme());
   return false;
 }
 
@@ -389,7 +389,7 @@
 
   Platform::Current()->ThemeEngine()->Paint(
       canvas, WebThemeEngine::kPartSliderTrack, GetWebThemeState(o.GetNode()),
-      WebRect(unzoomed_rect), &extra_params);
+      WebRect(unzoomed_rect), &extra_params, o.StyleRef().UsedColorScheme());
   return false;
 }
 
@@ -418,7 +418,7 @@
 
   Platform::Current()->ThemeEngine()->Paint(
       canvas, WebThemeEngine::kPartSliderThumb, GetWebThemeState(node),
-      WebRect(unzoomed_rect), &extra_params);
+      WebRect(unzoomed_rect), &extra_params, style.UsedColorScheme());
   return false;
 }
 
@@ -434,7 +434,7 @@
 
   Platform::Current()->ThemeEngine()->Paint(
       canvas, WebThemeEngine::kPartInnerSpinButton, GetWebThemeState(node),
-      WebRect(rect), &extra_params);
+      WebRect(rect), &extra_params, style.UsedColorScheme());
   return false;
 }
 
@@ -458,7 +458,7 @@
   cc::PaintCanvas* canvas = i.context.Canvas();
   Platform::Current()->ThemeEngine()->Paint(
       canvas, WebThemeEngine::kPartProgressBar, GetWebThemeState(o.GetNode()),
-      WebRect(rect), &extra_params);
+      WebRect(rect), &extra_params, o.StyleRef().UsedColorScheme());
   return false;
 }
 
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
index 71507744..64bb992 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
@@ -205,7 +205,9 @@
 #else
   Platform::Current()->ThemeEngine()->Paint(
       context.Canvas(), WebThemeEngine::kPartScrollbarCorner,
-      WebThemeEngine::kStateNormal, WebRect(corner_rect), nullptr);
+      WebThemeEngine::kStateNormal, WebRect(corner_rect), nullptr,
+      WebColorScheme::
+          kLight /* TODO(futhark): pass color scheme to scrollbars */);
 #endif
 }
 
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc
index 9ca4365a..5d1fb26d 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc
@@ -263,7 +263,9 @@
       scrollbar.Orientation() == kHorizontalScrollbar
           ? WebThemeEngine::kPartScrollbarHorizontalTrack
           : WebThemeEngine::kPartScrollbarVerticalTrack,
-      state, WebRect(rect), &extra_params);
+      state, WebRect(rect), &extra_params,
+      WebColorScheme::
+          kLight /* TODO(futhark): pass color scheme to scrollbar parts */);
 }
 
 void ScrollbarThemeAura::PaintButton(GraphicsContext& gc,
@@ -280,7 +282,9 @@
     return;
   DrawingRecorder recorder(gc, scrollbar, display_item_type);
   Platform::Current()->ThemeEngine()->Paint(
-      gc.Canvas(), params.part, params.state, WebRect(rect), nullptr);
+      gc.Canvas(), params.part, params.state, WebRect(rect), nullptr,
+      WebColorScheme::
+          kLight /* TODO(futhark): pass color scheme to scrollbar parts */);
 }
 
 void ScrollbarThemeAura::PaintThumb(GraphicsContext& gc,
@@ -306,7 +310,9 @@
       scrollbar.Orientation() == kHorizontalScrollbar
           ? WebThemeEngine::kPartScrollbarHorizontalThumb
           : WebThemeEngine::kPartScrollbarVerticalThumb,
-      state, WebRect(rect), nullptr);
+      state, WebRect(rect), nullptr,
+      WebColorScheme::
+          kLight /* TODO(futhark): pass color scheme to scrollbars */);
 }
 
 bool ScrollbarThemeAura::ShouldRepaintAllPartsOnInvalidation() const {
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.cc
index 2fdf0676..e75a76d 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.cc
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.cc
@@ -197,7 +197,7 @@
   }
 
   Platform::Current()->ThemeEngine()->Paint(canvas, part, state, WebRect(rect),
-                                            &params);
+                                            &params, WebColorScheme::kLight);
 
   if (scrollbar.IsLeftSideVerticalScrollbar())
     canvas->restore();
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index b30495c..f3cdd57 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2392,8 +2392,8 @@
   // Load the images of CSS properties that were deferred by LazyLoad.
   void LoadDeferredImages(Document&) const;
 
-  enum ColorScheme UsedColorScheme() const {
-    return DarkColorScheme() ? ColorScheme::kDark : ColorScheme::kLight;
+  enum WebColorScheme UsedColorScheme() const {
+    return DarkColorScheme() ? WebColorScheme::kDark : WebColorScheme::kLight;
   }
 
  private:
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc
index 6bc972c..c33134f 100644
--- a/third_party/blink/renderer/core/style/computed_style_test.cc
+++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -529,10 +529,10 @@
   light_value->Append(*CSSIdentifierValue::Create(CSSValueID::kLight));
 
   To<Longhand>(ref.GetProperty()).ApplyValue(state, *dark_value);
-  EXPECT_EQ(ColorScheme::kDark, style->UsedColorScheme());
+  EXPECT_EQ(WebColorScheme::kDark, style->UsedColorScheme());
 
   To<Longhand>(ref.GetProperty()).ApplyValue(state, *light_value);
-  EXPECT_EQ(ColorScheme::kLight, style->UsedColorScheme());
+  EXPECT_EQ(WebColorScheme::kLight, style->UsedColorScheme());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/devtools/front_end/web_audio/WebAudioModel.js b/third_party/blink/renderer/devtools/front_end/web_audio/WebAudioModel.js
index aa1ee5ab..7ec0e5d1 100644
--- a/third_party/blink/renderer/devtools/front_end/web_audio/WebAudioModel.js
+++ b/third_party/blink/renderer/devtools/front_end/web_audio/WebAudioModel.js
@@ -76,7 +76,7 @@
    * @param {!Protocol.WebAudio.ContextId} contextId
    * @override
    */
-  contextDestroyed(contextId) {
+  contextWillBeDestroyed(contextId) {
     this._contextMapById.delete(contextId);
     this.dispatchEventToListeners(WebAudio.WebAudioModel.Events.ContextDestroyed, contextId);
   }
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index c0dc89a..c6bc7c78 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -668,6 +668,7 @@
           "mediastream/media_track_supported_constraints.idl",
           "native_file_system/choose_file_system_entries_options.idl",
           "native_file_system/choose_file_system_entries_options_accepts.idl",
+          "native_file_system/file_system_create_writer_options.idl",
           "native_file_system/file_system_get_directory_options.idl",
           "native_file_system/file_system_get_file_options.idl",
           "native_file_system/file_system_handle_permission_descriptor.idl",
diff --git a/third_party/blink/renderer/modules/native_file_system/file_system_create_writer_options.idl b/third_party/blink/renderer/modules/native_file_system/file_system_create_writer_options.idl
new file mode 100644
index 0000000..df0834cd8
--- /dev/null
+++ b/third_party/blink/renderer/modules/native_file_system/file_system_create_writer_options.idl
@@ -0,0 +1,8 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/native-file-system/#dictdef-filesystemcreatewriteroptions
+dictionary FileSystemCreateWriterOptions {
+  boolean keepExistingData = false;
+};
diff --git a/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl b/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl
index 1b9f6375..68435f4 100644
--- a/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl
+++ b/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl
@@ -9,6 +9,6 @@
     RuntimeEnabled=NativeFileSystem,
     ImplementedAs=NativeFileSystemFileHandle
 ] interface FileSystemFileHandle : FileSystemHandle {
-    [CallWith=ScriptState] Promise<FileSystemWriter> createWriter();
+    [CallWith=ScriptState] Promise<FileSystemWriter> createWriter(optional FileSystemCreateWriterOptions options);
     [CallWith=ScriptState] Promise<File> getFile();
 };
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
index b385ee5..2fbaf48f 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/fileapi/file.h"
 #include "third_party/blink/renderer/core/fileapi/file_error.h"
+#include "third_party/blink/renderer/modules/native_file_system/file_system_create_writer_options.h"
 #include "third_party/blink/renderer/modules/native_file_system/native_file_system_writer.h"
 #include "third_party/blink/renderer/platform/file_metadata.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
@@ -26,27 +27,33 @@
 }
 
 ScriptPromise NativeFileSystemFileHandle::createWriter(
-    ScriptState* script_state) {
+    ScriptState* script_state,
+    const FileSystemCreateWriterOptions* options) {
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
   ScriptPromise result = resolver->Promise();
 
-  mojo_ptr_->CreateFileWriter(WTF::Bind(
-      [](ScriptPromiseResolver* resolver,
-         mojom::blink::NativeFileSystemErrorPtr result,
-         mojom::blink::NativeFileSystemFileWriterPtr writer) {
-        ExecutionContext* context = resolver->GetExecutionContext();
-        if (!context)
-          return;
-        if (result->error_code == base::File::FILE_OK) {
-          resolver->Resolve(MakeGarbageCollected<NativeFileSystemWriter>(
-              RevocableInterfacePtr<mojom::blink::NativeFileSystemFileWriter>(
-                  writer.PassInterface(), context->GetInterfaceInvalidator(),
-                  context->GetTaskRunner(TaskType::kMiscPlatformAPI))));
-        } else {
-          resolver->Reject(file_error::CreateDOMException(result->error_code));
-        }
-      },
-      WrapPersistent(resolver)));
+  mojo_ptr_->CreateFileWriter(
+      options->keepExistingData(),
+      WTF::Bind(
+          [](ScriptPromiseResolver* resolver,
+             mojom::blink::NativeFileSystemErrorPtr result,
+             mojom::blink::NativeFileSystemFileWriterPtr writer) {
+            ExecutionContext* context = resolver->GetExecutionContext();
+            if (!context)
+              return;
+            if (result->error_code == base::File::FILE_OK) {
+              resolver->Resolve(MakeGarbageCollected<NativeFileSystemWriter>(
+                  RevocableInterfacePtr<
+                      mojom::blink::NativeFileSystemFileWriter>(
+                      writer.PassInterface(),
+                      context->GetInterfaceInvalidator(),
+                      context->GetTaskRunner(TaskType::kMiscPlatformAPI))));
+            } else {
+              resolver->Reject(
+                  file_error::CreateDOMException(result->error_code));
+            }
+          },
+          WrapPersistent(resolver)));
 
   return result;
 }
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h
index fe24da2..fc530f31 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h"
 
 namespace blink {
+class FileSystemCreateWriterOptions;
 
 class NativeFileSystemFileHandle final : public NativeFileSystemHandle {
   DEFINE_WRAPPERTYPEINFO();
@@ -21,7 +22,8 @@
 
   bool isFile() const override { return true; }
 
-  ScriptPromise createWriter(ScriptState*);
+  ScriptPromise createWriter(ScriptState*,
+                             const FileSystemCreateWriterOptions* options);
   ScriptPromise getFile(ScriptState*);
 
   mojom::blink::NativeFileSystemTransferTokenPtr Transfer() override;
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc
index c7c410a..82fc280 100644
--- a/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc
+++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_writer.cc
@@ -240,6 +240,11 @@
   DCHECK(pending_operation_);
   if (result->error_code == base::File::FILE_OK) {
     pending_operation_->Resolve();
+  } else if (result->error_code == base::File::FILE_ERROR_INVALID_OPERATION) {
+    // TODO(https://crbug.com/971268): Better error messages that make sense in
+    // JS.
+    pending_operation_->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError));
   } else {
     pending_operation_->Reject(
         file_error::CreateDOMException(result->error_code));
@@ -252,6 +257,11 @@
   DCHECK(pending_operation_);
   if (result->error_code == base::File::FILE_OK) {
     pending_operation_->Resolve();
+  } else if (result->error_code == base::File::FILE_ERROR_INVALID_OPERATION) {
+    // TODO(https://crbug.com/971268): Better error messages that make sense in
+    // JS.
+    pending_operation_->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError));
   } else {
     pending_operation_->Reject(
         file_error::CreateDOMException(result->error_code));
@@ -264,12 +274,20 @@
   DCHECK(pending_operation_);
   if (result->error_code == base::File::FILE_OK) {
     pending_operation_->Resolve();
+  } else if (result->error_code == base::File::FILE_ERROR_INVALID_OPERATION) {
+    // TODO(https://crbug.com/971268): Better error messages that make sense in
+    // JS.
+    pending_operation_->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kInvalidStateError));
   } else {
     pending_operation_->Reject(
         file_error::CreateDOMException(result->error_code));
   }
   file_ = nullptr;
   pending_operation_ = nullptr;
+  // We close the mojo pipe because we intend this writer to be discarded after
+  // close. Subsequent operations will fail.
+  mojo_ptr_ = nullptr;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webaudio/inspector_web_audio_agent.cc b/third_party/blink/renderer/modules/webaudio/inspector_web_audio_agent.cc
index 4789505..bc85ec1 100644
--- a/third_party/blink/renderer/modules/webaudio/inspector_web_audio_agent.cc
+++ b/third_party/blink/renderer/modules/webaudio/inspector_web_audio_agent.cc
@@ -107,7 +107,7 @@
 
 void InspectorWebAudioAgent::WillDestroyBaseAudioContext(
     BaseAudioContext* context) {
-  GetFrontend()->contextDestroyed(context->Uuid());
+  GetFrontend()->contextWillBeDestroyed(context->Uuid());
 }
 
 void InspectorWebAudioAgent::DidChangeBaseAudioContext(
diff --git a/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc b/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc
index f014dd3..1e5b731 100644
--- a/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc
+++ b/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc
@@ -12,12 +12,6 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
 
-namespace {
-bool IsWithinEpsilon(double a, double b) {
-  return std::abs(a - b) < std::numeric_limits<double>::epsilon();
-}
-}  // namespace
-
 namespace blink {
 
 // makes a deep copy of transformationMatrix
@@ -68,16 +62,21 @@
 XRRigidTransform* XRRigidTransform::Create(DOMPointInit* position,
                                            DOMPointInit* orientation,
                                            ExceptionState& exception_state) {
-  if (position && !IsWithinEpsilon(1.0, position->w())) {
+  if (position && position->w() != 1.0) {
     exception_state.ThrowTypeError("W component of position must be 1.0");
     return nullptr;
   }
 
   if (orientation) {
-    if (IsWithinEpsilon(orientation->x(), 0.0) &&
-        IsWithinEpsilon(orientation->y(), 0.0) &&
-        IsWithinEpsilon(orientation->z(), 0.0) &&
-        IsWithinEpsilon(orientation->w(), 0.0)) {
+    double x = orientation->x();
+    double y = orientation->y();
+    double z = orientation->z();
+    double w = orientation->w();
+    double sq_len = x * x + y * y + z * z + w * w;
+
+    // The only way for the result of a square root to be 0 is if the squared
+    // number is 0, so save the square root operation and just compare to 0 now.
+    if (sq_len == 0.0) {
       exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                         "Orientation's length cannot be 0");
       return nullptr;
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 9644e43..bdf9305 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -484,6 +484,7 @@
     "exported/platform.cc",
     "exported/service_registry.cc",
     "exported/url_conversion.cc",
+    "exported/video_capture/web_video_capture_impl_manager.cc",
     "exported/web_audio_bus.cc",
     "exported/web_audio_device.cc",
     "exported/web_blob_info.cc",
@@ -829,7 +830,6 @@
     "graphics/color_behavior.cc",
     "graphics/color_behavior.h",
     "graphics/color_blend.h",
-    "graphics/color_scheme.h",
     "graphics/color_space_gamut.cc",
     "graphics/color_space_gamut.h",
     "graphics/color_space_profile_data.cc",
@@ -1338,6 +1338,8 @@
     "transforms/transformation_matrix.h",
     "transforms/translate_transform_operation.cc",
     "transforms/translate_transform_operation.h",
+    "video_capture/video_capture_impl.cc",
+    "video_capture/video_capture_impl.h",
     "web_test_support.cc",
     "web_test_support.h",
     "weborigin/known_ports.cc",
@@ -1643,6 +1645,7 @@
     "exported/mediastream/media_stream_audio_processor_test.cc",
     "exported/mediastream/media_stream_audio_test.cc",
     "exported/mediastream/webrtc_uma_histograms_test.cc",
+    "exported/video_capture/web_video_capture_impl_manager_test.cc",
     "exported/web_canonical_cookie_test.cc",
     "exported/web_icon_sizes_parser_test.cc",
     "exported/web_screen_info_test.cc",
@@ -1787,6 +1790,7 @@
     "transforms/rotation_test.cc",
     "transforms/transform_operations_test.cc",
     "transforms/transformation_matrix_test.cc",
+    "video_capture/video_capture_impl_test.cc",
     "weborigin/known_ports_test.cc",
     "weborigin/kurl_test.cc",
     "weborigin/scheme_registry_test.cc",
@@ -1818,6 +1822,7 @@
     "//cc",
     "//cc:test_support",
     "//media:test_support",
+    "//media/capture/mojom:video_capture",
     "//mojo/core/embedder",
     "//mojo/public/cpp/bindings/tests:for_blink_tests",
     "//mojo/public/cpp/test_support:test_utils",
diff --git a/third_party/blink/renderer/platform/exported/video_capture/DEPS b/third_party/blink/renderer/platform/exported/video_capture/DEPS
new file mode 100644
index 0000000..ab42aeca
--- /dev/null
+++ b/third_party/blink/renderer/platform/exported/video_capture/DEPS
@@ -0,0 +1,6 @@
+specific_include_rules = {
+    "web_video_capture_impl_manager_test.cc": [
+        "+media/base/bind_to_current_loop.h",
+        "+media/capture/mojom/video_capture.mojom-blink.h",
+    ],
+}
diff --git a/third_party/blink/renderer/platform/exported/video_capture/OWNER b/third_party/blink/renderer/platform/exported/video_capture/OWNER
new file mode 100644
index 0000000..36e2699c
--- /dev/null
+++ b/third_party/blink/renderer/platform/exported/video_capture/OWNER
@@ -0,0 +1 @@
+file://third_party/blink/renderer/platform/video_capture/OWNERS
diff --git a/content/renderer/media/video_capture/video_capture_impl_manager.cc b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc
similarity index 70%
rename from content/renderer/media/video_capture/video_capture_impl_manager.cc
rename to third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc
index 45985f7..fdaaf57a 100644
--- a/content/renderer/media/video_capture/video_capture_impl_manager.cc
+++ b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager.cc
@@ -6,7 +6,7 @@
 //
 // How is VideoCaptureImpl used:
 //
-// VideoCaptureImpl is an IO thread object while VideoCaptureImplManager
+// VideoCaptureImpl is an IO thread object while WebVideoCaptureImplManager
 // lives only on the render thread. It is only possible to access an
 // object of VideoCaptureImpl via a task on the IO thread.
 //
@@ -22,7 +22,7 @@
 // We make sure deletion is the last task on the IO thread for a
 // VideoCaptureImpl object. This allows the use of Unretained() binding.
 
-#include "content/renderer/media/video_capture/video_capture_impl_manager.h"
+#include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
 
 #include <algorithm>
 #include <string>
@@ -31,12 +31,25 @@
 #include "base/bind_helpers.h"
 #include "base/location.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "content/child/child_process.h"
-#include "content/renderer/media/video_capture/video_capture_impl.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/video_capture/video_capture_impl.h"
 
-namespace content {
+namespace blink {
 
-struct VideoCaptureImplManager::DeviceEntry {
+media::VideoCaptureFormats ToVideoCaptureFormats(
+    const Vector<media::VideoCaptureFormat>& format_vector) {
+  media::VideoCaptureFormats formats;
+  std::copy(format_vector.begin(), format_vector.end(),
+            std::back_inserter(formats));
+  return formats;
+}
+
+void MediaCallbackCaller(VideoCaptureDeviceFormatsCB media_callback,
+                         const Vector<media::VideoCaptureFormat>& formats) {
+  std::move(media_callback).Run(ToVideoCaptureFormats(formats));
+}
+
+struct WebVideoCaptureImplManager::DeviceEntry {
   media::VideoCaptureSessionId session_id;
 
   // To be used and destroyed only on the IO thread.
@@ -46,8 +59,8 @@
   int client_count;
 
   // This is set to true if this device is being suspended, via
-  // VideoCaptureImplManager::Suspend().
-  // See also: VideoCaptureImplManager::is_suspending_all_.
+  // WebVideoCaptureImplManager::Suspend().
+  // See also: WebVideoCaptureImplManager::is_suspending_all_.
   bool is_individually_suspended;
 
   DeviceEntry() : client_count(0), is_individually_suspended(false) {}
@@ -56,24 +69,24 @@
   ~DeviceEntry() = default;
 };
 
-VideoCaptureImplManager::VideoCaptureImplManager()
+WebVideoCaptureImplManager::WebVideoCaptureImplManager()
     : next_client_id_(0),
       render_main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       is_suspending_all_(false) {}
 
-VideoCaptureImplManager::~VideoCaptureImplManager() {
+WebVideoCaptureImplManager::~WebVideoCaptureImplManager() {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   if (devices_.empty())
     return;
   // Forcibly release all video capture resources.
   for (auto& entry : devices_) {
-    ChildProcess::current()->io_task_runner()->DeleteSoon(FROM_HERE,
-                                                          entry.impl.release());
+    Platform::Current()->GetIOTaskRunner()->DeleteSoon(FROM_HERE,
+                                                       entry.impl.release());
   }
   devices_.clear();
 }
 
-base::OnceClosure VideoCaptureImplManager::UseDevice(
+base::OnceClosure WebVideoCaptureImplManager::UseDevice(
     const media::VideoCaptureSessionId& id) {
   DVLOG(1) << __func__ << " session id: " << id;
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
@@ -90,7 +103,7 @@
   }
   ++it->client_count;
 
-  // Design limit: When there are multiple clients, VideoCaptureImplManager
+  // Design limit: When there are multiple clients, WebVideoCaptureImplManager
   // would have to individually track which ones requested suspending/resuming,
   // in order to determine whether the whole device should be suspended.
   // Instead, handle the non-common use case of multiple clients by just
@@ -99,15 +112,15 @@
   if (it->is_individually_suspended)
     Resume(id);
 
-  return base::BindOnce(&VideoCaptureImplManager::UnrefDevice,
+  return base::BindOnce(&WebVideoCaptureImplManager::UnrefDevice,
                         weak_factory_.GetWeakPtr(), id);
 }
 
-base::OnceClosure VideoCaptureImplManager::StartCapture(
+base::OnceClosure WebVideoCaptureImplManager::StartCapture(
     const media::VideoCaptureSessionId& id,
     const media::VideoCaptureParams& params,
-    const blink::VideoCaptureStateUpdateCB& state_update_cb,
-    const blink::VideoCaptureDeliverFrameCB& deliver_frame_cb) {
+    const VideoCaptureStateUpdateCB& state_update_cb,
+    const VideoCaptureDeliverFrameCB& deliver_frame_cb) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   const auto it = std::find_if(
       devices_.begin(), devices_.end(),
@@ -119,15 +132,15 @@
 
   // Use of base::Unretained() is safe because |devices_| is released on the
   // |io_task_runner()| as well.
-  ChildProcess::current()->io_task_runner()->PostTask(
+  Platform::Current()->GetIOTaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::StartCapture,
                                 base::Unretained(it->impl.get()), client_id,
                                 params, state_update_cb, deliver_frame_cb));
-  return base::BindOnce(&VideoCaptureImplManager::StopCapture,
+  return base::BindOnce(&WebVideoCaptureImplManager::StopCapture,
                         weak_factory_.GetWeakPtr(), client_id, id);
 }
 
-void VideoCaptureImplManager::RequestRefreshFrame(
+void WebVideoCaptureImplManager::RequestRefreshFrame(
     const media::VideoCaptureSessionId& id) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   const auto it = std::find_if(
@@ -136,12 +149,13 @@
   DCHECK(it != devices_.end());
   // Use of base::Unretained() is safe because |devices_| is released on the
   // |io_task_runner()| as well.
-  ChildProcess::current()->io_task_runner()->PostTask(
+  Platform::Current()->GetIOTaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::RequestRefreshFrame,
                                 base::Unretained(it->impl.get())));
 }
 
-void VideoCaptureImplManager::Suspend(const media::VideoCaptureSessionId& id) {
+void WebVideoCaptureImplManager::Suspend(
+    const media::VideoCaptureSessionId& id) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   const auto it = std::find_if(
       devices_.begin(), devices_.end(),
@@ -156,12 +170,13 @@
     return;  // Device should already be suspended.
   // Use of base::Unretained() is safe because |devices_| is released on the
   // |io_task_runner()| as well.
-  ChildProcess::current()->io_task_runner()->PostTask(
+  Platform::Current()->GetIOTaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::SuspendCapture,
                                 base::Unretained(it->impl.get()), true));
 }
 
-void VideoCaptureImplManager::Resume(const media::VideoCaptureSessionId& id) {
+void WebVideoCaptureImplManager::Resume(
+    const media::VideoCaptureSessionId& id) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   const auto it = std::find_if(
       devices_.begin(), devices_.end(),
@@ -174,14 +189,14 @@
     return;  // Device must remain suspended until all are resumed.
   // Use of base::Unretained() is safe because |devices_| is released on the
   // |io_task_runner()| as well.
-  ChildProcess::current()->io_task_runner()->PostTask(
+  Platform::Current()->GetIOTaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::SuspendCapture,
                                 base::Unretained(it->impl.get()), false));
 }
 
-void VideoCaptureImplManager::GetDeviceSupportedFormats(
+void WebVideoCaptureImplManager::GetDeviceSupportedFormats(
     const media::VideoCaptureSessionId& id,
-    blink::VideoCaptureDeviceFormatsCB callback) {
+    VideoCaptureDeviceFormatsCB callback) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   const auto it = std::find_if(
       devices_.begin(), devices_.end(),
@@ -189,15 +204,16 @@
   DCHECK(it != devices_.end());
   // Use of base::Unretained() is safe because |devices_| is released on the
   // |io_task_runner()| as well.
-  ChildProcess::current()->io_task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&VideoCaptureImpl::GetDeviceSupportedFormats,
-                     base::Unretained(it->impl.get()), std::move(callback)));
+  Platform::Current()->GetIOTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(&VideoCaptureImpl::GetDeviceSupportedFormats,
+                                base::Unretained(it->impl.get()),
+                                base::BindOnce(&MediaCallbackCaller,
+                                               std::move(callback))));
 }
 
-void VideoCaptureImplManager::GetDeviceFormatsInUse(
+void WebVideoCaptureImplManager::GetDeviceFormatsInUse(
     const media::VideoCaptureSessionId& id,
-    blink::VideoCaptureDeviceFormatsCB callback) {
+    VideoCaptureDeviceFormatsCB callback) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   const auto it = std::find_if(
       devices_.begin(), devices_.end(),
@@ -205,19 +221,20 @@
   DCHECK(it != devices_.end());
   // Use of base::Unretained() is safe because |devices_| is released on the
   // |io_task_runner()| as well.
-  ChildProcess::current()->io_task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&VideoCaptureImpl::GetDeviceFormatsInUse,
-                     base::Unretained(it->impl.get()), std::move(callback)));
+  Platform::Current()->GetIOTaskRunner()->PostTask(
+      FROM_HERE, base::BindOnce(&VideoCaptureImpl::GetDeviceFormatsInUse,
+                                base::Unretained(it->impl.get()),
+                                base::BindOnce(&MediaCallbackCaller,
+                                               std::move(callback))));
 }
 
 std::unique_ptr<VideoCaptureImpl>
-VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
+WebVideoCaptureImplManager::CreateVideoCaptureImplForTesting(
     const media::VideoCaptureSessionId& session_id) const {
   return nullptr;
 }
 
-void VideoCaptureImplManager::StopCapture(
+void WebVideoCaptureImplManager::StopCapture(
     int client_id,
     const media::VideoCaptureSessionId& id) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
@@ -227,12 +244,12 @@
   DCHECK(it != devices_.end());
   // Use of base::Unretained() is safe because |devices_| is released on the
   // |io_task_runner()| as well.
-  ChildProcess::current()->io_task_runner()->PostTask(
+  Platform::Current()->GetIOTaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::StopCapture,
                                 base::Unretained(it->impl.get()), client_id));
 }
 
-void VideoCaptureImplManager::UnrefDevice(
+void WebVideoCaptureImplManager::UnrefDevice(
     const media::VideoCaptureSessionId& id) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   const auto it = std::find_if(
@@ -243,19 +260,20 @@
   --it->client_count;
   if (it->client_count > 0)
     return;
-  ChildProcess::current()->io_task_runner()->DeleteSoon(FROM_HERE,
-                                                        it->impl.release());
+  Platform::Current()->GetIOTaskRunner()->DeleteSoon(FROM_HERE,
+                                                     it->impl.release());
+
   devices_.erase(it);
 }
 
-void VideoCaptureImplManager::SuspendDevices(
-    const blink::MediaStreamDevices& video_devices,
+void WebVideoCaptureImplManager::SuspendDevices(
+    const MediaStreamDevices& video_devices,
     bool suspend) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   if (is_suspending_all_ == suspend)
     return;
   is_suspending_all_ = suspend;
-  for (const blink::MediaStreamDevice& device : video_devices) {
+  for (const MediaStreamDevice& device : video_devices) {
     const media::VideoCaptureSessionId id = device.session_id();
     const auto it = std::find_if(
         devices_.begin(), devices_.end(),
@@ -265,13 +283,13 @@
       continue;  // Either: 1) Already suspended; or 2) Should not be resumed.
     // Use of base::Unretained() is safe because |devices_| is released on the
     // |io_task_runner()| as well.
-    ChildProcess::current()->io_task_runner()->PostTask(
+    Platform::Current()->GetIOTaskRunner()->PostTask(
         FROM_HERE, base::BindOnce(&VideoCaptureImpl::SuspendCapture,
                                   base::Unretained(it->impl.get()), suspend));
   }
 }
 
-void VideoCaptureImplManager::OnFrameDropped(
+void WebVideoCaptureImplManager::OnFrameDropped(
     const media::VideoCaptureSessionId& id,
     media::VideoCaptureFrameDropReason reason) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
@@ -279,13 +297,13 @@
       devices_.begin(), devices_.end(),
       [id](const DeviceEntry& entry) { return entry.session_id == id; });
   DCHECK(it != devices_.end());
-  ChildProcess::current()->io_task_runner()->PostTask(
+  Platform::Current()->GetIOTaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::OnFrameDropped,
                                 base::Unretained(it->impl.get()), reason));
 }
 
-void VideoCaptureImplManager::OnLog(const media::VideoCaptureSessionId& id,
-                                    const std::string& message) {
+void WebVideoCaptureImplManager::OnLog(const media::VideoCaptureSessionId& id,
+                                       const std::string& message) {
   DCHECK(render_main_task_runner_->BelongsToCurrentThread());
   const auto it = std::find_if(
       devices_.begin(), devices_.end(),
@@ -293,9 +311,9 @@
   DCHECK(it != devices_.end());
   // Use of base::Unretained() is safe because |devices_| is released on the
   // |io_task_runner()| as well.
-  ChildProcess::current()->io_task_runner()->PostTask(
+  Platform::Current()->GetIOTaskRunner()->PostTask(
       FROM_HERE, base::BindOnce(&VideoCaptureImpl::OnLog,
                                 base::Unretained(it->impl.get()), message));
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/content/renderer/media/video_capture/video_capture_impl_manager_unittest.cc b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc
similarity index 92%
rename from content/renderer/media/video_capture/video_capture_impl_manager_unittest.cc
rename to third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc
index 1b713e9..0bfbce3 100644
--- a/content/renderer/media/video_capture/video_capture_impl_manager_unittest.cc
+++ b/third_party/blink/renderer/platform/exported/video_capture/web_video_capture_impl_manager_test.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include <array>
-#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -12,13 +11,13 @@
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
-#include "content/child/child_process.h"
-#include "content/renderer/media/video_capture/video_capture_impl.h"
-#include "content/renderer/media/video_capture/video_capture_impl_manager.h"
 #include "media/base/bind_to_current_loop.h"
-#include "media/capture/mojom/video_capture.mojom.h"
+#include "media/capture/mojom/video_capture.mojom-blink.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
+#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
+#include "third_party/blink/renderer/platform/video_capture/video_capture_impl.h"
 
 using media::BindToCurrentLoop;
 using ::testing::_;
@@ -26,7 +25,7 @@
 using ::testing::InSequence;
 using ::testing::SaveArg;
 
-namespace content {
+namespace blink {
 
 ACTION_P(RunClosure, closure) {
   closure.Run();
@@ -47,7 +46,7 @@
 };
 
 class MockVideoCaptureImpl : public VideoCaptureImpl,
-                             public media::mojom::VideoCaptureHost {
+                             public media::mojom::blink::VideoCaptureHost {
  public:
   MockVideoCaptureImpl(const media::VideoCaptureSessionId& session_id,
                        PauseResumeCallback* pause_callback,
@@ -62,7 +61,7 @@
   void Start(const base::UnguessableToken& device_id,
              const base::UnguessableToken& session_id,
              const media::VideoCaptureParams& params,
-             media::mojom::VideoCaptureObserverPtr observer) override {
+             media::mojom::blink::VideoCaptureObserverPtr observer) override {
     // For every Start(), expect a corresponding Stop() call.
     EXPECT_CALL(*this, Stop(_));
     // Simulate device started.
@@ -100,7 +99,7 @@
   MOCK_METHOD2(OnFrameDropped,
                void(const base::UnguessableToken&,
                     media::VideoCaptureFrameDropReason));
-  MOCK_METHOD2(OnLog, void(const base::UnguessableToken&, const std::string&));
+  MOCK_METHOD2(OnLog, void(const base::UnguessableToken&, const String&));
 
   PauseResumeCallback* const pause_callback_;
   const base::Closure destruct_callback_;
@@ -108,7 +107,7 @@
   DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureImpl);
 };
 
-class MockVideoCaptureImplManager : public VideoCaptureImplManager {
+class MockVideoCaptureImplManager : public WebVideoCaptureImplManager {
  public:
   MockVideoCaptureImplManager(PauseResumeCallback* pause_callback,
                               base::Closure stop_capture_callback)
@@ -203,10 +202,10 @@
   MOCK_METHOD1(OnResumed, void(const media::VideoCaptureSessionId& id));
 
   void OnStateUpdate(const media::VideoCaptureSessionId& id,
-                     blink::VideoCaptureState state) {
-    if (state == blink::VIDEO_CAPTURE_STATE_STARTED)
+                     VideoCaptureState state) {
+    if (state == VIDEO_CAPTURE_STATE_STARTED)
       OnStarted(id);
-    else if (state == blink::VIDEO_CAPTURE_STATE_STOPPED)
+    else if (state == VIDEO_CAPTURE_STATE_STOPPED)
       OnStopped(id);
     else
       NOTREACHED();
@@ -223,7 +222,7 @@
   }
 
   base::test::ScopedTaskEnvironment scoped_task_environment_;
-  ChildProcess child_process_;
+  ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
   base::RunLoop cleanup_run_loop_;
   std::unique_ptr<MockVideoCaptureImplManager> manager_;
 
@@ -253,10 +252,10 @@
 
 TEST_F(VideoCaptureImplManagerTest, SuspendAndResumeSessions) {
   std::array<base::OnceClosure, kNumClients> release_callbacks;
-  blink::MediaStreamDevices video_devices;
+  MediaStreamDevices video_devices;
   for (size_t i = 0; i < kNumClients; ++i) {
     release_callbacks[i] = manager_->UseDevice(session_ids_[i]);
-    blink::MediaStreamDevice video_device;
+    MediaStreamDevice video_device;
     video_device.set_session_id(session_ids_[i]);
     video_devices.push_back(video_device);
   }
@@ -360,4 +359,4 @@
   cleanup_run_loop_.Run();
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index f782b654..a83c2838 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -9,6 +9,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
 #include "cc/input/main_thread_scrolling_reason.h"
 #include "cc/layers/layer.h"
 #include "cc/test/fake_impl_task_runner_provider.h"
@@ -2831,6 +2832,30 @@
   EXPECT_TRUE(clip_mask0->DrawsContent());
 }
 
+TEST_P(PaintArtifactCompositorTest,
+       SynthesizedClipSimpleFastBorderNotSupportedMacNonEqualCorners) {
+  // Tests that on Mac, we fall back to a mask layer if the corners are not all
+  // the same radii.
+  FloatSize corner(30, 30);
+  FloatRoundedRect rrect(FloatRect(50, 50, 300, 200), corner, corner, corner,
+                         FloatSize());
+  auto c1 = CreateClip(c0(), t0(), rrect);
+
+  TestPaintArtifact artifact;
+  artifact.Chunk(t0(), *c1, e0())
+      .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack);
+  Update(artifact.Build());
+
+#if defined(OS_MACOSX)
+  ASSERT_EQ(2u, RootLayer()->children().size());
+#else
+  if (RuntimeEnabledFeatures::FastBorderRadiusEnabled())
+    ASSERT_EQ(1u, RootLayer()->children().size());
+  else
+    ASSERT_EQ(2u, RootLayer()->children().size());
+#endif
+}
+
 TEST_P(PaintArtifactCompositorTest, SynthesizedClipNested) {
   // This tests the simplist case that a single layer needs to be clipped
   // by a single composited rounded clip.
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index e62bc0b..fec1a0f6 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h"
 
+#include "build/build_config.h"
 #include "cc/input/overscroll_behavior.h"
 #include "cc/layers/layer.h"
 #include "cc/trees/clip_node.h"
@@ -832,6 +833,19 @@
     return false;
   }
 
+  // Rounded corners that differ are not supported by the
+  // CALayerOverlay system on Mac. Instead of letting it fall back
+  // to the (worse for memory and battery) non-CALayerOverlay system
+  // for such cases, fall back to a non-fast border-radius mask for
+  // the effect node.
+#if defined(OS_MACOSX)
+  if (radii.TopLeft() != radii.TopRight() ||
+      radii.TopLeft() != radii.BottomRight() ||
+      radii.TopLeft() != radii.BottomLeft()) {
+    return false;
+  }
+#endif
+
   return true;
 }
 
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_center.cc b/third_party/blink/renderer/platform/mediastream/media_stream_center.cc
index 94546a10..8a767275 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_center.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_center.cc
@@ -90,11 +90,6 @@
     private_->DidCloneMediaStreamTrack(original, clone);
 }
 
-void MediaStreamCenter::DidSetContentHint(MediaStreamComponent* track) {
-  if (private_)
-    private_->DidSetContentHint(track);
-}
-
 std::unique_ptr<AudioSourceProvider>
 MediaStreamCenter::CreateWebAudioSourceFromMediaStreamTrack(
     MediaStreamComponent* track,
@@ -114,11 +109,4 @@
     private_->DidStopMediaStreamSource(source);
 }
 
-void MediaStreamCenter::GetSourceSettings(
-    MediaStreamSource* source,
-    WebMediaStreamTrack::Settings& settings) {
-  if (private_)
-    private_->GetSourceSettings(source, settings);
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_center.h b/third_party/blink/renderer/platform/mediastream/media_stream_center.h
index ea5f98b..21fc18a 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_center.h
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_center.h
@@ -61,7 +61,6 @@
   void DidCloneMediaStreamTrack(MediaStreamComponent* original,
                                 MediaStreamComponent* clone);
   void DidSetMediaStreamTrackEnabled(MediaStreamComponent*);
-  void DidSetContentHint(MediaStreamComponent*);
   std::unique_ptr<AudioSourceProvider> CreateWebAudioSourceFromMediaStreamTrack(
       MediaStreamComponent*,
       int context_sample_rate);
@@ -70,8 +69,6 @@
 
   void DidStopMediaStreamSource(MediaStreamSource*);
 
-  void GetSourceSettings(MediaStreamSource*, WebMediaStreamTrack::Settings&);
-
  private:
   MediaStreamCenter();
 
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_component.cc b/third_party/blink/renderer/platform/mediastream/media_stream_component.cc
index de2c065..0e48a23 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_component.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_component.cc
@@ -35,7 +35,6 @@
 #include "third_party/blink/public/platform/web_media_stream_track.h"
 #include "third_party/blink/renderer/platform/audio/audio_bus.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/mediastream/media_stream_center.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
 #include "third_party/blink/renderer/platform/wtf/uuid.h"
 
@@ -106,7 +105,9 @@
     return;
   content_hint_ = hint;
 
-  MediaStreamCenter::Instance().DidSetContentHint(this);
+  WebPlatformMediaStreamTrack* native_track = GetPlatformTrack();
+  if (native_track)
+    native_track->SetContentHint(ContentHint());
 }
 
 void MediaStreamComponent::AudioSourceProviderImpl::ProvideInput(
diff --git a/third_party/blink/renderer/platform/mediastream/media_stream_source.cc b/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
index 32f2f5a..354e0e0a 100644
--- a/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
+++ b/third_party/blink/renderer/platform/mediastream/media_stream_source.cc
@@ -30,11 +30,33 @@
 
 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
 
-#include "third_party/blink/renderer/platform/mediastream/media_stream_center.h"
+#include "third_party/blink/public/platform/modules/mediastream/media_stream_audio_source.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 
 namespace blink {
 
+namespace {
+
+void GetSourceSettings(const blink::WebMediaStreamSource& web_source,
+                       blink::WebMediaStreamTrack::Settings& settings) {
+  blink::MediaStreamAudioSource* const source =
+      blink::MediaStreamAudioSource::From(web_source);
+  if (!source)
+    return;
+
+  media::AudioParameters audio_parameters = source->GetAudioParameters();
+  if (audio_parameters.IsValid()) {
+    settings.sample_rate = audio_parameters.sample_rate();
+    settings.channel_count = audio_parameters.channels();
+    settings.latency = audio_parameters.GetBufferDuration().InSecondsF();
+  }
+  // kSampleFormatS16 is the format used for all audio input streams.
+  settings.sample_size =
+      media::SampleFormatToBitsPerChannel(media::kSampleFormatS16);
+}
+
+}  // namespace
+
 MediaStreamSource::MediaStreamSource(const String& id,
                                      StreamType type,
                                      const String& name,
@@ -144,7 +166,7 @@
   if (noise_supression_)
     settings.noise_supression = *noise_supression_;
 
-  MediaStreamCenter::Instance().GetSourceSettings(this, settings);
+  GetSourceSettings(this, settings);
 }
 
 void MediaStreamSource::SetAudioFormat(size_t number_of_channels,
diff --git a/third_party/blink/renderer/platform/mojo/blink_typemaps.gni b/third_party/blink/renderer/platform/mojo/blink_typemaps.gni
index 0925c08..81af75d7 100644
--- a/third_party/blink/renderer/platform/mojo/blink_typemaps.gni
+++ b/third_party/blink/renderer/platform/mojo/blink_typemaps.gni
@@ -4,6 +4,8 @@
 
 typemaps = [
   "//media/capture/mojom/video_capture_types_for_blink.typemap",
+  "//mojo/public/cpp/base/values.typemap",
+  "//ui/gfx/mojom/color_space_for_blink.typemap",
   "//ui/gfx/mojom/transform.typemap",
   "//services/network/public/cpp/http_request_headers.typemap",
   "//third_party/blink/renderer/core/messaging/blink_cloneable_message.typemap",
diff --git a/third_party/blink/renderer/platform/video_capture/DEPS b/third_party/blink/renderer/platform/video_capture/DEPS
new file mode 100644
index 0000000..cc06b7a
--- /dev/null
+++ b/third_party/blink/renderer/platform/video_capture/DEPS
@@ -0,0 +1,19 @@
+include_rules = [
+    # Don't depend on platform.
+    "-third_party/blink/renderer/platform",
+
+    # Module.
+    "+third_party/blink/renderer/platform/video_capture",
+
+    # Dependencies.
+    "+media/base",
+    "+media/capture",
+    "+third_party/blink/renderer/platform/wtf",
+    "+third_party/blink/renderer/platform/platform_export.h",
+]
+
+specific_include_rules = {
+    "video_capture_impl_test.cc": [
+        "+third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h",
+    ],
+}
diff --git a/third_party/blink/renderer/platform/video_capture/OWNERS b/third_party/blink/renderer/platform/video_capture/OWNERS
new file mode 100644
index 0000000..0a6f62e
--- /dev/null
+++ b/third_party/blink/renderer/platform/video_capture/OWNERS
@@ -0,0 +1,4 @@
+chfremer@chromium.org
+guidou@chromium.org
+
+# COMPONENT: Blink>GetUserMedia>Webcam
diff --git a/content/renderer/media/video_capture/video_capture_impl.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
similarity index 80%
rename from content/renderer/media/video_capture/video_capture_impl.cc
rename to third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
index 25688a141f..cb58719 100644
--- a/content/renderer/media/video_capture/video_capture_impl.cc
+++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
@@ -9,36 +9,36 @@
 // VideoCaptureImpl never post task to itself. All operations must be
 // synchronous.
 
-#include "content/renderer/media/video_capture/video_capture_impl.h"
+#include "third_party/blink/renderer/platform/video_capture/video_capture_impl.h"
 
 #include <stddef.h>
 #include <algorithm>
 #include <memory>
 #include <utility>
-#include <vector>
 
 #include "base/bind.h"
 #include "base/macros.h"
 #include "base/stl_util.h"
 #include "base/trace_event/trace_event.h"
-#include "content/child/child_process.h"
-#include "content/public/child/child_thread.h"
-#include "content/public/common/service_names.mojom.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/limits.h"
 #include "media/base/video_frame.h"
-#include "media/capture/mojom/video_capture_types.mojom.h"
+#include "media/capture/mojom/video_capture_types.mojom-blink.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
 
-namespace content {
+namespace blink {
 
-using VideoFrameBufferHandleType = media::mojom::VideoBufferHandle::Tag;
+using VideoFrameBufferHandleType = media::mojom::blink::VideoBufferHandle::Tag;
 
 struct VideoCaptureImpl::BufferContext
     : public base::RefCountedThreadSafe<BufferContext> {
  public:
-  explicit BufferContext(media::mojom::VideoBufferHandlePtr buffer_handle)
+  explicit BufferContext(
+      media::mojom::blink::VideoBufferHandlePtr buffer_handle)
       : buffer_type_(buffer_handle->which()) {
     switch (buffer_type_) {
       case VideoFrameBufferHandleType::SHARED_BUFFER_HANDLE:
@@ -67,7 +67,7 @@
   VideoFrameBufferHandleType buffer_type() const { return buffer_type_; }
   const uint8_t* data() const { return data_; }
   size_t data_size() const { return data_size_; }
-  const std::vector<gpu::MailboxHolder>& mailbox_holders() const {
+  const Vector<gpu::MailboxHolder>& mailbox_holders() const {
     return mailbox_holders_;
   }
 
@@ -99,7 +99,7 @@
   }
 
   void InitializeFromMailbox(
-      media::mojom::MailboxBufferHandleSetPtr mailbox_handles) {
+      media::mojom::blink::MailboxBufferHandleSetPtr mailbox_handles) {
     DCHECK_EQ(media::VideoFrame::kMaxPlanes,
               mailbox_handles->mailbox_holder.size());
     mailbox_holders_ = std::move(mailbox_handles->mailbox_holder);
@@ -122,7 +122,7 @@
   size_t data_size_ = 0;
 
   // Only valid for |buffer_type_ == MAILBOX_HANDLES|.
-  std::vector<gpu::MailboxHolder> mailbox_holders_;
+  Vector<gpu::MailboxHolder> mailbox_holders_;
 
   DISALLOW_COPY_AND_ASSIGN(BufferContext);
 };
@@ -137,9 +137,9 @@
 
   media::VideoCaptureParams params;
 
-  blink::VideoCaptureStateUpdateCB state_update_cb;
+  VideoCaptureStateUpdateCB state_update_cb;
 
-  blink::VideoCaptureDeliverFrameCB deliver_frame_cb;
+  VideoCaptureDeliverFrameCB deliver_frame_cb;
 };
 
 VideoCaptureImpl::VideoCaptureImpl(media::VideoCaptureSessionId session_id)
@@ -149,27 +149,25 @@
       observer_binding_(this),
       state_(blink::VIDEO_CAPTURE_STATE_STOPPED) {
   CHECK(!session_id.is_empty());
-  io_thread_checker_.DetachFromThread();
+  DETACH_FROM_THREAD(io_thread_checker_);
 
-  if (ChildThread::Get()) {  // This will be null in unit tests.
-    media::mojom::VideoCaptureHostPtr temp_video_capture_host;
-    ChildThread::Get()->GetConnector()->BindInterface(
-        mojom::kBrowserServiceName,
-        mojo::MakeRequest(&temp_video_capture_host));
-    video_capture_host_info_ = temp_video_capture_host.PassInterface();
-  }
+  media::mojom::blink::VideoCaptureHostPtr temp_video_capture_host;
+  Platform::Current()->GetConnector()->BindInterface(
+      Platform::Current()->GetBrowserServiceName(),
+      mojo::MakeRequest(&temp_video_capture_host));
+  video_capture_host_info_ = temp_video_capture_host.PassInterface();
 }
 
 VideoCaptureImpl::~VideoCaptureImpl() {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
-  if ((state_ == blink::VIDEO_CAPTURE_STATE_STARTING ||
-       state_ == blink::VIDEO_CAPTURE_STATE_STARTED) &&
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  if ((state_ == VIDEO_CAPTURE_STATE_STARTING ||
+       state_ == VIDEO_CAPTURE_STATE_STARTED) &&
       GetVideoCaptureHost())
     GetVideoCaptureHost()->Stop(device_id_);
 }
 
 void VideoCaptureImpl::SuspendCapture(bool suspend) {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   if (suspend)
     GetVideoCaptureHost()->Pause(device_id_);
   else
@@ -179,10 +177,10 @@
 void VideoCaptureImpl::StartCapture(
     int client_id,
     const media::VideoCaptureParams& params,
-    const blink::VideoCaptureStateUpdateCB& state_update_cb,
-    const blink::VideoCaptureDeliverFrameCB& deliver_frame_cb) {
+    const VideoCaptureStateUpdateCB& state_update_cb,
+    const VideoCaptureDeliverFrameCB& deliver_frame_cb) {
   DVLOG(1) << __func__ << " |device_id_| = " << device_id_;
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   OnLog("VideoCaptureImpl got request to start capture.");
 
   ClientInfo client_info;
@@ -191,8 +189,8 @@
   client_info.deliver_frame_cb = deliver_frame_cb;
 
   switch (state_) {
-    case blink::VIDEO_CAPTURE_STATE_STARTING:
-    case blink::VIDEO_CAPTURE_STATE_STARTED:
+    case VIDEO_CAPTURE_STATE_STARTING:
+    case VIDEO_CAPTURE_STATE_STARTED:
       clients_[client_id] = client_info;
       OnLog("VideoCaptureImpl capture is already started or starting.");
       // TODO(sheu): Allowing resolution change will require that all
@@ -200,13 +198,13 @@
       DCHECK_EQ(params_.resolution_change_policy,
                 params.resolution_change_policy);
       return;
-    case blink::VIDEO_CAPTURE_STATE_STOPPING:
+    case VIDEO_CAPTURE_STATE_STOPPING:
       clients_pending_on_restart_[client_id] = client_info;
       DVLOG(1) << __func__ << " Got new resolution while stopping: "
                << params.requested_format.frame_size.ToString();
       return;
-    case blink::VIDEO_CAPTURE_STATE_STOPPED:
-    case blink::VIDEO_CAPTURE_STATE_ENDED:
+    case VIDEO_CAPTURE_STATE_STOPPED:
+    case VIDEO_CAPTURE_STATE_ENDED:
       clients_[client_id] = client_info;
       params_ = params;
       params_.requested_format.frame_rate =
@@ -218,12 +216,12 @@
       OnLog("VideoCaptureImpl starting capture.");
       StartCaptureInternal();
       return;
-    case blink::VIDEO_CAPTURE_STATE_ERROR:
+    case VIDEO_CAPTURE_STATE_ERROR:
       OnLog("VideoCaptureImpl is in error state.");
       state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_ERROR);
       return;
-    case blink::VIDEO_CAPTURE_STATE_PAUSED:
-    case blink::VIDEO_CAPTURE_STATE_RESUMED:
+    case VIDEO_CAPTURE_STATE_PAUSED:
+    case VIDEO_CAPTURE_STATE_RESUMED:
       // The internal |state_| is never set to PAUSED/RESUMED since
       // VideoCaptureImpl is not modified by those.
       NOTREACHED();
@@ -232,7 +230,7 @@
 }
 
 void VideoCaptureImpl::StopCapture(int client_id) {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   // A client ID can be in only one client list.
   // If this ID is in any client list, we can just remove it from
   // that client list and don't have to run the other following RemoveClient().
@@ -249,13 +247,13 @@
 }
 
 void VideoCaptureImpl::RequestRefreshFrame() {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   GetVideoCaptureHost()->RequestRefreshFrame(device_id_);
 }
 
 void VideoCaptureImpl::GetDeviceSupportedFormats(
-    blink::VideoCaptureDeviceFormatsCB callback) {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+    VideoCaptureDeviceFormatsCallback callback) {
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   GetVideoCaptureHost()->GetDeviceSupportedFormats(
       device_id_, session_id_,
       base::BindOnce(&VideoCaptureImpl::OnDeviceSupportedFormats,
@@ -263,8 +261,8 @@
 }
 
 void VideoCaptureImpl::GetDeviceFormatsInUse(
-    blink::VideoCaptureDeviceFormatsCB callback) {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+    VideoCaptureDeviceFormatsCallback callback) {
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   GetVideoCaptureHost()->GetDeviceFormatsInUse(
       device_id_, session_id_,
       base::BindOnce(&VideoCaptureImpl::OnDeviceFormatsInUse,
@@ -277,17 +275,17 @@
 }
 
 void VideoCaptureImpl::OnLog(const std::string& message) {
-  GetVideoCaptureHost()->OnLog(device_id_, message);
+  GetVideoCaptureHost()->OnLog(device_id_, WTF::String(message.data()));
 }
 
 void VideoCaptureImpl::OnStateChanged(media::mojom::VideoCaptureState state) {
   DVLOG(1) << __func__ << " state: " << state;
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
 
   switch (state) {
     case media::mojom::VideoCaptureState::STARTED:
       OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_STARTED");
-      state_ = blink::VIDEO_CAPTURE_STATE_STARTED;
+      state_ = VIDEO_CAPTURE_STATE_STARTED;
       for (const auto& client : clients_)
         client.second.state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_STARTED);
       // In case there is any frame dropped before STARTED, always request for
@@ -297,7 +295,7 @@
       break;
     case media::mojom::VideoCaptureState::STOPPED:
       OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_STOPPED");
-      state_ = blink::VIDEO_CAPTURE_STATE_STOPPED;
+      state_ = VIDEO_CAPTURE_STATE_STOPPED;
       client_buffers_.clear();
       weak_factory_.InvalidateWeakPtrs();
       if (!clients_.empty() || !clients_pending_on_restart_.empty()) {
@@ -318,7 +316,7 @@
       for (const auto& client : clients_)
         client.second.state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_ERROR);
       clients_.clear();
-      state_ = blink::VIDEO_CAPTURE_STATE_ERROR;
+      state_ = VIDEO_CAPTURE_STATE_ERROR;
       break;
     case media::mojom::VideoCaptureState::ENDED:
       OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_ENDED");
@@ -326,16 +324,16 @@
       for (const auto& client : clients_)
         client.second.state_update_cb.Run(blink::VIDEO_CAPTURE_STATE_STOPPED);
       clients_.clear();
-      state_ = blink::VIDEO_CAPTURE_STATE_ENDED;
+      state_ = VIDEO_CAPTURE_STATE_ENDED;
       break;
   }
 }
 
 void VideoCaptureImpl::OnNewBuffer(
     int32_t buffer_id,
-    media::mojom::VideoBufferHandlePtr buffer_handle) {
+    media::mojom::blink::VideoBufferHandlePtr buffer_handle) {
   DVLOG(1) << __func__ << " buffer_id: " << buffer_id;
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
 
   const bool inserted =
       client_buffers_
@@ -345,12 +343,13 @@
   DCHECK(inserted);
 }
 
-void VideoCaptureImpl::OnBufferReady(int32_t buffer_id,
-                                     media::mojom::VideoFrameInfoPtr info) {
+void VideoCaptureImpl::OnBufferReady(
+    int32_t buffer_id,
+    media::mojom::blink::VideoFrameInfoPtr info) {
   DVLOG(1) << __func__ << " buffer_id: " << buffer_id;
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
 
-  bool consume_buffer = state_ == blink::VIDEO_CAPTURE_STATE_STARTED;
+  bool consume_buffer = state_ == VIDEO_CAPTURE_STATE_STARTED;
   if (!consume_buffer) {
     OnFrameDropped(
         media::VideoCaptureFrameDropReason::kVideoCaptureImplNotInStartedState);
@@ -402,23 +401,26 @@
         uint8_t* u_data =
             y_data + (media::VideoFrame::Rows(media::VideoFrame::kYPlane,
                                               info->pixel_format,
-                                              info->coded_size.height()) *
+                                              info->coded_size.height) *
                       info->strides->stride_by_plane[0]);
         uint8_t* v_data =
             u_data + (media::VideoFrame::Rows(media::VideoFrame::kUPlane,
                                               info->pixel_format,
-                                              info->coded_size.height()) *
+                                              info->coded_size.height) *
                       info->strides->stride_by_plane[1]);
         frame = media::VideoFrame::WrapExternalYuvData(
-            info->pixel_format, info->coded_size, info->visible_rect,
-            info->visible_rect.size(), info->strides->stride_by_plane[0],
+            info->pixel_format, gfx::Size(info->coded_size),
+            gfx::Rect(info->visible_rect),
+            gfx::Size(info->visible_rect.width, info->visible_rect.height),
+            info->strides->stride_by_plane[0],
             info->strides->stride_by_plane[1],
             info->strides->stride_by_plane[2], y_data, u_data, v_data,
             info->timestamp);
       } else {
         frame = media::VideoFrame::WrapExternalData(
-            info->pixel_format, info->coded_size, info->visible_rect,
-            info->visible_rect.size(),
+            info->pixel_format, gfx::Size(info->coded_size),
+            gfx::Rect(info->visible_rect),
+            gfx::Size(info->visible_rect.width, info->visible_rect.height),
             const_cast<uint8_t*>(buffer_context->data()),
             buffer_context->data_size(), info->timestamp);
       }
@@ -427,8 +429,9 @@
       // As with the SHARED_BUFFER_HANDLE type, it is sufficient to just wrap
       // the data without attaching the shared region to the frame.
       frame = media::VideoFrame::WrapExternalData(
-          info->pixel_format, info->coded_size, info->visible_rect,
-          info->visible_rect.size(),
+          info->pixel_format, gfx::Size(info->coded_size),
+          gfx::Rect(info->visible_rect),
+          gfx::Size(info->visible_rect.width, info->visible_rect.height),
           const_cast<uint8_t*>(buffer_context->data()),
           buffer_context->data_size(), info->timestamp);
       break;
@@ -444,8 +447,10 @@
       }
       frame = media::VideoFrame::WrapNativeTextures(
           info->pixel_format, mailbox_holder_array,
-          media::VideoFrame::ReleaseMailboxCB(), info->coded_size,
-          info->visible_rect, info->visible_rect.size(), info->timestamp);
+          media::VideoFrame::ReleaseMailboxCB(), gfx::Size(info->coded_size),
+          gfx::Rect(info->visible_rect),
+          gfx::Size(info->visible_rect.width, info->visible_rect.height),
+          info->timestamp);
       break;
     }
 #if defined(OS_CHROMEOS)
@@ -480,7 +485,7 @@
 }
 
 void VideoCaptureImpl::OnBufferDestroyed(int32_t buffer_id) {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
 
   const auto& cb_iter = client_buffers_.find(buffer_id);
   if (cb_iter != client_buffers_.end()) {
@@ -494,7 +499,7 @@
     int buffer_id,
     scoped_refptr<BufferContext> buffer_context,
     double consumer_resource_utilization) {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
 
 // Subtle race note: It's important that the |buffer_context| argument be
 // std::move()'ed to this method and never copied. This is so that the caller,
@@ -520,19 +525,19 @@
 }
 
 void VideoCaptureImpl::StopDevice() {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
-  if (state_ != blink::VIDEO_CAPTURE_STATE_STARTING &&
-      state_ != blink::VIDEO_CAPTURE_STATE_STARTED)
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  if (state_ != VIDEO_CAPTURE_STATE_STARTING &&
+      state_ != VIDEO_CAPTURE_STATE_STARTED)
     return;
-  state_ = blink::VIDEO_CAPTURE_STATE_STOPPING;
+  state_ = VIDEO_CAPTURE_STATE_STOPPING;
   OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_STOPPING");
   GetVideoCaptureHost()->Stop(device_id_);
   params_.requested_format.frame_size.SetSize(0, 0);
 }
 
 void VideoCaptureImpl::RestartCapture() {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(state_, blink::VIDEO_CAPTURE_STATE_STOPPED);
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPED);
 
   int width = 0;
   int height = 0;
@@ -551,32 +556,32 @@
 }
 
 void VideoCaptureImpl::StartCaptureInternal() {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
-  state_ = blink::VIDEO_CAPTURE_STATE_STARTING;
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  state_ = VIDEO_CAPTURE_STATE_STARTING;
   OnLog("VideoCaptureImpl changing state to VIDEO_CAPTURE_STATE_STARTING");
 
-  media::mojom::VideoCaptureObserverPtr observer;
+  media::mojom::blink::VideoCaptureObserverPtr observer;
   observer_binding_.Bind(mojo::MakeRequest(&observer));
   GetVideoCaptureHost()->Start(device_id_, session_id_, params_,
                                std::move(observer));
 }
 
 void VideoCaptureImpl::OnDeviceSupportedFormats(
-    blink::VideoCaptureDeviceFormatsCB callback,
-    const media::VideoCaptureFormats& supported_formats) {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+    VideoCaptureDeviceFormatsCallback callback,
+    const Vector<media::VideoCaptureFormat>& supported_formats) {
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   std::move(callback).Run(supported_formats);
 }
 
 void VideoCaptureImpl::OnDeviceFormatsInUse(
-    blink::VideoCaptureDeviceFormatsCB callback,
-    const media::VideoCaptureFormats& formats_in_use) {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+    VideoCaptureDeviceFormatsCallback callback,
+    const Vector<media::VideoCaptureFormat>& formats_in_use) {
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   std::move(callback).Run(formats_in_use);
 }
 
 bool VideoCaptureImpl::RemoveClient(int client_id, ClientInfoMap* clients) {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
 
   const ClientInfoMap::iterator it = clients->find(client_id);
   if (it == clients->end())
@@ -587,8 +592,8 @@
   return true;
 }
 
-media::mojom::VideoCaptureHost* VideoCaptureImpl::GetVideoCaptureHost() {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
+media::mojom::blink::VideoCaptureHost* VideoCaptureImpl::GetVideoCaptureHost() {
+  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
   if (video_capture_host_for_testing_)
     return video_capture_host_for_testing_;
 
@@ -611,4 +616,4 @@
   std::move(callback_to_io_thread).Run(consumer_resource_utilization);
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/content/renderer/media/video_capture/video_capture_impl.h b/third_party/blink/renderer/platform/video_capture/video_capture_impl.h
similarity index 72%
rename from content/renderer/media/video_capture/video_capture_impl.h
rename to third_party/blink/renderer/platform/video_capture/video_capture_impl.h
index 99e8b7b..fccc4def 100644
--- a/content/renderer/media/video_capture/video_capture_impl.h
+++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.h
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_IMPL_H_
-#define CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_IMPL_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_VIDEO_CAPTURE_VIDEO_CAPTURE_IMPL_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_VIDEO_CAPTURE_VIDEO_CAPTURE_IMPL_H_
 
 #include <stdint.h>
-
 #include <list>
 #include <map>
 #include <string>
@@ -14,22 +13,22 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
-#include "content/common/content_export.h"
 #include "media/base/video_frame.h"
-#include "media/capture/mojom/video_capture.mojom.h"
+#include "media/capture/mojom/video_capture.mojom-blink.h"
 #include "media/capture/video_capture_types.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/blink/public/common/media/video_capture.h"
+#include "third_party/blink/renderer/platform/platform_export.h"
 
-namespace content {
+namespace blink {
 
 // VideoCaptureImpl represents a capture device in renderer process. It provides
 // an interface for clients to command the capture (Start, Stop, etc), and
 // communicates back to these clients e.g. the capture state or incoming
 // captured VideoFrames. VideoCaptureImpl is created in the main Renderer thread
 // but otherwise operates on |io_task_runner_|, which is usually the IO thread.
-class CONTENT_EXPORT VideoCaptureImpl
-    : public media::mojom::VideoCaptureObserver {
+class PLATFORM_EXPORT VideoCaptureImpl
+    : public media::mojom::blink::VideoCaptureObserver {
  public:
   explicit VideoCaptureImpl(media::VideoCaptureSessionId session_id);
   ~VideoCaptureImpl() override;
@@ -44,8 +43,8 @@
   // |deliver_frame_cb| will be called when a frame is ready.
   void StartCapture(int client_id,
                     const media::VideoCaptureParams& params,
-                    const blink::VideoCaptureStateUpdateCB& state_update_cb,
-                    const blink::VideoCaptureDeliverFrameCB& deliver_frame_cb);
+                    const VideoCaptureStateUpdateCB& state_update_cb,
+                    const VideoCaptureDeliverFrameCB& deliver_frame_cb);
 
   // Stop capturing. |client_id| is the identifier used to call StartCapture.
   void StopCapture(int client_id);
@@ -56,27 +55,32 @@
 
   // Get capturing formats supported by this device.
   // |callback| will be invoked with the results.
-  void GetDeviceSupportedFormats(blink::VideoCaptureDeviceFormatsCB callback);
+  //
+  using VideoCaptureDeviceFormatsCallback =
+      base::OnceCallback<void(const Vector<media::VideoCaptureFormat>&)>;
+  void GetDeviceSupportedFormats(VideoCaptureDeviceFormatsCallback callback);
 
   // Get capturing formats currently in use by this device.
   // |callback| will be invoked with the results.
-  void GetDeviceFormatsInUse(blink::VideoCaptureDeviceFormatsCB callback);
+  void GetDeviceFormatsInUse(VideoCaptureDeviceFormatsCallback callback);
 
   void OnFrameDropped(media::VideoCaptureFrameDropReason reason);
   void OnLog(const std::string& message);
 
   const media::VideoCaptureSessionId& session_id() const { return session_id_; }
 
-  void SetVideoCaptureHostForTesting(media::mojom::VideoCaptureHost* service) {
+  void SetVideoCaptureHostForTesting(
+      media::mojom::blink::VideoCaptureHost* service) {
     video_capture_host_for_testing_ = service;
   }
 
   // media::mojom::VideoCaptureObserver implementation.
   void OnStateChanged(media::mojom::VideoCaptureState state) override;
-  void OnNewBuffer(int32_t buffer_id,
-                   media::mojom::VideoBufferHandlePtr buffer_handle) override;
+  void OnNewBuffer(
+      int32_t buffer_id,
+      media::mojom::blink::VideoBufferHandlePtr buffer_handle) override;
   void OnBufferReady(int32_t buffer_id,
-                     media::mojom::VideoFrameInfoPtr info) override;
+                     media::mojom::blink::VideoFrameInfoPtr info) override;
   void OnBufferDestroyed(int32_t buffer_id) override;
 
  private:
@@ -103,15 +107,17 @@
   void StartCaptureInternal();
 
   void OnDeviceSupportedFormats(
-      blink::VideoCaptureDeviceFormatsCB callback,
-      const media::VideoCaptureFormats& supported_formats);
-  void OnDeviceFormatsInUse(blink::VideoCaptureDeviceFormatsCB callback,
-                            const media::VideoCaptureFormats& formats_in_use);
+      VideoCaptureDeviceFormatsCallback callback,
+      const Vector<media::VideoCaptureFormat>& supported_formats);
+
+  void OnDeviceFormatsInUse(
+      VideoCaptureDeviceFormatsCallback callback,
+      const Vector<media::VideoCaptureFormat>& formats_in_use);
 
   // Tries to remove |client_id| from |clients|, returning false if not found.
   bool RemoveClient(int client_id, ClientInfoMap* clients);
 
-  media::mojom::VideoCaptureHost* GetVideoCaptureHost();
+  media::mojom::blink::VideoCaptureHost* GetVideoCaptureHost();
 
   // Called (by an unknown thread) when all consumers are done with a VideoFrame
   // and its ref-count has gone to zero.  This helper function grabs the
@@ -129,11 +135,11 @@
   // |video_capture_host_| is an IO-thread InterfacePtr to a remote service
   // implementation and is created by binding |video_capture_host_info_|,
   // unless a |video_capture_host_for_testing_| has been injected.
-  media::mojom::VideoCaptureHostPtrInfo video_capture_host_info_;
-  media::mojom::VideoCaptureHostPtr video_capture_host_;
-  media::mojom::VideoCaptureHost* video_capture_host_for_testing_;
+  media::mojom::blink::VideoCaptureHostPtrInfo video_capture_host_info_;
+  media::mojom::blink::VideoCaptureHostPtr video_capture_host_;
+  media::mojom::blink::VideoCaptureHost* video_capture_host_for_testing_;
 
-  mojo::Binding<media::mojom::VideoCaptureObserver> observer_binding_;
+  mojo::Binding<media::mojom::blink::VideoCaptureObserver> observer_binding_;
 
   // Buffers available for sending to the client.
   using ClientBufferMap = std::map<int32_t, scoped_refptr<BufferContext>>;
@@ -148,9 +154,9 @@
   // First captured frame reference time sent from browser process side.
   base::TimeTicks first_frame_ref_time_;
 
-  blink::VideoCaptureState state_;
+  VideoCaptureState state_;
 
-  base::ThreadChecker io_thread_checker_;
+  THREAD_CHECKER(io_thread_checker_);
 
   // WeakPtrFactory pointing back to |this| object, for use with
   // media::VideoFrames constructed in OnBufferReceived() from buffers cached
@@ -160,6 +166,6 @@
   DISALLOW_COPY_AND_ASSIGN(VideoCaptureImpl);
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_IMPL_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_VIDEO_CAPTURE_VIDEO_CAPTURE_IMPL_H_
diff --git a/content/renderer/media/video_capture/video_capture_impl_unittest.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
similarity index 90%
rename from content/renderer/media/video_capture/video_capture_impl_unittest.cc
rename to third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
index 0165684..e5e7375 100644
--- a/content/renderer/media/video_capture/video_capture_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl_test.cc
@@ -4,7 +4,6 @@
 
 #include <stddef.h>
 #include <memory>
-#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -12,13 +11,14 @@
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/memory/unsafe_shared_memory_region.h"
 #include "base/test/scoped_task_environment.h"
-#include "content/child/child_process.h"
-#include "content/renderer/media/video_capture/video_capture_impl.h"
-#include "media/capture/mojom/video_capture.mojom.h"
-#include "media/capture/mojom/video_capture_types.mojom.h"
+#include "media/capture/mojom/video_capture.mojom-blink.h"
+#include "media/capture/mojom/video_capture_types.mojom-blink.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
+#include "third_party/blink/renderer/platform/video_capture/video_capture_impl.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 using ::testing::_;
 using ::testing::InSequence;
@@ -27,20 +27,19 @@
 using ::testing::SaveArg;
 using ::testing::WithArgs;
 
-namespace content {
-
+namespace blink {
 
 void RunEmptyFormatsCallback(
-    media::mojom::VideoCaptureHost::GetDeviceSupportedFormatsCallback&
+    media::mojom::blink::VideoCaptureHost::GetDeviceSupportedFormatsCallback&
         callback) {
-  media::VideoCaptureFormats formats;
+  Vector<media::VideoCaptureFormat> formats;
   std::move(callback).Run(formats);
 }
 
 ACTION(DoNothing) {}
 
 // Mock implementation of the Mojo Host service.
-class MockMojoVideoCaptureHost : public media::mojom::VideoCaptureHost {
+class MockMojoVideoCaptureHost : public media::mojom::blink::VideoCaptureHost {
  public:
   MockMojoVideoCaptureHost() : released_buffer_count_(0) {
     ON_CALL(*this, GetDeviceSupportedFormatsMock(_, _, _))
@@ -56,7 +55,7 @@
   void Start(const base::UnguessableToken& device_id,
              const base::UnguessableToken& session_id,
              const media::VideoCaptureParams& params,
-             media::mojom::VideoCaptureObserverPtr observer) override {
+             media::mojom::blink::VideoCaptureObserverPtr observer) override {
     DoStart(device_id, session_id, params);
   }
   MOCK_METHOD3(DoStart,
@@ -83,7 +82,7 @@
   MOCK_METHOD2(OnFrameDropped,
                void(const base::UnguessableToken&,
                     media::VideoCaptureFrameDropReason));
-  MOCK_METHOD2(OnLog, void(const base::UnguessableToken&, const std::string&));
+  MOCK_METHOD2(OnLog, void(const base::UnguessableToken&, const String&));
 
   void GetDeviceSupportedFormats(
       const base::UnguessableToken& arg1,
@@ -135,10 +134,11 @@
   // These four mocks are used to create callbacks for the different oeprations.
   MOCK_METHOD2(OnFrameReady,
                void(scoped_refptr<media::VideoFrame>, base::TimeTicks));
-  MOCK_METHOD1(OnStateUpdate, void(blink::VideoCaptureState));
-  MOCK_METHOD1(OnDeviceFormatsInUse, void(const media::VideoCaptureFormats&));
+  MOCK_METHOD1(OnStateUpdate, void(VideoCaptureState));
+  MOCK_METHOD1(OnDeviceFormatsInUse,
+               void(const Vector<media::VideoCaptureFormat>&));
   MOCK_METHOD1(OnDeviceSupportedFormats,
-               void(const media::VideoCaptureFormats&));
+               void(const Vector<media::VideoCaptureFormat>&));
 
   void StartCapture(int client_id, const media::VideoCaptureParams& params) {
     const auto state_update_callback = base::Bind(
@@ -157,19 +157,22 @@
   void SimulateOnBufferCreated(int buffer_id,
                                const base::UnsafeSharedMemoryRegion& region) {
     video_capture_impl_->OnNewBuffer(
-        buffer_id, media::mojom::VideoBufferHandle::NewSharedBufferHandle(
-                       mojo::WrapUnsafeSharedMemoryRegion(region.Duplicate())));
+        buffer_id,
+        media::mojom::blink::VideoBufferHandle::NewSharedBufferHandle(
+            mojo::WrapUnsafeSharedMemoryRegion(region.Duplicate())));
   }
 
   void SimulateReadOnlyBufferCreated(int buffer_id,
                                      base::ReadOnlySharedMemoryRegion region) {
     video_capture_impl_->OnNewBuffer(
-        buffer_id, media::mojom::VideoBufferHandle::NewReadOnlyShmemRegion(
-                       std::move(region)));
+        buffer_id,
+        media::mojom::blink::VideoBufferHandle::NewReadOnlyShmemRegion(
+            std::move(region)));
   }
 
   void SimulateBufferReceived(int buffer_id, const gfx::Size& size) {
-    media::mojom::VideoFrameInfoPtr info = media::mojom::VideoFrameInfo::New();
+    media::mojom::blink::VideoFrameInfoPtr info =
+        media::mojom::blink::VideoFrameInfo::New();
 
     const base::TimeTicks now = base::TimeTicks::Now();
     media::VideoFrameMetadata frame_metadata;
@@ -178,8 +181,8 @@
 
     info->timestamp = now - base::TimeTicks();
     info->pixel_format = media::PIXEL_FORMAT_I420;
-    info->coded_size = size;
-    info->visible_rect = gfx::Rect(size);
+    info->coded_size = WebSize(size);
+    info->visible_rect = WebRect(gfx::Rect(size));
 
     video_capture_impl_->OnBufferReady(buffer_id, std::move(info));
   }
@@ -189,16 +192,16 @@
   }
 
   void GetDeviceSupportedFormats() {
-    const base::Callback<void(const media::VideoCaptureFormats&)> callback =
-        base::Bind(&VideoCaptureImplTest::OnDeviceSupportedFormats,
-                   base::Unretained(this));
+    const base::Callback<void(const Vector<media::VideoCaptureFormat>&)>
+        callback = base::Bind(&VideoCaptureImplTest::OnDeviceSupportedFormats,
+                              base::Unretained(this));
     video_capture_impl_->GetDeviceSupportedFormats(callback);
   }
 
   void GetDeviceFormatsInUse() {
-    const base::Callback<void(const media::VideoCaptureFormats&)> callback =
-        base::Bind(&VideoCaptureImplTest::OnDeviceFormatsInUse,
-                   base::Unretained(this));
+    const base::Callback<void(const Vector<media::VideoCaptureFormat>&)>
+        callback = base::Bind(&VideoCaptureImplTest::OnDeviceFormatsInUse,
+                              base::Unretained(this));
     video_capture_impl_->GetDeviceFormatsInUse(callback);
   }
 
@@ -208,7 +211,7 @@
 
   const base::UnguessableToken session_id_ = base::UnguessableToken::Create();
   base::test::ScopedTaskEnvironment scoped_task_environment_;
-  const ChildProcess child_process_;
+  ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
   const std::unique_ptr<VideoCaptureImpl> video_capture_impl_;
   MockMojoVideoCaptureHost mock_video_capture_host_;
   media::VideoCaptureParams params_small_;
@@ -520,4 +523,4 @@
   StopCapture(0);
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index de50a5f..4a9d4f9 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -130660,9 +130660,6 @@
    "css/css-align/resources/alignment-parsing-utils.js": [
     []
    ],
-   "css/css-animations/CSSAnimation-animationName.tentative-expected.txt": [
-    []
-   ],
    "css/css-animations/CSSAnimation-canceling.tentative-expected.txt": [
     []
    ],
@@ -176695,9 +176692,6 @@
    "webxr/resources/webxr_util.js": [
     []
    ],
-   "webxr/xrWebGLLayer_framebuffer.https-expected.txt": [
-    []
-   ],
    "workers/META.yml": [
     []
    ],
@@ -211172,6 +211166,12 @@
      {}
     ]
    ],
+   "css/css-typed-om/the-stylepropertymap/computed/get-auto-min-size.html": [
+    [
+     "css/css-typed-om/the-stylepropertymap/computed/get-auto-min-size.html",
+     {}
+    ]
+   ],
    "css/css-typed-om/the-stylepropertymap/computed/get-invalid.html": [
     [
      "css/css-typed-om/the-stylepropertymap/computed/get-invalid.html",
@@ -214142,6 +214142,12 @@
      {}
     ]
    ],
+   "css/cssom-view/elementFromPoint-list-001.html": [
+    [
+     "css/cssom-view/elementFromPoint-list-001.html",
+     {}
+    ]
+   ],
    "css/cssom-view/elementFromPoint-mixed-font-sizes.html": [
     [
      "css/cssom-view/elementFromPoint-mixed-font-sizes.html",
@@ -300587,12 +300593,6 @@
      {}
     ]
    ],
-   "webxr/xrWebGLLayer_framebuffer.https.html": [
-    [
-     "webxr/xrWebGLLayer_framebuffer.https.html",
-     {}
-    ]
-   ],
    "webxr/xrWebGLLayer_framebuffer_draw.https.html": [
     [
      "webxr/xrWebGLLayer_framebuffer_draw.https.html",
@@ -318035,7 +318035,7 @@
    "testharness"
   ],
   "IndexedDB/idbfactory-databases-opaque-origin.html": [
-   "805c1951b3caae393496b5228a9e31bdf2ae4579",
+   "5f1b3070c638ddf36b7d2d30717c24d324a38f06",
    "testharness"
   ],
   "IndexedDB/idbfactory-deleteDatabase-opaque-origin.html": [
@@ -342458,10 +342458,6 @@
    "fd2197fcace453760d8ef7613139a978ab8ba0e6",
    "testharness"
   ],
-  "css/css-animations/CSSAnimation-animationName.tentative-expected.txt": [
-   "8ac2b7458c70ba15493845c0a999ba14e20afea7",
-   "support"
-  ],
   "css/css-animations/CSSAnimation-animationName.tentative.html": [
    "370d5ef85e27c2e83deb54522a31da9deb8b556c",
    "testharness"
@@ -342519,7 +342515,7 @@
    "testharness"
   ],
   "css/css-animations/CSSPseudoElement-getAnimations.tentative-expected.txt": [
-   "3d3f2b024cabbc400f07043131366e80436d43b1",
+   "08e57b14180dcf962c0e5447f53d775db6b78802",
    "support"
   ],
   "css/css-animations/CSSPseudoElement-getAnimations.tentative.html": [
@@ -342527,7 +342523,7 @@
    "testharness"
   ],
   "css/css-animations/Document-getAnimations.tentative-expected.txt": [
-   "70dfff0455d0f221dbb6e9b638621c9edda14473",
+   "e2affb22cb3d16528bad235ae30faf82c1e357e7",
    "support"
   ],
   "css/css-animations/Document-getAnimations.tentative.html": [
@@ -389254,6 +389250,10 @@
    "9bbcb306998c22dc7770be3a28e0bc3c613827b1",
    "testharness"
   ],
+  "css/css-typed-om/the-stylepropertymap/computed/get-auto-min-size.html": [
+   "3466fb21ca6d78eb963db53e90d6b9e2d2024e9e",
+   "testharness"
+  ],
   "css/css-typed-om/the-stylepropertymap/computed/get-invalid.html": [
    "8117d18b764ced36e845b20e0de6f358d5ed363c",
    "testharness"
@@ -401038,6 +401038,10 @@
    "e0acb90fb8fe76f3b0c5b561d84a3bdc6e05bd78",
    "testharness"
   ],
+  "css/cssom-view/elementFromPoint-list-001.html": [
+   "e3c2c4d18f4c35f31908fd1095b0516fd0161b8a",
+   "testharness"
+  ],
   "css/cssom-view/elementFromPoint-mixed-font-sizes.html": [
    "e2bac90afdfb226aa8e44d40dc36d98423181cc3",
    "testharness"
@@ -422687,7 +422691,7 @@
    "testharness"
   ],
   "html/browsers/history/the-location-interface/location_hash.html": [
-   "ef6f6331389168c8fed45c1eabe810e0cdf5e512",
+   "c063e285ea64cb9e5017976f8dcc3a6a5a31af9b",
    "testharness"
   ],
   "html/browsers/history/the-location-interface/location_host.html": [
@@ -480383,11 +480387,11 @@
    "support"
   ],
   "tools/wptrunner/wptrunner/wptmanifest/node.py": [
-   "33e9796c430c33aa0328559f12079f221180d679",
+   "24d523f924a2cf668de84975671207ada65720bf",
    "support"
   ],
   "tools/wptrunner/wptrunner/wptmanifest/parser.py": [
-   "a8e2bd6db2f36f3034d5beecd40f23f03f6c8a06",
+   "8f1897b08f3e50602afc77d47cf41ee45f70f5fc",
    "support"
   ],
   "tools/wptrunner/wptrunner/wptmanifest/serializer.py": [
@@ -491498,14 +491502,6 @@
    "74f0e7611e5e201a275b1a444a6d4b367af3e53d",
    "testharness"
   ],
-  "webxr/xrWebGLLayer_framebuffer.https-expected.txt": [
-   "54e5aa445b27baa62ee3c94a64c96b942edfdbb6",
-   "support"
-  ],
-  "webxr/xrWebGLLayer_framebuffer.https.html": [
-   "ba6b7dc0b922ae45aa714de8d3ca6f4ffbaf414c",
-   "testharness"
-  ],
   "webxr/xrWebGLLayer_framebuffer_draw.https.html": [
    "dd40865e445aafce88f5941f4127236c36f01f2d",
    "testharness"
@@ -491515,7 +491511,7 @@
    "testharness"
   ],
   "webxr/xrWebGLLayer_opaque_framebuffer.https.html": [
-   "ceff6251d565726ddb56798da7bbbef649d96d2f",
+   "37955f3988d125b9b16959d0a55e40ce75934de6",
    "testharness"
   ],
   "webxr/xrWebGLLayer_viewports.https.html": [
diff --git a/third_party/blink/web_tests/external/wpt/IndexedDB/idbfactory-databases-opaque-origin.html b/third_party/blink/web_tests/external/wpt/IndexedDB/idbfactory-databases-opaque-origin.html
index 805c195..5f1b307 100644
--- a/third_party/blink/web_tests/external/wpt/IndexedDB/idbfactory-databases-opaque-origin.html
+++ b/third_party/blink/web_tests/external/wpt/IndexedDB/idbfactory-databases-opaque-origin.html
@@ -31,9 +31,16 @@
 const script =
   '<script>' +
   '  window.onmessage = () => {' +
-  '    indexedDB.databases().then(' +
-  '      () => window.parent.postMessage({result: "no exception"}, "*"),' +
-  '      ex => window.parent.postMessage({result: ex.name}, "*"));' +
+  '    try { ' +
+  '      if (!indexedDB || !indexedDB.databases) {' +
+  '        window.parent.postMessage({result: "indexedDB.databases undefined"}, "*")' +
+  '      }' +
+  '      indexedDB.databases().then(' +
+  '        () => window.parent.postMessage({result: "no exception"}, "*"),' +
+  '        ex => window.parent.postMessage({result: ex.name}, "*"));' +
+  '    } catch(e) { ' +
+  '      window.parent.postMessage({result: e.name + " thrown, not rejected"}, "*")' +
+  '    }'+
   '  };' +
   '<\/script>';
 
@@ -50,6 +57,6 @@
   iframe.contentWindow.postMessage({}, '*');
   const message = await wait_for_message(iframe);
   assert_equals(message.result, 'SecurityError',
-                'Exception should be SecurityError');
+                'Promise should be rejected with SecurityError');
 }, 'IDBFactory.databases() in sandboxed iframe should reject');
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.https.window.js
index f2c2fc8..acc0be1 100644
--- a/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/native-file-system/FileSystemWriter.tentative.https.window.js
@@ -136,3 +136,156 @@
     assert_equals(await getFileContents(handle), 'abc\0\0');
     assert_equals(await getFileSize(handle), 5);
 }, 'truncate() to grow a file');
+
+promise_test(async t => {
+  const root = await FileSystemDirectoryHandle.getSystemDirectory({ type: 'sandbox' });
+  const dir = await createDirectory(t, 'parent_dir', root);
+  const file_name = 'create_writer_fails_when_dir_removed.txt';
+  const handle = await createEmptyFile(t, file_name, dir);
+
+  await root.removeEntry('parent_dir', {recursive: true});
+  await promise_rejects(t, 'NotFoundError', handle.createWriter());
+}, 'createWriter() fails when parent directory is removed');
+
+promise_test(async t => {
+  const root = await FileSystemDirectoryHandle.getSystemDirectory({ type: 'sandbox' });
+  const dir = await createDirectory(t, 'parent_dir', root);
+  const file_name = 'write_fails_when_dir_removed.txt';
+  const handle = await createEmptyFile(t, file_name, dir);
+  const writer = await handle.createWriter();
+
+  await root.removeEntry('parent_dir', {recursive: true});
+  await promise_rejects(t, 'NotFoundError', writer.write(0, new Blob(['foo'])));
+}, 'write() fails when parent directory is removed');
+
+promise_test(async t => {
+  const root = await FileSystemDirectoryHandle.getSystemDirectory({ type: 'sandbox' });
+  const dir = await createDirectory(t, 'parent_dir', root);
+  const file_name = 'truncate_fails_when_dir_removed.txt';
+  const handle = await createEmptyFile(t, file_name, dir);
+  const writer = await handle.createWriter();
+
+  await root.removeEntry('parent_dir', {recursive: true});
+  await promise_rejects(t, 'NotFoundError', writer.truncate(0));
+}, 'truncate() fails when parent directory is removed');
+
+promise_test(async t => {
+  const root = await FileSystemDirectoryHandle.getSystemDirectory({ type: 'sandbox' });
+  const dir = await createDirectory(t, 'parent_dir', root);
+  const file_name = 'close_fails_when_dir_removed.txt';
+  const handle = await createEmptyFile(t, file_name, dir);
+  const writer = await handle.createWriter();
+  await writer.write(0, new Blob(['foo']));
+
+  await root.removeEntry('parent_dir', {recursive: true});
+  await promise_rejects(t, 'NotFoundError', writer.close());
+}, 'atomic writes: close() fails when parent directory is removed');
+
+promise_test(async t => {
+  const handle = await createEmptyFile(t, 'atomic_writes.txt');
+  const writer = await handle.createWriter();
+  await writer.write(0, new Blob(['foox']));
+
+  const writer2 = await handle.createWriter();
+  await writer2.write(0, new Blob(['bar']));
+
+  assert_equals(await getFileSize(handle), 0);
+
+  await writer2.close();
+  assert_equals(await getFileContents(handle), 'bar');
+  assert_equals(await getFileSize(handle), 3);
+
+  await writer.close();
+  assert_equals(await getFileContents(handle), 'foox');
+  assert_equals(await getFileSize(handle), 4);
+}, 'atomic writes: writers make atomic changes on close');
+
+promise_test(async t => {
+  const handle = await createEmptyFile(t, 'atomic_write_after_close.txt');
+  const writer = await handle.createWriter();
+  await writer.write(0, new Blob(['foo']));
+
+  await writer.close();
+  assert_equals(await getFileContents(handle), 'foo');
+  assert_equals(await getFileSize(handle), 3);
+
+  await promise_rejects(t, 'InvalidStateError', writer.write(0, new Blob(['abc'])));
+}, 'atomic writes: write() after close() fails');
+
+promise_test(async t => {
+  const handle = await createEmptyFile(t, 'atomic_truncate_after_close.txt');
+  const writer = await handle.createWriter();
+  await writer.write(0, new Blob(['foo']));
+
+  await writer.close();
+  assert_equals(await getFileContents(handle), 'foo');
+  assert_equals(await getFileSize(handle), 3);
+
+  await promise_rejects(t, 'InvalidStateError', writer.truncate(0));
+}, 'atomic writes: truncate() after close() fails');
+
+promise_test(async t => {
+  const handle = await createEmptyFile(t, 'atomic_close_after_close.txt');
+  const writer = await handle.createWriter();
+  await writer.write(0, new Blob(['foo']));
+
+  await writer.close();
+  assert_equals(await getFileContents(handle), 'foo');
+  assert_equals(await getFileSize(handle), 3);
+
+  await promise_rejects(t, 'InvalidStateError', writer.close());
+}, 'atomic writes: close() after close() fails');
+
+promise_test(async t => {
+  const handle = await createEmptyFile(t, 'there_can_be_only_one.txt');
+  const writer = await handle.createWriter();
+  await writer.write(0, new Blob(['foo']));
+
+  // This test might be flaky if there is a race condition allowing
+  // close() to be called multiple times.
+  let success_promises = [...Array(100)].map(() => writer
+                                             .close()
+                                             .then(() => 1)
+                                             .catch(() => 0));
+  let close_attempts = await Promise.all(success_promises);
+  let success_count = close_attempts.reduce((x,y) => x + y);
+  assert_equals(success_count, 1);
+}, 'atomic writes: only one close() operation may succeed');
+
+promise_test(async t => {
+  const handle = await createFileWithContents(t, 'atomic_file_is_copied.txt', 'fooks');
+  const writer = await handle.createWriter({keepExistingData: true});
+
+  await writer.write(0, new Blob(['bar']));
+  await writer.close();
+  assert_equals(await getFileContents(handle), 'barks');
+  assert_equals(await getFileSize(handle), 5);
+}, 'createWriter({keepExistingData: true}): atomic writer initialized with source contents');
+
+promise_test(async t => {
+  const handle = await createFileWithContents(t, 'atomic_file_is_not_copied.txt', 'very long string');
+  const writer = await handle.createWriter({keepExistingData: false});
+
+  await writer.write(0, new Blob(['bar']));
+  assert_equals(await getFileContents(handle), 'very long string');
+  await writer.close();
+  assert_equals(await getFileContents(handle), 'bar');
+  assert_equals(await getFileSize(handle), 3);
+}, 'createWriter({keepExistingData: false}): atomic writer initialized with empty file');
+
+promise_test(async t => {
+  const root = await FileSystemDirectoryHandle.getSystemDirectory({ type: 'sandbox' });
+  const dir = await createDirectory(t, 'parent_dir', root);
+  const file_name = 'atomic_writer_persists_removed.txt';
+  const handle = await createFileWithContents(t, file_name, 'foo', dir);
+
+  const writer = await handle.createWriter();
+  await writer.write(0, new Blob(['bar']));
+
+  await dir.removeEntry(file_name);
+  await promise_rejects(t, 'NotFoundError', getFileContents(handle));
+
+  await writer.close();
+  assert_equals(await getFileContents(handle), 'bar');
+  assert_equals(await getFileSize(handle), 3);
+}, 'atomic writes: writer persists file on close, even if file is removed');
diff --git a/third_party/blink/web_tests/external/wpt/native-file-system/resources/test-helpers.js b/third_party/blink/web_tests/external/wpt/native-file-system/resources/test-helpers.js
index 56c93b5..b794cee 100644
--- a/third_party/blink/web_tests/external/wpt/native-file-system/resources/test-helpers.js
+++ b/third_party/blink/web_tests/external/wpt/native-file-system/resources/test-helpers.js
@@ -84,6 +84,7 @@
     const handle = await createEmptyFile(test, name, parent);
     const writer = await handle.createWriter();
     await writer.write(0, new Blob([contents]));
+    await writer.close();
     return handle;
 }
 
@@ -91,4 +92,4 @@
     // TODO(https://github.com/web-platform-tests/wpt/issues/7899): Change to
     // some sort of cross-browser GC trigger.
     if (self.gc) self.gc();
-};
\ No newline at end of file
+};
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/node.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/node.py
index 33e9796c43..24d523f 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/node.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/node.py
@@ -58,7 +58,8 @@
             while index > 0 and isinstance(self.children[index - 1], DataNode):
                 index -= 1
             for i in xrange(index):
-                assert other.data != self.children[i].data
+                if other.data == self.children[i].data:
+                    raise ValueError("Duplicate key %s" % self.children[i].data)
             self.children.insert(index, other)
 
 
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py
index a8e2bd6..8f1897b 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py
@@ -520,11 +520,18 @@
         self.expr_builders = []
 
     def parse(self, input):
-        self.reset()
-        self.token_generator = self.tokenizer.tokenize(input)
-        self.consume()
-        self.manifest()
-        return self.tree.node
+        try:
+            self.reset()
+            self.token_generator = self.tokenizer.tokenize(input)
+            self.consume()
+            self.manifest()
+            return self.tree.node
+        except Exception as e:
+            if not isinstance(e, ParseError):
+                raise ParseError(self.tokenizer.filename,
+                                 self.tokenizer.line_number,
+                                 str(e))
+            raise
 
     def consume(self):
         self.token = self.token_generator.next()
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer.https-expected.txt b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer.https-expected.txt
deleted file mode 100644
index 54e5aa4..0000000
--- a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer.https-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL XRWebGLLayer reports a valid framebuffer for immersive sessions assert_equals: expected (number) 5890 but got (object) null
-FAIL XRWebGLLayer reports a valid framebuffer for inline sessions assert_not_equals: got disallowed value null
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer.https.html
deleted file mode 100644
index ba6b7dc..0000000
--- a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_framebuffer.https.html
+++ /dev/null
@@ -1,69 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/webxr_test_constants.js"></script>
-<script src="resources/webxr_util.js"></script>
-<canvas></canvas>
-
-<script>
-
-let immersiveTestName = "XRWebGLLayer reports a valid framebuffer for immersive sessions";
-let inlineTestName = "XRWebGLLayer reports a valid framebuffer for inline sessions";
-
-let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE;
-
-let testFunction = function(session, fakeDeviceController, t) {
-  return session.requestReferenceSpace('viewer')
-      .then((space) => new Promise((resolve) => {
-    function onFrame(time, xrFrame) {
-      let layer = xrFrame.session.renderState.baseLayer;
-      let gl = layer.context;
-
-      // The layer's framebuffer is a WebGL framebuffer
-      t.step(() => {
-        assert_not_equals(layer.framebuffer, null);
-        assert_true(layer.framebuffer instanceof WebGLFramebuffer);
-
-        // The XR framebuffer is not bound to the GL context by default.
-        assert_not_equals(layer.framebuffer, gl.getParameter(gl.FRAMEBUFFER_BINDING));
-      });
-
-      // The XR framebuffer can be bound to the GL context.
-      gl.bindFramebuffer(gl.FRAMEBUFFER, layer.framebuffer);
-
-      t.step(() => {
-        assert_equals(layer.framebuffer, gl.getParameter(gl.FRAMEBUFFER_BINDING));
-      });
-
-      // The XR framebuffer has a 2D texture
-      let attachment = gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE);
-
-      t.step(() => {
-        assert_equals(attachment, gl.TEXTURE);
-      });
-
-      // Check that each viewport fits inside the framebuffer dimensions
-      let viewer_pose = xrFrame.getViewerPose(space);
-      for (view of viewer_pose.views) {
-        let viewport = layer.getViewport(view);
-
-        t.step(() => {
-          assert_less_than_equal(viewport.x + viewport.width, layer.framebufferWidth);
-          assert_less_than_equal(viewport.y + viewport.height, layer.framebufferHeight);
-        });
-      }
-
-      // Finished test.
-      resolve();
-    }
-
-    session.requestAnimationFrame(onFrame);
-  }));
-};
-
-xr_session_promise_test(immersiveTestName, testFunction,
-  fakeDeviceInitParams, 'immersive-vr');
-xr_session_promise_test(inlineTestName, testFunction,
-  fakeDeviceInitParams, 'inline');
-
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer.https.html
index ceff6251..37955f3 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer.https.html
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrWebGLLayer_opaque_framebuffer.https.html
@@ -31,6 +31,10 @@
   }
 
   assert_not_equals(xrFramebuffer, null);
+
+  // The XR framebuffer is not bound to the GL context by default.
+  assert_not_equals(xrFramebuffer, gl.getParameter(gl.FRAMEBUFFER_BINDING));
+
   assert_greater_than(webglLayer.framebufferWidth, 0);
   assert_greater_than(webglLayer.framebufferHeight, 0);
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/webaudio/webaudio-basic.js b/third_party/blink/web_tests/http/tests/inspector-protocol/webaudio/webaudio-basic.js
index 706e3224..4c03da0 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/webaudio/webaudio-basic.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/webaudio/webaudio-basic.js
@@ -5,7 +5,6 @@
 
   let result, event, contextId;
 
-
   result = await dp.WebAudio.enable();
   testRunner.log(`Enabled successfully: ${!result.error}`);
 
@@ -27,8 +26,8 @@
   testRunner.log(`got context realtime data: ${!response.result.realtimeData}`);
   testRunner.log(Object.keys(response.result.realtimeData));
 
-  // TODO(crbug.com/942615): Test |contextDestroyed| when AudioContext GC issue
-  // is fixed.
+  // TODO(crbug.com/942615): Test |contextWillBeDestroyed| when the GC issue is
+  // fixed.
 
   result = await dp.WebAudio.disable();
   testRunner.log(`Disabled successfully: ${!result.error}`);
diff --git a/third_party/googletest/OWNERS b/third_party/googletest/OWNERS
index 21b33d5..507760e 100644
--- a/third_party/googletest/OWNERS
+++ b/third_party/googletest/OWNERS
@@ -1,3 +1,4 @@
 thakis@chromium.org
 pwnall@chromium.org
 dpranke@chromium.org
+# COMPONENT: Test>gTest
diff --git a/third_party/r8/README.chromium b/third_party/r8/README.chromium
index e2bdf15..6bca04b 100644
--- a/third_party/r8/README.chromium
+++ b/third_party/r8/README.chromium
@@ -1,7 +1,7 @@
 Name: R8
 URL: https://r8.googlesource.com/r8
-Revision: 1a63f77c87eb4346ed26849302013b40797cb41c
-Version: 1.6.17-dev
+Revision: 09516867c67b961f861308bceec63243b5cb7d1a
+Version: 1.6.11-dev
 License: BSD 3-Clause
 License File: NOT_SHIPPED
 Security Critical: no
diff --git a/tools/fuchsia/OWNERS b/tools/fuchsia/OWNERS
index e7034ea..c1b5845 100644
--- a/tools/fuchsia/OWNERS
+++ b/tools/fuchsia/OWNERS
@@ -1 +1,4 @@
 file://build/fuchsia/OWNERS
+# COMPONENT: Fuchsia
+# OS: Fuchsia
+# TEAM: cr-fuchsia@chromium.org
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index e4384796..def08e61 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -149,18 +149,21 @@
   "chrome/browser/resources/sync_file_system_internals/sync_file_system_internals_resources.grd": {
     "includes": [13850],
   },
+  "chrome/browser/resources/tab_strip/tab_strip_resources.grd": {
+    "structures": [13880],
+  },
   "chrome/browser/resources/translate_internals/translate_internals_resources.grd": {
-    "includes": [13880],
+    "includes": [13900],
   },
   "chrome/browser/resources/webapks/webapks_ui_resources.grd": {
-    "includes": [13890],
+    "includes": [13910],
   },
   "chrome/browser/resources/welcome/onboarding_welcome_resources.grd": {
-    "includes": [13900],
-    "structures": [13950],
+    "includes": [13920],
+    "structures": [13970],
   },
   "chrome/browser/vr/testapp/vr_testapp_resources.grd": {
-    "includes": [13990],
+    "includes": [14010],
   },
   # END chrome/browser section.
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index e5eb998..8b9f6703 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -848,11 +848,11 @@
       'gpu-fyi-try-win7-nvidia-rel': 'gpu_fyi_tests_release_trybot_x86',
       'gpu-fyi-try-win7-nvidia-rel-64': 'gpu_fyi_tests_release_trybot',
       'gpu-fyi-try-win10-intel-dqp': 'deqp_release_trybot_x86',
-      'gpu-fyi-try-win10-intel-exp': 'gpu_fyi_tests_release_trybot_x86',
+      'gpu-fyi-try-win10-intel-exp-64': 'gpu_fyi_tests_release_trybot',
       'gpu-fyi-try-win10-intel-rel': 'gpu_fyi_tests_release_trybot_x86',
       'gpu-fyi-try-win10-nvidia-dbg': 'gpu_fyi_tests_debug_trybot_x86',
       'gpu-fyi-try-win10-nvidia-dqp': 'deqp_release_trybot_x86',
-      'gpu-fyi-try-win10-nvidia-exp': 'gpu_fyi_tests_release_trybot_x86',
+      'gpu-fyi-try-win10-nvidia-exp-64': 'gpu_fyi_tests_release_trybot',
       'gpu-fyi-try-win10-nvidia-rel': 'gpu_fyi_tests_release_trybot_x86',
       'gpu-try-win10-nvidia-dbg': 'gpu_tests_debug_trybot_x86',
       'gpu-try-win10-nvidia-rel': 'gpu_tests_release_trybot_x86_resource_whitelisting',
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 27b92b8..72938f4 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -1424,8 +1424,8 @@
 </action>
 
 <action name="Android.BookmarkPage.RemoveItem">
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
+  <owner>chrome-android-app@chromium.org</owner>
   <description>
     User removed an item on the native Android bookmark page by clicking
     &quot;delete&quot; from the &quot;more&quot; menu.
@@ -1433,8 +1433,8 @@
 </action>
 
 <action name="Android.BookmarkPage.SelectFromMenu">
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
+  <owner>chrome-android-app@chromium.org</owner>
   <description>
     User selected an item on the native Android bookmark page by clicking
     &quot;select&quot; from the &quot;more&quot; menu.
@@ -1664,7 +1664,7 @@
 </action>
 
 <action name="Android.DarkTheme.Preference">
-  <owner>huayinz@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
   <owner>chrome-android-app@chromium.org</owner>
   <description>
     User changed preference to use system default, light, or dark theme.
@@ -1808,7 +1808,6 @@
     Deprecated in favor of Android.DownloadManager.List.View.Action.
   </obsolete>
   <owner>dtrainor@chromium.org</owner>
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <description>
     User removed an item on the native Android download page by clicking
@@ -4736,7 +4735,6 @@
 
 <action name="ContextualSuggestions">
   <obsolete>This feature was deprecated in M74</obsolete>
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.com</owner>
   <owner>wylieb@chromium.com</owner>
   <description>Android: User interacts with the feature directly.</description>
@@ -4744,7 +4742,6 @@
 
 <action name="ContextualSuggestions.ContextMenu">
   <obsolete>This feature was deprecated in M74</obsolete>
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.com</owner>
   <description>
     Android: User used the context menu on a suggested item on the contextual
@@ -4754,7 +4751,6 @@
 
 <action name="ContextualSuggestions.Preference.Disabled">
   <obsolete>This feature was deprecated in M74</obsolete>
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <description>
     Android: Contextual suggestions are disabled by a user click on the switch
@@ -4764,7 +4760,6 @@
 
 <action name="ContextualSuggestions.Preference.Enabled">
   <obsolete>This feature was deprecated in M74</obsolete>
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <description>
     Android: Contextual suggestions are enabled by a user click on the switch
@@ -11435,6 +11430,15 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="MobileBookmarkManagerDragReorder">
+  <owner>jhimawan@google.com</owner>
+  <owner>twellington@google.com</owner>
+  <description>
+    Recorded when a user drops a bookmark after a drag in the Android bookmark
+    manager.
+  </description>
+</action>
+
 <action name="MobileBookmarkManagerEntryDeleted">
   <owner>sczs@chromium.org</owner>
   <description>
@@ -11455,6 +11459,24 @@
   </description>
 </action>
 
+<action name="MobileBookmarkManagerMoveDown">
+  <owner>jhimawan@google.com</owner>
+  <owner>twellington@google.com</owner>
+  <description>
+    Recorded when a user uses the &quot;Move Down&quot; button to reorder
+    bookmarks in the Android bookmark manager.
+  </description>
+</action>
+
+<action name="MobileBookmarkManagerMoveUp">
+  <owner>jhimawan@google.com</owner>
+  <owner>twellington@google.com</owner>
+  <description>
+    Recorded when a user uses the &quot;Move Up&quot; button to reorder
+    bookmarks in the Android bookmark manager.
+  </description>
+</action>
+
 <action name="MobileBookmarkManagerOpen">
   <owner>ianwen@chromium.org</owner>
   <description>
@@ -20921,8 +20943,8 @@
 </action>
 
 <action name="Suggestions.ExpandableHeader.Collapsed">
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.com</owner>
+  <owner>chrome-android-app@chromium.org</owner>
   <description>
     Android: The suggestions section is collapsed by user click on the section
     header.
@@ -20930,8 +20952,8 @@
 </action>
 
 <action name="Suggestions.ExpandableHeader.Expanded">
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.com</owner>
+  <owner>chrome-android-app@chromium.org</owner>
   <description>
     Android: The suggestions section is expanded by user click on the section
     header.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 309974f..c29754b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -34877,6 +34877,7 @@
   <int value="-956696029" label="scheduler-configuration"/>
   <int value="-951394314" label="top-chrome-md"/>
   <int value="-950793721" label="TranslateUI2016Q2:disabled"/>
+  <int value="-950384924" label="OmniboxDisableInstantExtendedLimit:enabled"/>
   <int value="-949178861" label="enable-new-avatar-menu"/>
   <int value="-945806012" label="DownloadsUi:enabled"/>
   <int value="-938178614" label="enable-suggestions-with-substring-match"/>
@@ -35819,6 +35820,7 @@
   <int value="403741682" label="CrostiniBackup:enabled"/>
   <int value="405329388"
       label="FramebustingNeedsSameOriginOrUserGesture:enabled"/>
+  <int value="408190863" label="OmniboxDisableInstantExtendedLimit:disabled"/>
   <int value="411250226" label="AutoplayMutedVideos:disabled"/>
   <int value="412957264" label="tab-close-buttons-hidden-with-touch"/>
   <int value="413081240" label="enable-new-md-input-view"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b565018..6b65cc0 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -143,7 +143,7 @@
 </histogram>
 
 <histogram name="Accessibility.CrosChromeVoxAfterSwitchAccess"
-    enum="BooleanEnabled" expires_after="M80">
+    enum="BooleanEnabled" expires_after="M85">
   <owner>anastasi@google.com</owner>
   <owner>dtseng@chromium.org</owner>
   <summary>
@@ -334,7 +334,7 @@
 </histogram>
 
 <histogram name="Accessibility.CrosSwitchAccessAfterChromeVox"
-    enum="BooleanEnabled" expires_after="M80">
+    enum="BooleanEnabled" expires_after="M85">
   <owner>anastasi@google.com</owner>
   <owner>dtseng@chromium.org</owner>
   <summary>
@@ -1928,7 +1928,7 @@
 
 <histogram name="Android.DarkTheme.EnabledReason" enum="DarkThemeEnabledReason"
     expires_after="M90">
-  <owner>huayinz@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
   <owner>chrome-android-app@chromium.org</owner>
   <summary>
     Records the reason why dark theme is enabled when dark theme is visible to
@@ -1938,7 +1938,7 @@
 
 <histogram name="Android.DarkTheme.EnabledState" enum="BooleanEnabled"
     expires_after="M90">
-  <owner>huayinz@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
   <owner>chrome-android-app@chromium.org</owner>
   <summary>
     Records whether dark theme is enabled or not on cold start and when the
@@ -1948,7 +1948,7 @@
 
 <histogram name="Android.DarkTheme.Preference.State"
     enum="DarkThemePreferences" expires_after="M90">
-  <owner>huayinz@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
   <owner>chrome-android-app@chromium.org</owner>
   <summary>
     Records user theme preference of system default, light or dark theme on cold
@@ -3211,7 +3211,7 @@
 
 <histogram name="Android.RecentTabsManager.OtherDevices" units="count"
     expires_after="M82">
-  <owner>huayinz@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
   <owner>chrome-android-app@chromium.org</owner>
   <summary>
     Records the number of other devices listed in recent tabs page when recent
@@ -3221,7 +3221,7 @@
 
 <histogram name="Android.RecentTabsManager.RecentlyClosedTabs" units="count"
     expires_after="M82">
-  <owner>huayinz@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
   <owner>chrome-android-app@chromium.org</owner>
   <summary>
     Records the number of recently-closed tabs shown in recent tabs page when
@@ -3231,7 +3231,7 @@
 
 <histogram name="Android.RecentTabsManager.TotalTabs" units="count"
     expires_after="M82">
-  <owner>huayinz@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
   <owner>chrome-android-app@chromium.org</owner>
   <summary>
     Records the total number of tabs listed in recent tabs page (sum of all tab
@@ -22698,7 +22698,6 @@
   <obsolete>
     This feature was deprecated in M74
   </obsolete>
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
     Android: Whether contextual suggestions are enabled. Recorded when the
@@ -22828,7 +22827,6 @@
   <obsolete>
     This feature was deprecated in M74
   </obsolete>
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
     Android: Whether the user preference for contextual suggestions is enabled.
@@ -22843,7 +22841,6 @@
     Deprecated 01/2019, no longer needed
   </obsolete>
   <owner>twellington@chromium.org</owner>
-  <owner>huayinz@chromium.org</owner>
   <summary>
     Android: Whether the contextual suggestions results are returned to the
     UI-layer while the user is in overview mode.
@@ -22856,7 +22853,6 @@
     This feature was deprecated in M74
   </obsolete>
   <owner>twellington@chromium.org</owner>
-  <owner>huayinz@chromium.org</owner>
   <summary>
     Android: The position of the clicked contextual suggestion card within its
     cluster.
@@ -22869,7 +22865,6 @@
     This feature was deprecated in M74
   </obsolete>
   <owner>twellington@chromium.org</owner>
-  <owner>huayinz@chromium.org</owner>
   <summary>
     Android: The position of the clicked contextual suggestion card within the
     entire list of suggestions.
@@ -59437,6 +59432,17 @@
   </summary>
 </histogram>
 
+<histogram name="Media.MojoVideoDecoder.Decode" units="ms"
+    expires_after="2020-07-28">
+  <owner>mcasas@chromium.org</owner>
+  <owner>chromeos-gfx@chromium.org</owner>
+  <summary>
+    Delay between a DecodeBuffer (and encoded chunk) input and a decoded
+    VideoFrame being produced by the remote MojoVideoDecoder. Output once per
+    successful decode.
+  </summary>
+</histogram>
+
 <histogram name="Media.MSE.AudioCodec" enum="MSECodec" expires_after="never">
 <!-- expires-never: Codec support planning metric. -->
 
@@ -82509,8 +82515,8 @@
 
 <histogram name="NewTabPage.ContentSuggestions.ArticlesListVisible"
     enum="BooleanVisible">
-  <owner>huayinz@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
+  <owner>chrome-android-app@chromium.org</owner>
   <summary>
     Android: Whether article suggestions on New Tab Page are set visible by user
     on startup and when the visibility is changed.
@@ -90878,6 +90884,26 @@
   </summary>
 </histogram>
 
+<histogram name="Ozone.TouchEventConverterEvdev.HoldCountAtCancel"
+    units="touch event" expires_after="2020-12-01">
+  <owner>robsc@chromium.org</owner>
+  <summary>
+    The count of the number of held events cancelled when we decide to finally
+    cancel a stroke. Only reported if events have been held, and will be
+    positive. Events are only held from PalmDetectionFilter.
+  </summary>
+</histogram>
+
+<histogram name="Ozone.TouchEventConverterEvdev.HoldCountAtRelease"
+    units="touch event" expires_after="2020-12-01">
+  <owner>robsc@chromium.org</owner>
+  <summary>
+    The count of the number of held events released at once for a stroke when we
+    decide to release. Only reported if events have been held, and will be
+    positive. Events are only held from PalmDetectionFilter.
+  </summary>
+</histogram>
+
 <histogram name="Ozone.TouchNoiseFilter.FarApartTapDistance"
     units="squared pixels">
   <owner>pkotwicz@google.com</owner>
@@ -114791,7 +114817,12 @@
 </histogram>
 
 <histogram name="SafeBrowsing.V4Update.Parse.Result"
-    enum="SafeBrowsingParseV4UpdateResult" expires_after="M77">
+    enum="SafeBrowsingParseV4UpdateResult" expires_after="never">
+<!-- expires-never: This reports the reason for the failure to parse the Safe
+Browsing database update received from the API backend. It is crucial to detect
+if we ever start failing to parse the updates which puts users' security at
+risk. -->
+
   <owner>vakh@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -114808,7 +114839,11 @@
 </histogram>
 
 <histogram name="SafeBrowsing.V4Update.Result"
-    enum="SafeBrowsingV4OperationResult" expires_after="M77">
+    enum="SafeBrowsingV4OperationResult" expires_after="never">
+<!-- expires-never: This reports the outcome of fetching the Safe Browsing
+database update from the API backend. It is crucial to detect if we ever start
+failing to fetch the updates which puts users' security at risk. -->
+
   <owner>vakh@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -114819,6 +114854,9 @@
 
 <histogram name="SafeBrowsing.V4Update.TimedOut" enum="BooleanTimedOut"
     expires_after="M77">
+  <obsolete>
+    Removed in M78 due to lack of use and timed out rate being less than 0.03%
+  </obsolete>
   <owner>vakh@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>True if a PVer4 update request timed out.</summary>
@@ -124521,7 +124559,7 @@
 </histogram>
 
 <histogram name="Settings.GivenShowHomeButton_HomePageIsNewTabPage"
-    enum="Boolean" expires_after="2019-08-30">
+    enum="Boolean" expires_after="M82">
   <owner>mpearson@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -124566,7 +124604,7 @@
 </histogram>
 
 <histogram name="Settings.HomePageIsCustomized" enum="Boolean"
-    expires_after="2019-08-30">
+    expires_after="M82">
   <owner>twellington@chromium.org</owner>
   <owner>tedchoc@chromium.org</owner>
   <summary>
@@ -124828,7 +124866,7 @@
 </histogram>
 
 <histogram name="Settings.ShowHomeButton" enum="BooleanEnabled"
-    expires_after="2019-08-30">
+    expires_after="M82">
   <owner>mpearson@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -124862,7 +124900,7 @@
 </histogram>
 
 <histogram name="Settings.ShowHomeButtonPreferenceState" enum="BooleanEnabled"
-    expires_after="2019-08-30">
+    expires_after="M82">
   <owner>twellington@chromium.org</owner>
   <owner>tedchoc@chromium.org</owner>
   <summary>
@@ -124874,7 +124912,7 @@
 </histogram>
 
 <histogram name="Settings.ShowHomeButtonPreferenceStateChanged"
-    enum="BooleanEnabled" expires_after="2019-08-30">
+    enum="BooleanEnabled" expires_after="M82">
   <owner>twellington@chromium.org</owner>
   <owner>tedchoc@chromium.org</owner>
   <summary>
diff --git a/ui/accessibility/ax_node_position_unittest.cc b/ui/accessibility/ax_node_position_unittest.cc
index 9a454066..9798a8e 100644
--- a/ui/accessibility/ax_node_position_unittest.cc
+++ b/ui/accessibility/ax_node_position_unittest.cc
@@ -1965,18 +1965,12 @@
   TestPositionType test_position = null_position->AsPositionBeforeCharacter();
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
-  test_position = null_position->AsLeafTextPositionBeforeCharacter();
-  EXPECT_NE(nullptr, test_position);
-  EXPECT_TRUE(test_position->IsNullPosition());
   test_position = null_position->AsPositionAfterCharacter();
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
-  test_position = null_position->AsLeafTextPositionAfterCharacter();
-  EXPECT_NE(nullptr, test_position);
-  EXPECT_TRUE(test_position->IsNullPosition());
 }
 
-TEST_F(AXPositionTest, AsPositionBeforeCharacter) {
+TEST_F(AXPositionTest, AsPositionBeforeCharacterNoAdjustment) {
   // A text offset that is on the line break right after "Line 1".
   TestPositionType text_position = AXNodePosition::CreateTextPosition(
       tree_.data().tree_id, root_.id, 6 /* text_offset */,
@@ -2000,7 +1994,7 @@
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(text_field_.id, test_position->anchor_id());
   EXPECT_EQ(6, test_position->text_offset());
-  EXPECT_EQ(ax::mojom::TextAffinity::kDownstream, test_position->affinity());
+  EXPECT_EQ(ax::mojom::TextAffinity::kUpstream, test_position->affinity());
 
   text_position = AXNodePosition::CreateTextPosition(
       tree_.data().tree_id, text_field_.id, 13 /* text_offset */,
@@ -2045,7 +2039,7 @@
   EXPECT_EQ(0, test_position->text_offset());
 }
 
-TEST_F(AXPositionTest, AsPositionAfterCharacter) {
+TEST_F(AXPositionTest, AsPositionAfterCharacterNoAdjustment) {
   // A text offset that is after "Line 2".
   TestPositionType text_position = AXNodePosition::CreateTextPosition(
       tree_.data().tree_id, root_.id, 13 /* text_offset */,
@@ -2128,25 +2122,13 @@
   EXPECT_EQ(6, test_position->text_offset());
 }
 
-TEST_F(AXPositionTest, AsLeafTextPositionBeforeCharacter) {
+TEST_F(AXPositionTest, AsPositionBeforeCharacter) {
   TestPositionType text_position = AXNodePosition::CreateTextPosition(
-      tree_.data().tree_id, root_.id, 0 /* text_offset */,
-      ax::mojom::TextAffinity::kDownstream);
-  ASSERT_NE(nullptr, text_position);
-  ASSERT_TRUE(text_position->IsTextPosition());
-  TestPositionType test_position =
-      text_position->AsLeafTextPositionBeforeCharacter();
-  EXPECT_NE(nullptr, test_position);
-  EXPECT_TRUE(test_position->IsTextPosition());
-  EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
-  EXPECT_EQ(0, test_position->text_offset());
-
-  text_position = AXNodePosition::CreateTextPosition(
       tree_.data().tree_id, inline_box1_.id, 3 /* text_offset */,
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
-  test_position = text_position->AsLeafTextPositionBeforeCharacter();
+  TestPositionType test_position = text_position->AsPositionBeforeCharacter();
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
@@ -2157,7 +2139,7 @@
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
-  test_position = text_position->AsLeafTextPositionBeforeCharacter();
+  test_position = text_position->AsPositionBeforeCharacter();
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
@@ -2165,10 +2147,10 @@
 
   text_position = AXNodePosition::CreateTextPosition(
       tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */,
-      ax::mojom::TextAffinity::kDownstream);
+      ax::mojom::TextAffinity::kUpstream);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
-  test_position = text_position->AsLeafTextPositionBeforeCharacter();
+  test_position = text_position->AsPositionBeforeCharacter();
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
@@ -2176,22 +2158,30 @@
 
   text_position = AXNodePosition::CreateTextPosition(
       tree_.data().tree_id, inline_box2_.id, 6 /* text_offset */,
+      ax::mojom::TextAffinity::kUpstream);
+  ASSERT_NE(nullptr, text_position);
+  ASSERT_TRUE(text_position->IsTextPosition());
+  test_position = text_position->AsPositionBeforeCharacter();
+  EXPECT_NE(nullptr, test_position);
+  EXPECT_TRUE(test_position->IsNullPosition());
+
+  text_position = AXNodePosition::CreateTextPosition(
+      tree_.data().tree_id, root_.id, 13 /* text_offset */,
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
-  test_position = text_position->AsLeafTextPositionBeforeCharacter();
+  test_position = text_position->AsPositionBeforeCharacter();
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 }
 
-TEST_F(AXPositionTest, AsLeafTextPositionAfterCharacter) {
+TEST_F(AXPositionTest, AsPositionAfterCharacter) {
   TestPositionType text_position = AXNodePosition::CreateTextPosition(
       tree_.data().tree_id, inline_box1_.id, 0 /* text_offset */,
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
-  TestPositionType test_position =
-      text_position->AsLeafTextPositionAfterCharacter();
+  TestPositionType test_position = text_position->AsPositionAfterCharacter();
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsNullPosition());
 
@@ -2200,7 +2190,7 @@
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
-  test_position = text_position->AsLeafTextPositionAfterCharacter();
+  test_position = text_position->AsPositionAfterCharacter();
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(inline_box1_.id, test_position->anchor_id());
@@ -2208,10 +2198,10 @@
 
   text_position = AXNodePosition::CreateTextPosition(
       tree_.data().tree_id, line_break_.id, 1 /* text_offset */,
-      ax::mojom::TextAffinity::kDownstream);
+      ax::mojom::TextAffinity::kUpstream);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
-  test_position = text_position->AsLeafTextPositionAfterCharacter();
+  test_position = text_position->AsPositionAfterCharacter();
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(line_break_.id, test_position->anchor_id());
@@ -2219,25 +2209,23 @@
 
   text_position = AXNodePosition::CreateTextPosition(
       tree_.data().tree_id, inline_box2_.id, 0 /* text_offset */,
-      ax::mojom::TextAffinity::kDownstream);
+      ax::mojom::TextAffinity::kUpstream);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
-  test_position = text_position->AsLeafTextPositionAfterCharacter();
+  test_position = text_position->AsPositionAfterCharacter();
   EXPECT_NE(nullptr, test_position);
   EXPECT_TRUE(test_position->IsTextPosition());
   EXPECT_EQ(line_break_.id, test_position->anchor_id());
   EXPECT_EQ(1, test_position->text_offset());
 
   text_position = AXNodePosition::CreateTextPosition(
-      tree_.data().tree_id, root_.id, 13 /* text_offset */,
+      tree_.data().tree_id, root_.id, 0 /* text_offset */,
       ax::mojom::TextAffinity::kDownstream);
   ASSERT_NE(nullptr, text_position);
   ASSERT_TRUE(text_position->IsTextPosition());
-  test_position = text_position->AsLeafTextPositionAfterCharacter();
+  test_position = text_position->AsPositionAfterCharacter();
   EXPECT_NE(nullptr, test_position);
-  EXPECT_TRUE(test_position->IsTextPosition());
-  EXPECT_EQ(inline_box2_.id, test_position->anchor_id());
-  EXPECT_EQ(6, test_position->text_offset());
+  EXPECT_TRUE(test_position->IsNullPosition());
 }
 
 TEST_F(AXPositionTest, CreateNextAndPreviousCharacterPositionWithNullPosition) {
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h
index fdd872c..23422bf3 100644
--- a/ui/accessibility/ax_position.h
+++ b/ui/accessibility/ax_position.h
@@ -862,30 +862,26 @@
 
   // Returns a text position located right before the next character (from this
   // position) in the tree's text representation, following these conditions:
+  //
   //   - If this position is at the end of its anchor, normalize it to the start
-  //   of the next text anchor, regardless of the position's affinity. Both
-  //   positions are equal when compared, but we consider the start of an anchor
-  //   to be a position BEFORE its first character and the end to be AFTER its
-  //   last character.
+  //   of the next text anchor, regardless of the position's affinity.
+  //   Both text positions are equal when compared, but we consider the start of
+  //   an anchor to be a position BEFORE its first character and the end of the
+  //   previous to be AFTER its last character.
+  //
   //   - Skip any empty text anchors; they're "invisible" to the text
   //   representation and the next character could be ahead.
+  //
   //   - Return a null position if there is no next character forward.
-  // Don't return a leaf equivalent position, but try and return a position that
-  // has the same anchor as the current position if the resulting position is
-  // enclosed by the same anchor.
+  //
+  // If possible, return a position anchored at the current position's anchor;
+  // this is necessary because we don't want to return any position that might
+  // be located in the shadow DOM or in a position anchored at a node that is
+  // not visible to a specific platform's APIs.
   AXPositionInstance AsPositionBeforeCharacter() const {
-    AXPositionInstance text_position = AsLeafTextPositionBeforeCharacter();
-
-    // If possible, return a position anchored at the current position. This is
-    // necessary because we don't want to return any position that might be in
-    // the shadow DOM or a position anchored at a node that is not visible to
-    // platform APIs, if the original position didn't meet any of these
-    // criteria.
-    AXPositionInstance common_ancestor =
-        text_position->LowestCommonAncestor(*this);
-    if (GetAnchor() == common_ancestor->GetAnchor())
-      text_position = std::move(common_ancestor);
-
+    AXPositionInstance text_position = AsTextPosition();
+    while (text_position->AtEndOfAnchor())
+      text_position = text_position->CreateNextTextAnchorPosition();
     return text_position;
   }
 
@@ -893,35 +889,7 @@
   // this position) in the tree's text representation.
   // See `AsPositionBeforeCharacter`, as this is its "reversed" version.
   AXPositionInstance AsPositionAfterCharacter() const {
-    AXPositionInstance text_position = AsLeafTextPositionAfterCharacter();
-
-    // If possible, return a position anchored at the current position. This is
-    // necessary because we don't want to return any position that might be in
-    // the shadow DOM or a position anchored at a node that is not visible to
-    // platform APIs, if the original position didn't meet any of these
-    // criteria.
-    AXPositionInstance common_ancestor =
-        text_position->LowestCommonAncestor(*this);
-    if (GetAnchor() == common_ancestor->GetAnchor())
-      text_position = std::move(common_ancestor);
-
-    return text_position;
-  }
-
-  // Same as `AsPositionBeforeCharacter`, but returns the leaf equivalent text
-  // position.
-  AXPositionInstance AsLeafTextPositionBeforeCharacter() const {
-    AXPositionInstance text_position = AsLeafTextPosition();
-    // This loop satisfies all the conditions described above.
-    while (text_position->AtEndOfAnchor())
-      text_position = text_position->CreateNextTextAnchorPosition();
-    return text_position;
-  }
-
-  // Same as `AsPositionAfterCharacter`, but returns the leaf equivalent text
-  // position.
-  AXPositionInstance AsLeafTextPositionAfterCharacter() const {
-    AXPositionInstance text_position = AsLeafTextPosition();
+    AXPositionInstance text_position = AsTextPosition();
     while (text_position->AtStartOfAnchor()) {
       text_position = text_position->CreatePreviousTextAnchorPosition();
       text_position = text_position->CreatePositionAtEndOfAnchor();
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
index 154d3cf..63c1d43 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -32,7 +32,7 @@
 AXPlatformNodeTextRangeProviderWin::~AXPlatformNodeTextRangeProviderWin() {}
 
 ITextRangeProvider* AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider(
-    ui::AXPlatformNodeWin* owner,
+    AXPlatformNodeWin* owner,
     AXPositionInstance start,
     AXPositionInstance end) {
   CComObject<AXPlatformNodeTextRangeProviderWin>* text_range_provider = nullptr;
@@ -127,14 +127,14 @@
       // boundary, thus we only need to move the end position.
       AXPositionInstance end_backup = end_->Clone();
       end_ = start_->CreateNextCharacterPosition(
-          ui::AXBoundaryBehavior::CrossBoundary);
+          AXBoundaryBehavior::CrossBoundary);
 
       if (end_->IsNullPosition()) {
         // The previous could fail if the start is at the end of the last anchor
         // of the tree, try expanding to the previous character instead.
         AXPositionInstance start_backup = start_->Clone();
         start_ = start_->CreatePreviousCharacterPosition(
-            ui::AXBoundaryBehavior::CrossBoundary);
+            AXBoundaryBehavior::CrossBoundary);
 
         if (start_->IsNullPosition()) {
           // Text representation is empty, undo everything and exit.
@@ -143,35 +143,42 @@
           return S_OK;
         }
         end_ = start_->CreateNextCharacterPosition(
-            ui::AXBoundaryBehavior::CrossBoundary);
+            AXBoundaryBehavior::CrossBoundary);
         DCHECK(!end_->IsNullPosition());
       }
       break;
     }
     case TextUnit_Format:
       start_ = start_->CreatePreviousFormatStartPosition(
-          ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
       end_ = start_->CreateNextFormatEndPosition(
-          ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
       break;
     case TextUnit_Word:
       start_ = start_->CreatePreviousWordStartPosition(
-          ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
-      end_ = start_->CreateNextWordEndPosition(
-          ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+
+      // Since start_ is already located at a word boundary, we need to cross it
+      // in order to move to the next one; the only edge case here is the last
+      // word in the document, which will result in a null position.
+      end_ = start_->CreateNextWordStartPosition(
+          AXBoundaryBehavior::CrossBoundary);
+      if (end_->IsNullPosition())
+        end_ = start_->CreatePositionAtEndOfDocument();
       break;
     case TextUnit_Line:
       start_ = start_->CreatePreviousLineStartPosition(
-          ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
       end_ = start_->CreateNextLineEndPosition(
-          ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
       break;
     case TextUnit_Paragraph:
       start_ = start_->CreatePreviousParagraphStartPosition(
-          ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
       end_ = start_->CreateNextParagraphEndPosition(
-          ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary);
+          AXBoundaryBehavior::StopIfAlreadyAtBoundary);
       break;
+
     // Since web content is not paginated, TextUnit_Page is not supported.
     // Substituting it by the next larger unit: TextUnit_Document.
     case TextUnit_Page:
@@ -186,9 +193,8 @@
   // Some text positions are equal when compared, but they could be located at
   // different anchors, affecting how `GetEnclosingElement` works. Normalize the
   // endpoints to correctly enclose characters of the text representation.
-  AXPositionInstance normalized_start =
-      start_->AsLeafTextPositionBeforeCharacter();
-  AXPositionInstance normalized_end = end_->AsLeafTextPositionBeforeCharacter();
+  AXPositionInstance normalized_start = start_->AsPositionBeforeCharacter();
+  AXPositionInstance normalized_end = end_->AsPositionBeforeCharacter();
 
   if (!normalized_start->IsNullPosition()) {
     DCHECK_EQ(*start_, *normalized_start);
@@ -730,7 +736,7 @@
   UIA_VALIDATE_BOUNDS(root_screen_bounds);
   target_point += root_screen_bounds.OffsetFromOrigin();
 
-  ui::AXActionData action_data;
+  AXActionData action_data;
   action_data.action = ax::mojom::Action::kScrollToPoint;
   action_data.target_node_id = common_ancestor_anchor->id();
   action_data.target_point = target_point;
@@ -787,7 +793,7 @@
   return range.GetText(AXTextConcatenationBehavior::kAsInnerText);
 }
 
-ui::AXPlatformNodeWin* AXPlatformNodeTextRangeProviderWin::owner() const {
+AXPlatformNodeWin* AXPlatformNodeTextRangeProviderWin::owner() const {
   return owner_;
 }
 
@@ -821,19 +827,23 @@
     int* units_moved) {
   DCHECK_NE(count, 0);
 
-  CreateNextPositionFunction create_next_position = nullptr;
-  if (count > 0)
-    create_next_position =
-        is_start_endpoint ? &AXPositionInstanceType::CreateNextWordStartPosition
-                          : &AXPositionInstanceType::CreateNextWordEndPosition;
-  else
-    create_next_position =
-        is_start_endpoint
-            ? &AXPositionInstanceType::CreatePreviousWordStartPosition
-            : &AXPositionInstanceType::CreatePreviousWordEndPosition;
+  bool going_forward = count > 0;
+  AXPositionInstance new_position = MoveEndpointByUnitHelper(
+      std::move(endpoint),
+      going_forward ? &AXPositionInstanceType::CreateNextWordStartPosition
+                    : &AXPositionInstanceType::CreatePreviousWordStartPosition,
+      count, units_moved);
 
-  return MoveEndpointByUnitHelper(std::move(endpoint), create_next_position,
-                                  count, units_moved);
+  if (going_forward && *units_moved < count &&
+      !new_position->AsPositionBeforeCharacter()->IsNullPosition()) {
+    AXPositionInstance next_word_position =
+        new_position->CreatePositionAtEndOfDocument();
+    DCHECK(!next_word_position->IsNullPosition());
+
+    new_position = std::move(next_word_position);
+    ++*units_moved;
+  }
+  return new_position;
 }
 
 AXPlatformNodeTextRangeProviderWin::AXPositionInstance
@@ -886,7 +896,7 @@
   auto current_endpoint = endpoint->Clone();
   const bool forwards = count > 0;
   const int count_abs = std::abs(count);
-  const auto behavior = ui::AXBoundaryBehavior::CrossBoundary;
+  const auto behavior = AXBoundaryBehavior::CrossBoundary;
   int iteration = 0;
   for (iteration = 0; iteration < count_abs; ++iteration) {
     AXPositionInstance next_endpoint;
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
index ad602a2..3e8c4d3 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h
@@ -30,7 +30,7 @@
 
   // Creates an instance of the class.
   static ITextRangeProvider* CreateTextRangeProvider(
-      ui::AXPlatformNodeWin* owner,
+      AXPlatformNodeWin* owner,
       AXNodePosition::AXPositionInstance start,
       AXNodePosition::AXPositionInstance end);
 
@@ -89,7 +89,7 @@
   friend class AXPlatformNodeTextRangeProviderTest;
   friend class AXPlatformNodeTextProviderTest;
   base::string16 GetString();
-  ui::AXPlatformNodeWin* owner() const;
+  AXPlatformNodeWin* owner() const;
   AXPlatformNodeDelegate* GetDelegate(
       const AXPositionInstanceType* position) const;
 
@@ -128,7 +128,7 @@
       const int count,
       int* units_moved);
 
-  CComPtr<ui::AXPlatformNodeWin> owner_;
+  CComPtr<AXPlatformNodeWin> owner_;
   AXPositionInstance start_;
   AXPositionInstance end_;
 };
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index 1b1cf4c..7af0152 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -976,7 +976,7 @@
   // Start endpoint is already on a word's start boundary.
   ASSERT_HRESULT_SUCCEEDED(
       text_range_provider->ExpandToEnclosingUnit(TextUnit_Word));
-  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"definitely");
+  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"definitely ");
 
   // Start endpoint is between a word's start and end boundaries.
   int count;
@@ -984,11 +984,11 @@
       TextPatternRangeEndpoint_Start, TextUnit_Character, /*count*/ -2,
       &count));
   ASSERT_EQ(-2, count);
-  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"xtdefinitely");
+  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"xtdefinitely ");
 
   ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
-      TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ 5, &count));
-  ASSERT_EQ(5, count);
+      TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ 4, &count));
+  ASSERT_EQ(4, count);
   EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"xtdefinitely not ");
 
   ASSERT_HRESULT_SUCCEEDED(
@@ -1009,7 +1009,7 @@
 
   ASSERT_HRESULT_SUCCEEDED(
       text_range_provider->ExpandToEnclosingUnit(TextUnit_Word));
-  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"not");
+  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"not ");
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest,
@@ -1576,19 +1576,19 @@
   // Move forward.
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ 1,
-                  /*expected_text*/ L"line",
+                  /*expected_text*/ L"line ",
                   /*expected_count*/ 1);
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ 2,
-                  /*expected_text*/ L"text",
+                  /*expected_text*/ L"text\n\n",
                   /*expected_count*/ 2);
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ 2,
-                  /*expected_text*/ L"line",
+                  /*expected_text*/ L"line\n",
                   /*expected_count*/ 2);
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ 3,
-                  /*expected_text*/ L"Paragraph",
+                  /*expected_text*/ L"Paragraph ",
                   /*expected_count*/ 3);
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ 6,
@@ -1604,26 +1604,26 @@
   // Move backward.
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ -3,
-                  /*expected_text*/ L"Paragraph",
+                  /*expected_text*/ L"Paragraph ",
                   /*expected_count*/ -3);
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ -3,
-                  /*expected_text*/ L"line",
+                  /*expected_text*/ L"line\n",
                   /*expected_count*/ -3);
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ -2,
-                  /*expected_text*/ L"text",
+                  /*expected_text*/ L"text\n\n",
                   /*expected_count*/ -2);
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ -6,
-                  /*expected_text*/ L"First",
+                  /*expected_text*/ L"First ",
                   /*expected_count*/ -3);
 
   // Moving backward by any number of words at the start of document
   // should have no effect.
   EXPECT_UIA_MOVE(text_range_provider, TextUnit_Word,
                   /*count*/ -20,
-                  /*expected_text*/ L"First",
+                  /*expected_text*/ L"First ",
                   /*expected_count*/ 0);
 
   // Degenerate range moves.
@@ -2137,7 +2137,7 @@
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
                                    TextPatternRangeEndpoint_End, TextUnit_Word,
                                    /*count*/ -1,
-                                   /*expected_text*/ L"more",
+                                   /*expected_text*/ L"more ",
                                    /*expected_count*/ -1);
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
                                    TextPatternRangeEndpoint_End, TextUnit_Word,
@@ -2158,9 +2158,9 @@
       /*expected_count*/ -3);
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
                                    TextPatternRangeEndpoint_End, TextUnit_Word,
-                                   /*count*/ -2,
+                                   /*count*/ -1,
                                    /*expected_text*/ L"more text",
-                                   /*expected_count*/ -2);
+                                   /*expected_count*/ -1);
 
   // Moving the end past the start, then reverting.
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
@@ -2171,13 +2171,13 @@
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
                                    TextPatternRangeEndpoint_End, TextUnit_Word,
                                    /*count*/ 3,
-                                   /*expected_text*/ L" textmore text",
+                                   /*expected_text*/ L"textmore text",
                                    /*expected_count*/ 3);
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(
       text_range_provider, TextPatternRangeEndpoint_Start, TextUnit_Word,
-      /*count*/ 2,
+      /*count*/ 1,
       /*expected_text*/ L"more text",
-      /*expected_count*/ 2);
+      /*expected_count*/ 1);
 
   // Moving the endpoints further than both ends of the document.
   EXPECT_UIA_MOVE_ENDPOINT_BY_UNIT(text_range_provider,
@@ -2386,7 +2386,7 @@
   ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
       TextPatternRangeEndpoint_End, TextUnit_Word, /*count*/ 1, &count));
   ASSERT_EQ(1, count);
-  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some textmore");
+  EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"some textmore ");
 
   ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit(
       TextPatternRangeEndpoint_End, TextUnit_Word, /*count*/ -1, &count));
diff --git a/ui/android/java/res/OWNERS b/ui/android/java/res/OWNERS
index fea93505..2730e11 100644
--- a/ui/android/java/res/OWNERS
+++ b/ui/android/java/res/OWNERS
@@ -4,7 +4,6 @@
 set noparent
 
 dtrainor@chromium.org
-huayinz@chromium.org
 mdjones@chromium.org
 tedchoc@chromium.org
 twellington@chromium.org
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/OWNERS b/ui/android/java/src/org/chromium/ui/modaldialog/OWNERS
index 4c1b84f..38a5178 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/OWNERS
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/OWNERS
@@ -1,4 +1,3 @@
-huayinz@chromium.org
 twellington@chromium.org
 tedchoc@chromium.org
 
diff --git a/ui/base/ime/ime_input_context_handler_interface.h b/ui/base/ime/ime_input_context_handler_interface.h
index fd46682..5837b4a 100644
--- a/ui/base/ime/ime_input_context_handler_interface.h
+++ b/ui/base/ime/ime_input_context_handler_interface.h
@@ -53,6 +53,9 @@
 
   // Commits any composition text.
   virtual void ConfirmCompositionText() = 0;
+
+  // Returns true if there is any composition text.
+  virtual bool HasCompositionText() = 0;
 };
 
 }  // namespace ui
diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc
index aa1631a..062fa7a7 100644
--- a/ui/base/ime/input_method_base.cc
+++ b/ui/base/ime/input_method_base.cc
@@ -290,6 +290,11 @@
     client->ConfirmCompositionText();
 }
 
+bool InputMethodBase::HasCompositionText() {
+  TextInputClient* client = GetTextInputClient();
+  return client && client->HasCompositionText();
+}
+
 const std::vector<std::unique_ptr<ui::KeyEvent>>&
 InputMethodBase::GetKeyEventsForTesting() {
   return key_events_for_testing_;
diff --git a/ui/base/ime/input_method_base.h b/ui/base/ime/input_method_base.h
index 83ff2fe..04c2e3bd 100644
--- a/ui/base/ime/input_method_base.h
+++ b/ui/base/ime/input_method_base.h
@@ -99,6 +99,7 @@
   void SendKeyEvent(KeyEvent* event) override;
   InputMethod* GetInputMethod() override;
   void ConfirmCompositionText() override;
+  bool HasCompositionText() override;
 
   // Sends a fake key event for IME composing without physical key events.
   // Returns true if the faked key event is stopped propagation.
diff --git a/ui/base/ime/mock_ime_input_context_handler.cc b/ui/base/ime/mock_ime_input_context_handler.cc
index d7db4d06..0325909 100644
--- a/ui/base/ime/mock_ime_input_context_handler.cc
+++ b/ui/base/ime/mock_ime_input_context_handler.cc
@@ -73,9 +73,16 @@
 }
 
 void MockIMEInputContextHandler::ConfirmCompositionText() {
+  if (!HasCompositionText())
+    return;
+
   CommitText(
       base::UTF16ToUTF8(last_update_composition_arg_.composition_text.text));
   last_update_composition_arg_.composition_text.text = base::string16();
 }
 
+bool MockIMEInputContextHandler::HasCompositionText() {
+  return !last_update_composition_arg_.composition_text.text.empty();
+}
+
 }  // namespace ui
diff --git a/ui/base/ime/mock_ime_input_context_handler.h b/ui/base/ime/mock_ime_input_context_handler.h
index 6a9afe4..8708214 100644
--- a/ui/base/ime/mock_ime_input_context_handler.h
+++ b/ui/base/ime/mock_ime_input_context_handler.h
@@ -49,6 +49,7 @@
   void SendKeyEvent(KeyEvent* event) override;
   InputMethod* GetInputMethod() override;
   void ConfirmCompositionText() override;
+  bool HasCompositionText() override;
 
   int commit_text_call_count() const { return commit_text_call_count_; }
 
diff --git a/ui/base/x/x11_window.cc b/ui/base/x/x11_window.cc
index 2b07d1d8..79d1ff4 100644
--- a/ui/base/x/x11_window.cc
+++ b/ui/base/x/x11_window.cc
@@ -381,10 +381,8 @@
   XMapWindow(xdisplay_, xwindow_);
   window_mapped_in_client_ = true;
 
-#if defined(OS_CHROMEOS)
   // TODO(thomasanderson): Find out why this flush is necessary.
   XFlush(xdisplay_);
-#endif
 }
 
 void XWindow::Close() {
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index a96486c1..0e86c7ce 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -624,6 +624,7 @@
         "ozone/evdev/touch_filter/false_touch_finder_unittest.cc",
         "ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter_unittest.cc",
         "ozone/evdev/touch_filter/open_palm_detection_filter_unittest.cc",
+        "ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc",
         "ozone/gamepad/generic_gamepad_mapping_unittest.cc",
       ]
 
diff --git a/ui/events/ozone/BUILD.gn b/ui/events/ozone/BUILD.gn
index aad5d85..b6e66ad2 100644
--- a/ui/events/ozone/BUILD.gn
+++ b/ui/events/ozone/BUILD.gn
@@ -126,6 +126,8 @@
         "evdev/touch_filter/open_palm_detection_filter.h",
         "evdev/touch_filter/palm_detection_filter.cc",
         "evdev/touch_filter/palm_detection_filter.h",
+        "evdev/touch_filter/palm_detection_filter_factory.cc",
+        "evdev/touch_filter/palm_detection_filter_factory.h",
         "evdev/touch_filter/shared_palm_detection_filter_state.h",
         "evdev/touch_filter/single_position_touch_noise_filter.cc",
         "evdev/touch_filter/single_position_touch_noise_filter.h",
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc
index 2aead6ff4..c7543d3 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev.cc
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -56,6 +56,7 @@
 #if defined(USE_EVDEV_GESTURES)
   GesturePropertyProvider* gesture_property_provider;
 #endif
+  SharedPalmDetectionFilterState* shared_palm_state;
 };
 
 #if defined(USE_EVDEV_GESTURES)
@@ -105,7 +106,8 @@
   if (devinfo.HasTouchscreen()) {
     std::unique_ptr<TouchEventConverterEvdev> converter(
         new TouchEventConverterEvdev(std::move(fd), params.path, params.id,
-                                     devinfo, params.dispatcher));
+                                     devinfo, params.shared_palm_state,
+                                     params.dispatcher));
     converter->Initialize(devinfo);
     return std::move(converter);
   }
@@ -169,6 +171,7 @@
     CursorDelegateEvdev* cursor)
     : task_runner_(base::ThreadTaskRunnerHandle::Get()),
       cursor_(cursor),
+      shared_palm_state_(new SharedPalmDetectionFilterState),
 #if defined(USE_EVDEV_GESTURES)
       gesture_property_provider_(new GesturePropertyProvider),
 #endif
@@ -186,6 +189,7 @@
   params.path = path;
   params.cursor = cursor_;
   params.dispatcher = dispatcher_.get();
+  params.shared_palm_state = shared_palm_state_.get();
 
 #if defined(USE_EVDEV_GESTURES)
   params.gesture_property_provider = gesture_property_provider_.get();
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.h b/ui/events/ozone/evdev/input_device_factory_evdev.h
index b078fb2..160f78d 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev.h
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.h
@@ -21,6 +21,7 @@
 #include "ui/events/ozone/evdev/event_device_info.h"
 #include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
 #include "ui/events/ozone/evdev/input_device_settings_evdev.h"
+#include "ui/events/ozone/evdev/touch_filter/shared_palm_detection_filter_state.h"
 #include "ui/ozone/public/input_controller.h"
 
 #if defined(USE_EVDEV_GESTURES)
@@ -110,6 +111,9 @@
   // Cursor movement.
   CursorDelegateEvdev* cursor_;
 
+  // Shared Palm state.
+  const std::unique_ptr<SharedPalmDetectionFilterState> shared_palm_state_;
+
 #if defined(USE_EVDEV_GESTURES)
   // Gesture library property provider (used by touchpads/mice).
   std::unique_ptr<GesturePropertyProvider> gesture_property_provider_;
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.cc b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
index 5b78904..add9a5fa 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev.cc
@@ -19,6 +19,7 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -33,6 +34,8 @@
 #include "ui/events/ozone/evdev/device_event_dispatcher_evdev.h"
 #include "ui/events/ozone/evdev/touch_evdev_types.h"
 #include "ui/events/ozone/evdev/touch_filter/false_touch_finder.h"
+#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
+#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.h"
 #include "ui/ozone/public/input_controller.h"
 
 namespace {
@@ -119,6 +122,7 @@
     base::FilePath path,
     int id,
     const EventDeviceInfo& devinfo,
+    SharedPalmDetectionFilterState* shared_palm_state,
     DeviceEventDispatcherEvdev* dispatcher)
     : EventConverterEvdev(fd.get(),
                           path,
@@ -130,7 +134,9 @@
                           devinfo.product_id(),
                           devinfo.version()),
       input_device_fd_(std::move(fd)),
-      dispatcher_(dispatcher) {
+      dispatcher_(dispatcher),
+      palm_detection_filter_(
+          CreatePalmDetectionFilter(devinfo, shared_palm_state)) {
   touch_evdev_debug_buffer_.Initialize(devinfo);
 }
 
@@ -546,12 +552,15 @@
 
   if (false_touch_finder_)
     false_touch_finder_->HandleTouches(events_, timestamp);
-
+  std::bitset<kNumTouchEvdevSlots> hold, suppress;
+  palm_detection_filter_->Filter(events_, timestamp, &hold, &suppress);
   for (size_t i = 0; i < events_.size(); i++) {
     InProgressTouchEvdev* event = &events_[i];
     if (IsPalm(*event)) {
       event->cancelled = true;
     }
+    event->held |= hold.test(i);
+    event->cancelled |= suppress.test(i);
     if (event->altered && (event->cancelled ||
                            (false_touch_finder_ &&
                             false_touch_finder_->SlotHasNoise(event->slot)))) {
@@ -594,14 +603,19 @@
       auto empty_q =
           std::queue<std::pair<InProgressTouchEvdev, base::TimeTicks>>();
       held_events_[i].swap(empty_q);
+      UMA_HISTOGRAM_COUNTS_100(kHoldCountAtCancelEventName, empty_q.size());
     }
 
-    while (!held_events_[i].empty()) {
-      auto held_event = held_events_[i].front();
-      held_events_[i].pop();
-      held_event.first.held = false;
-      held_event.first.was_held = true;
-      ProcessTouchEvent(&held_event.first, held_event.second);
+    if (!held_events_[i].empty()) {
+      UMA_HISTOGRAM_COUNTS_100(kHoldCountAtReleaseEventName,
+                               held_events_[i].size());
+      while (!held_events_[i].empty()) {
+        auto held_event = held_events_[i].front();
+        held_events_[i].pop();
+        held_event.first.held = false;
+        held_event.first.was_held = true;
+        ProcessTouchEvent(&held_event.first, held_event.second);
+      }
     }
     ProcessTouchEvent(event, timestamp);
     event->was_cancelled = event->cancelled;
@@ -665,4 +679,8 @@
   return next_tracking_id_++ & kMaxTrackingId;
 }
 
+const char TouchEventConverterEvdev::kHoldCountAtReleaseEventName[] =
+    "Ozone.TouchEventConverterEvdev.HoldCountAtRelease";
+const char TouchEventConverterEvdev::kHoldCountAtCancelEventName[] =
+    "Ozone.TouchEventConverterEvdev.HoldCountAtCancel";
 }  // namespace ui
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev.h b/ui/events/ozone/evdev/touch_event_converter_evdev.h
index 81b9bc0..abb5d1cb 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev.h
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev.h
@@ -29,6 +29,7 @@
 #include "ui/events/ozone/evdev/event_device_info.h"
 #include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
 #include "ui/events/ozone/evdev/touch_evdev_debug_buffer.h"
+#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
 
 namespace ui {
 
@@ -43,6 +44,7 @@
                            base::FilePath path,
                            int id,
                            const EventDeviceInfo& devinfo,
+                           SharedPalmDetectionFilterState* shared_palm_state,
                            DeviceEventDispatcherEvdev* dispatcher);
   ~TouchEventConverterEvdev() override;
 
@@ -66,6 +68,9 @@
   // Unsafe part of initialization.
   virtual void Initialize(const EventDeviceInfo& info);
 
+  static const char kHoldCountAtReleaseEventName[];
+  static const char kHoldCountAtCancelEventName[];
+
  private:
   friend class MockTouchEventConverterEvdev;
 
@@ -170,6 +175,9 @@
   // Finds touches that need to be filtered.
   std::unique_ptr<FalseTouchFinder> false_touch_finder_;
 
+  // Finds touches that are palms with user software not just firmware.
+  const std::unique_ptr<PalmDetectionFilter> palm_detection_filter_;
+
   // Records the recent touch events. It is used to fill the feedback reports
   TouchEventLogEvdev touch_evdev_debug_buffer_;
 
diff --git a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
index a7299a3b3..08aa398 100644
--- a/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
+++ b/ui/events/ozone/evdev/touch_event_converter_evdev_unittest.cc
@@ -20,7 +20,9 @@
 #include "base/posix/eintr_wrapper.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/time/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/event_switches.h"
@@ -28,6 +30,7 @@
 #include "ui/events/ozone/evdev/event_device_test_util.h"
 #include "ui/events/ozone/evdev/touch_evdev_types.h"
 #include "ui/events/ozone/evdev/touch_filter/false_touch_finder.h"
+#include "ui/events/ozone/evdev/touch_filter/shared_palm_detection_filter_state.h"
 #include "ui/events/ozone/evdev/touch_filter/touch_filter.h"
 #include "ui/events/platform/platform_event_dispatcher.h"
 #include "ui/events/platform/platform_event_source.h"
@@ -88,10 +91,13 @@
 
 class MockTouchEventConverterEvdev : public TouchEventConverterEvdev {
  public:
-  MockTouchEventConverterEvdev(base::ScopedFD fd,
-                               base::FilePath path,
-                               const EventDeviceInfo& devinfo,
-                               DeviceEventDispatcherEvdev* dispatcher);
+  MockTouchEventConverterEvdev(
+
+      base::ScopedFD fd,
+      base::FilePath path,
+      const EventDeviceInfo& devinfo,
+      SharedPalmDetectionFilterState* shared_palm_state,
+      DeviceEventDispatcherEvdev* dispatcher);
   ~MockTouchEventConverterEvdev() override;
 
   void ConfigureReadMock(struct input_event* queue,
@@ -178,8 +184,14 @@
     base::ScopedFD fd,
     base::FilePath path,
     const EventDeviceInfo& devinfo,
+    SharedPalmDetectionFilterState* shared_palm_state,
     DeviceEventDispatcherEvdev* dispatcher)
-    : TouchEventConverterEvdev(std::move(fd), path, 1, devinfo, dispatcher) {
+    : TouchEventConverterEvdev(std::move(fd),
+                               path,
+                               1,
+                               devinfo,
+                               shared_palm_state,
+                               dispatcher) {
   int fds[2];
 
   if (pipe(fds))
@@ -230,13 +242,14 @@
     // Device creation happens on a worker thread since it may involve blocking
     // operations. Simulate that by creating it before creating a UI message
     // loop.
+    shared_palm_state_.reset(new ui::SharedPalmDetectionFilterState);
     EventDeviceInfo devinfo;
     dispatcher_.reset(new ui::MockDeviceEventDispatcherEvdev(
         base::BindRepeating(&TouchEventConverterEvdevTest::DispatchCallback,
                             base::Unretained(this))));
     device_.reset(new ui::MockTouchEventConverterEvdev(
         std::move(events_in), base::FilePath(kTestDevicePath), devinfo,
-        dispatcher_.get()));
+        shared_palm_state_.get(), dispatcher_.get()));
     device_->Initialize(devinfo);
     loop_ = new base::MessageLoopForUI;
 
@@ -256,7 +269,9 @@
   }
 
   ui::MockTouchEventConverterEvdev* device() { return device_.get(); }
-
+  ui::SharedPalmDetectionFilterState* shared_palm_state() {
+    return shared_palm_state_.get();
+  }
   unsigned size() { return dispatched_events_.size(); }
   const ui::TouchEventParams& dispatched_touch_event(unsigned index) {
     DCHECK_GT(dispatched_events_.size(), index);
@@ -287,19 +302,21 @@
     test_clock_->SetNowTicks(ticks);
   }
 
+ protected:
+  base::HistogramTester histogram_tester_;
+
  private:
   base::MessageLoop* loop_;
   std::unique_ptr<ui::MockTouchEventConverterEvdev> device_;
   std::unique_ptr<ui::MockDeviceEventDispatcherEvdev> dispatcher_;
   std::unique_ptr<ui::test::ScopedEventTestTickClock> test_clock_;
-
+  std::unique_ptr<ui::SharedPalmDetectionFilterState> shared_palm_state_;
   base::ScopedFD events_out_;
 
   void DispatchCallback(const GenericEventParams& params) {
     dispatched_events_.push_back(params);
   }
   std::vector<GenericEventParams> dispatched_events_;
-
   DISALLOW_COPY_AND_ASSIGN(TouchEventConverterEvdevTest);
 };
 
@@ -1606,6 +1623,12 @@
     EXPECT_EQ(base::TimeDelta::FromMicroseconds(8000 * i),
               (event.timestamp - base_ticks));
   }
+  EXPECT_THAT(histogram_tester_.GetAllSamples(
+                  TouchEventConverterEvdev::kHoldCountAtReleaseEventName),
+              testing::ElementsAre(base::Bucket(3, 1)));
+  EXPECT_THAT(histogram_tester_.GetAllSamples(
+                  TouchEventConverterEvdev::kHoldCountAtCancelEventName),
+              testing::ElementsAre());
 }
 
 TEST_F(TouchEventConverterEvdevTest, HeldThenEnd) {
@@ -1661,6 +1684,12 @@
   device()->ReadNow();
   EXPECT_EQ(4u, size());
   EXPECT_EQ(ui::ET_TOUCH_RELEASED, dispatched_touch_event(3).type);
+  EXPECT_THAT(histogram_tester_.GetAllSamples(
+                  TouchEventConverterEvdev::kHoldCountAtReleaseEventName),
+              testing::ElementsAre(base::Bucket(3, 1)));
+  EXPECT_THAT(histogram_tester_.GetAllSamples(
+                  TouchEventConverterEvdev::kHoldCountAtCancelEventName),
+              testing::ElementsAre());
 }
 
 TEST_F(TouchEventConverterEvdevTest, SentHeldThenPalm) {
@@ -1733,6 +1762,12 @@
                 (event.timestamp - base_ticks));
     }
   }
+  EXPECT_THAT(histogram_tester_.GetAllSamples(
+                  TouchEventConverterEvdev::kHoldCountAtReleaseEventName),
+              testing::ElementsAre());
+  EXPECT_THAT(histogram_tester_.GetAllSamples(
+                  TouchEventConverterEvdev::kHoldCountAtCancelEventName),
+              testing::ElementsAre(base::Bucket(5, 1)));
 }
 
 TEST_F(TouchEventConverterEvdevTest, HeldThenPalm) {
@@ -1783,6 +1818,12 @@
 
   EXPECT_EQ(0u, size());
   EXPECT_FALSE(device()->event(0).held);
+  EXPECT_THAT(histogram_tester_.GetAllSamples(
+                  TouchEventConverterEvdev::kHoldCountAtReleaseEventName),
+              testing::ElementsAre());
+  EXPECT_THAT(histogram_tester_.GetAllSamples(
+                  TouchEventConverterEvdev::kHoldCountAtCancelEventName),
+              testing::ElementsAre(base::Bucket(4, 1)));
 }
 
 TEST_F(TouchEventConverterEvdevTest, ScalePressure) {
diff --git a/ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.cc b/ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.cc
index bac6f5d4..a1cac14 100644
--- a/ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.cc
+++ b/ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.cc
@@ -60,5 +60,17 @@
   DCHECK(hold >= cancel) << "Expected hold time to be longer than cancel time.";
 }
 
+const char HeuristicStylusPalmDetectionFilter::kFilterName[] =
+    "HeuristicStylusPalmDetectionFilter";
+std::string HeuristicStylusPalmDetectionFilter::FilterNameForTesting() const {
+  return kFilterName;
+}
 HeuristicStylusPalmDetectionFilter::~HeuristicStylusPalmDetectionFilter() {}
+
+base::TimeDelta HeuristicStylusPalmDetectionFilter::HoldTime() const {
+  return time_after_stylus_to_hold_;
+}
+base::TimeDelta HeuristicStylusPalmDetectionFilter::CancelTime() const {
+  return time_after_stylus_to_cancel_;
+}
 }  // namespace ui
diff --git a/ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.h b/ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.h
index 06e9f6b..7006172 100644
--- a/ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.h
+++ b/ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.h
@@ -26,6 +26,11 @@
 // this are held for the stroke count (as above). If they're cancelled
 // externally, we never report them. If they terminate before the count, we
 // output all items.
+//
+// NOTE: This filter is only intended for certain boards of hardware that have
+// poor interaction between a mutually exclusive stylus and finger input:
+// Turning it on for devices where is not intended will probably degrade
+// performance and create a poor UX.
 class EVENTS_OZONE_EVDEV_EXPORT HeuristicStylusPalmDetectionFilter
     : public PalmDetectionFilter {
  public:
@@ -40,6 +45,12 @@
               std::bitset<kNumTouchEvdevSlots>* slots_to_hold,
               std::bitset<kNumTouchEvdevSlots>* slots_to_suppress) override;
 
+  const static char kFilterName[];
+  std::string FilterNameForTesting() const override;
+
+  base::TimeDelta HoldTime() const;
+  base::TimeDelta CancelTime() const;
+
  private:
   const int hold_stroke_count_;
   const base::TimeDelta time_after_stylus_to_hold_;
diff --git a/ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.cc b/ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.cc
index 8508923b..b7246ac 100644
--- a/ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.cc
+++ b/ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.cc
@@ -18,5 +18,10 @@
   slots_to_suppress->reset();
 }
 
+const char OpenPalmDetectionFilter::kFilterName[] = "OpenPalmDetectionFilter";
+std::string OpenPalmDetectionFilter::FilterNameForTesting() const {
+  return kFilterName;
+}
+
 OpenPalmDetectionFilter::~OpenPalmDetectionFilter() {}
 }  // namespace ui
diff --git a/ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.h b/ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.h
index 73a0fa72..07697ea 100644
--- a/ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.h
+++ b/ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.h
@@ -27,6 +27,9 @@
               std::bitset<kNumTouchEvdevSlots>* slots_to_hold,
               std::bitset<kNumTouchEvdevSlots>* slots_to_suppress) override;
 
+  const static char kFilterName[];
+  std::string FilterNameForTesting() const override;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(OpenPalmDetectionFilter);
 };
diff --git a/ui/events/ozone/evdev/touch_filter/palm_detection_filter.h b/ui/events/ozone/evdev/touch_filter/palm_detection_filter.h
index 7c54def..a5db46f 100644
--- a/ui/events/ozone/evdev/touch_filter/palm_detection_filter.h
+++ b/ui/events/ozone/evdev/touch_filter/palm_detection_filter.h
@@ -39,6 +39,10 @@
                       base::TimeTicks time,
                       std::bitset<kNumTouchEvdevSlots>* slots_to_hold,
                       std::bitset<kNumTouchEvdevSlots>* slots_to_suppress) = 0;
+
+  // The name of this filter, for testing purposes.
+  virtual std::string FilterNameForTesting() const = 0;
+
   virtual ~PalmDetectionFilter();
 
  protected:
diff --git a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc
new file mode 100644
index 0000000..5d29bf53
--- /dev/null
+++ b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.h"
+
+#include <memory>
+
+#include "base/feature_list.h"
+#include "base/time/time.h"
+#include "ui/events/ozone/evdev/event_device_info.h"
+#include "ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.h"
+#include "ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.h"
+#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
+
+namespace ui {
+const base::Feature kEnableHeuristicPalmDetectionFilter{
+    "EnableHeuristicPalmDetectionFilter", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::FeatureParam<double> kHeuristicCancelThresholdSeconds{
+    &kEnableHeuristicPalmDetectionFilter,
+    "heuristic_palm_cancel_threshold_seconds", 0.4};
+
+const base::FeatureParam<double> kHeuristicHoldThresholdSeconds{
+    &kEnableHeuristicPalmDetectionFilter,
+    "heuristic_palm_hold_threshold_seconds", 1.0};
+
+const base::FeatureParam<int> kHeuristicStrokeCount{
+    &kEnableHeuristicPalmDetectionFilter, "heuristic_palm_stroke_count", 0};
+
+std::unique_ptr<PalmDetectionFilter> CreatePalmDetectionFilter(
+    const EventDeviceInfo& devinfo,
+    SharedPalmDetectionFilterState* shared_palm_state) {
+  if (base::FeatureList::IsEnabled(kEnableHeuristicPalmDetectionFilter)) {
+    const base::TimeDelta hold_time =
+        base::TimeDelta::FromSecondsD(kHeuristicHoldThresholdSeconds.Get());
+    const base::TimeDelta cancel_time =
+        base::TimeDelta::FromSecondsD(kHeuristicCancelThresholdSeconds.Get());
+    const int stroke_count = kHeuristicStrokeCount.Get();
+    return std::make_unique<HeuristicStylusPalmDetectionFilter>(
+        shared_palm_state, stroke_count, hold_time, cancel_time);
+  }
+  return std::make_unique<OpenPalmDetectionFilter>(shared_palm_state);
+}
+
+}  // namespace ui
diff --git a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.h b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.h
new file mode 100644
index 0000000..d6b4b77
--- /dev/null
+++ b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.h
@@ -0,0 +1,36 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef UI_EVENTS_OZONE_EVDEV_TOUCH_FILTER_PALM_DETECTION_FILTER_FACTORY_H_
+#define UI_EVENTS_OZONE_EVDEV_TOUCH_FILTER_PALM_DETECTION_FILTER_FACTORY_H_
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/time/time.h"
+#include "ui/events/ozone/evdev/event_device_info.h"
+#include "ui/events/ozone/evdev/events_ozone_evdev_export.h"
+#include "ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.h"
+#include "ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.h"
+#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
+#include "ui/events/ozone/evdev/touch_filter/shared_palm_detection_filter_state.h"
+namespace ui {
+
+extern const EVENTS_OZONE_EVDEV_EXPORT base::Feature
+    kEnableHeuristicPalmDetectionFilter;
+
+extern const EVENTS_OZONE_EVDEV_EXPORT base::FeatureParam<double>
+    kHeuristicCancelThresholdSeconds;
+extern const EVENTS_OZONE_EVDEV_EXPORT base::FeatureParam<double>
+    kHeuristicHoldThresholdSeconds;
+extern const EVENTS_OZONE_EVDEV_EXPORT base::FeatureParam<int>
+    kHeuristicStrokeCount;
+std::unique_ptr<PalmDetectionFilter> EVENTS_OZONE_EVDEV_EXPORT
+CreatePalmDetectionFilter(const EventDeviceInfo& devinfo,
+                          SharedPalmDetectionFilterState* shared_palm_state);
+}  // namespace ui
+
+#endif  // UI_EVENTS_OZONE_EVDEV_TOUCH_FILTER_PALM_DETECTION_FILTER_FACTORY_H_
diff --git a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc
new file mode 100644
index 0000000..4f2c37fa
--- /dev/null
+++ b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.h"
+
+#include <linux/input.h>
+
+#include "base/test/scoped_feature_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/ozone/evdev/event_device_info.h"
+#include "ui/events/ozone/evdev/event_device_test_util.h"
+#include "ui/events/ozone/evdev/touch_filter/open_palm_detection_filter.h"
+#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
+#include "ui/events/ozone/evdev/touch_filter/shared_palm_detection_filter_state.h"
+
+namespace ui {
+class PalmDetectionFilterFactoryTest : public testing::Test {
+ public:
+  PalmDetectionFilterFactoryTest() = default;
+  void SetUp() override {
+    EXPECT_TRUE(
+        CapabilitiesToDeviceInfo(kEveTouchScreen, &eve_touchscreen_info_));
+    EXPECT_TRUE(CapabilitiesToDeviceInfo(kNocturneTouchScreen,
+                                         &nocturne_touchscreen_info_));
+    EXPECT_TRUE(
+        CapabilitiesToDeviceInfo(kNocturneStylus, &nocturne_stylus_info_));
+    EXPECT_TRUE(CapabilitiesToDeviceInfo(kEveStylus, &eve_stylus_info_));
+    scoped_feature_list_.reset(new base::test::ScopedFeatureList);
+  }
+
+ protected:
+  std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
+  EventDeviceInfo eve_touchscreen_info_, eve_stylus_info_,
+      nocturne_touchscreen_info_, nocturne_stylus_info_;
+  SharedPalmDetectionFilterState shared_palm_state_;
+  DISALLOW_COPY_AND_ASSIGN(PalmDetectionFilterFactoryTest);
+};
+
+TEST_F(PalmDetectionFilterFactoryTest, AllDisabled) {
+  scoped_feature_list_->InitAndDisableFeature(
+      ui::kEnableHeuristicPalmDetectionFilter);
+  std::unique_ptr<PalmDetectionFilter> palm_filter =
+      CreatePalmDetectionFilter(eve_touchscreen_info_, &shared_palm_state_);
+  EXPECT_EQ(OpenPalmDetectionFilter::kFilterName,
+            palm_filter->FilterNameForTesting());
+
+  palm_filter = CreatePalmDetectionFilter(nocturne_touchscreen_info_,
+                                          &shared_palm_state_);
+  EXPECT_EQ(OpenPalmDetectionFilter::kFilterName,
+            palm_filter->FilterNameForTesting());
+}
+
+TEST_F(PalmDetectionFilterFactoryTest, HeuristicEnabledForEve) {
+  scoped_feature_list_->InitWithFeaturesAndParameters(
+      {base::test::ScopedFeatureList::FeatureAndParams(
+          ui::kEnableHeuristicPalmDetectionFilter, {})},
+      {});
+  std::unique_ptr<PalmDetectionFilter> palm_filter =
+      CreatePalmDetectionFilter(eve_touchscreen_info_, &shared_palm_state_);
+  EXPECT_EQ(HeuristicStylusPalmDetectionFilter::kFilterName,
+            palm_filter->FilterNameForTesting());
+
+  palm_filter = CreatePalmDetectionFilter(nocturne_touchscreen_info_,
+                                          &shared_palm_state_);
+  EXPECT_EQ(HeuristicStylusPalmDetectionFilter::kFilterName,
+            palm_filter->FilterNameForTesting());
+
+  // And the stylus.
+  palm_filter =
+      CreatePalmDetectionFilter(nocturne_stylus_info_, &shared_palm_state_);
+  EXPECT_EQ(HeuristicStylusPalmDetectionFilter::kFilterName,
+            palm_filter->FilterNameForTesting());
+  palm_filter =
+      CreatePalmDetectionFilter(eve_stylus_info_, &shared_palm_state_);
+  EXPECT_EQ(HeuristicStylusPalmDetectionFilter::kFilterName,
+            palm_filter->FilterNameForTesting());
+}
+
+TEST_F(PalmDetectionFilterFactoryTest, HeuristicTimesSet) {
+  scoped_feature_list_->InitWithFeaturesAndParameters(
+      {base::test::ScopedFeatureList::FeatureAndParams(
+          ui::kEnableHeuristicPalmDetectionFilter,
+          {{"heuristic_palm_cancel_threshold_seconds", "0.8"},
+           {"heuristic_palm_hold_threshold_seconds", "15.327"}})},
+      {});
+
+  std::unique_ptr<PalmDetectionFilter> palm_filter = CreatePalmDetectionFilter(
+      nocturne_touchscreen_info_, &shared_palm_state_);
+  ASSERT_EQ(HeuristicStylusPalmDetectionFilter::kFilterName,
+            palm_filter->FilterNameForTesting());
+  HeuristicStylusPalmDetectionFilter* heuristic_filter =
+      static_cast<HeuristicStylusPalmDetectionFilter*>(palm_filter.get());
+  EXPECT_EQ(base::TimeDelta::FromSecondsD(0.8), heuristic_filter->CancelTime());
+  EXPECT_EQ(base::TimeDelta::FromSecondsD(15.327),
+            heuristic_filter->HoldTime());
+}
+
+}  // namespace ui
diff --git a/ui/file_manager/OWNERS b/ui/file_manager/OWNERS
index 6db7e1c..353bd977 100644
--- a/ui/file_manager/OWNERS
+++ b/ui/file_manager/OWNERS
@@ -1,4 +1,5 @@
 amistry@chromium.org
+austinct@chromium.org
 dats@chromium.org
 fdegros@chromium.org
 fukino@chromium.org
diff --git a/ui/gfx/mojom/color_space_for_blink.typemap b/ui/gfx/mojom/color_space_for_blink.typemap
new file mode 100644
index 0000000..6971705
--- /dev/null
+++ b/ui/gfx/mojom/color_space_for_blink.typemap
@@ -0,0 +1,12 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//ui/gfx/mojom/color_space.mojom"
+public_headers = [ "//ui/gfx/color_space.h" ]
+traits_headers = [ "//ui/gfx/mojom/color_space_mojom_traits.h" ]
+
+public_deps = [
+  "//ui/gfx",
+]
+type_mappings = [ "gfx.mojom.ColorSpace=gfx::ColorSpace" ]
diff --git a/ui/native_theme/common_theme.cc b/ui/native_theme/common_theme.cc
index 4893693..8bd17ec4 100644
--- a/ui/native_theme/common_theme.cc
+++ b/ui/native_theme/common_theme.cc
@@ -17,7 +17,11 @@
 namespace ui {
 
 SkColor GetAuraColor(NativeTheme::ColorId color_id,
-                     const NativeTheme* base_theme) {
+                     const NativeTheme* base_theme,
+                     NativeTheme::ColorScheme color_scheme) {
+  if (color_scheme == NativeTheme::ColorScheme::kDefault)
+    color_scheme = base_theme->GetSystemColorScheme();
+
   // High contrast overrides the normal colors for certain ColorIds to be much
   // darker or lighter.
   if (base_theme->UsesHighContrastColors()) {
@@ -29,18 +33,19 @@
       case NativeTheme::kColorId_SeparatorColor:
       case NativeTheme::kColorId_UnfocusedBorderColor:
       case NativeTheme::kColorId_TabBottomBorder:
-        return base_theme->SystemDarkModeEnabled() ? SK_ColorWHITE
-                                                   : SK_ColorBLACK;
+        return color_scheme == NativeTheme::ColorScheme::kDark ? SK_ColorWHITE
+                                                               : SK_ColorBLACK;
       case NativeTheme::kColorId_FocusedBorderColor:
       case NativeTheme::kColorId_ProminentButtonColor:
-        return base_theme->SystemDarkModeEnabled() ? gfx::kGoogleBlue100
-                                                   : gfx::kGoogleBlue900;
+        return color_scheme == NativeTheme::ColorScheme::kDark
+                   ? gfx::kGoogleBlue100
+                   : gfx::kGoogleBlue900;
       default:
         break;
     }
   }
 
-  if (base_theme->SystemDarkModeEnabled()) {
+  if (color_scheme == NativeTheme::ColorScheme::kDark) {
     switch (color_id) {
       // Dialogs
       case NativeTheme::kColorId_WindowBackground:
@@ -98,7 +103,7 @@
             SK_ColorWHITE,
             GetAuraColor(
                 NativeTheme::kColorId_LabelTextSelectionBackgroundFocused,
-                base_theme),
+                base_theme, color_scheme),
             SkAlpha{0xDD});
       case NativeTheme::kColorId_LabelTextSelectionBackgroundFocused:
         return SkColorSetA(gfx::kGoogleBlue700, 0xCC);
@@ -122,7 +127,7 @@
             SK_ColorWHITE,
             GetAuraColor(
                 NativeTheme::kColorId_LabelTextSelectionBackgroundFocused,
-                base_theme),
+                base_theme, color_scheme),
             SkAlpha{0xDD});
       case NativeTheme::kColorId_TextfieldSelectionBackgroundFocused:
         return SkColorSetA(gfx::kGoogleBlue700, 0xCC);
@@ -138,7 +143,7 @@
             SK_ColorWHITE,
             GetAuraColor(
                 NativeTheme::kColorId_LabelTextSelectionBackgroundFocused,
-                base_theme),
+                base_theme, color_scheme),
             SkAlpha{0xDD});
 
       // Material spinner/throbber
@@ -169,7 +174,8 @@
       return kPrimaryTextColor;
     case NativeTheme::kColorId_LabelDisabledColor:
       return SkColorSetA(
-          base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor),
+          base_theme->GetSystemColor(NativeTheme::kColorId_LabelEnabledColor,
+                                     color_scheme),
           gfx::kDisabledControlAlpha);
 
     // FocusableBorder
@@ -180,11 +186,13 @@
     case NativeTheme::kColorId_TextfieldDefaultColor:
       return kPrimaryTextColor;
     case NativeTheme::kColorId_TextfieldDefaultBackground:
-      return base_theme->GetSystemColor(NativeTheme::kColorId_DialogBackground);
+      return base_theme->GetSystemColor(NativeTheme::kColorId_DialogBackground,
+                                        color_scheme);
     case NativeTheme::kColorId_TextfieldReadOnlyColor:
-      return SkColorSetA(base_theme->GetSystemColor(
-                             NativeTheme::kColorId_TextfieldDefaultColor),
-                         gfx::kDisabledControlAlpha);
+      return SkColorSetA(
+          base_theme->GetSystemColor(
+              NativeTheme::kColorId_TextfieldDefaultColor, color_scheme),
+          gfx::kDisabledControlAlpha);
 
     default:
       break;
@@ -265,7 +273,7 @@
       return kButtonEnabledColor;
     case NativeTheme::kColorId_LabelDisabledColor:
       return base_theme->GetSystemColor(
-          NativeTheme::kColorId_ButtonDisabledColor);
+          NativeTheme::kColorId_ButtonDisabledColor, color_scheme);
     case NativeTheme::kColorId_LabelTextSelectionColor:
       return kTextSelectionColor;
     case NativeTheme::kColorId_LabelTextSelectionBackgroundFocused:
@@ -338,12 +346,13 @@
     // Table Header
     case NativeTheme::kColorId_TableHeaderText:
       return base_theme->GetSystemColor(
-          NativeTheme::kColorId_EnabledMenuItemForegroundColor);
+          NativeTheme::kColorId_EnabledMenuItemForegroundColor, color_scheme);
     case NativeTheme::kColorId_TableHeaderBackground:
       return base_theme->GetSystemColor(
-          NativeTheme::kColorId_MenuBackgroundColor);
+          NativeTheme::kColorId_MenuBackgroundColor, color_scheme);
     case NativeTheme::kColorId_TableHeaderSeparator:
-      return base_theme->GetSystemColor(NativeTheme::kColorId_MenuBorderColor);
+      return base_theme->GetSystemColor(NativeTheme::kColorId_MenuBorderColor,
+                                        color_scheme);
 
     // FocusableBorder
     case NativeTheme::kColorId_FocusedBorderColor:
@@ -383,17 +392,18 @@
     cc::PaintCanvas* canvas,
     NativeTheme::State state,
     const gfx::Rect& rect,
-    const NativeTheme::MenuItemExtraParams& menu_item) {
+    const NativeTheme::MenuItemExtraParams& menu_item,
+    NativeTheme::ColorScheme color_scheme) {
   cc::PaintFlags flags;
   switch (state) {
     case NativeTheme::kNormal:
     case NativeTheme::kDisabled:
-      flags.setColor(
-          theme->GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor));
+      flags.setColor(theme->GetSystemColor(
+          NativeTheme::kColorId_MenuBackgroundColor, color_scheme));
       break;
     case NativeTheme::kHovered:
       flags.setColor(theme->GetSystemColor(
-          NativeTheme::kColorId_FocusedMenuItemBackgroundColor));
+          NativeTheme::kColorId_FocusedMenuItemBackgroundColor, color_scheme));
       break;
     default:
       NOTREACHED() << "Invalid state " << state;
diff --git a/ui/native_theme/common_theme.h b/ui/native_theme/common_theme.h
index f323478..1d27507 100644
--- a/ui/native_theme/common_theme.h
+++ b/ui/native_theme/common_theme.h
@@ -17,15 +17,18 @@
 // Returns the color to use on Aura for |color_id|.  For a few colors that are
 // theme-specific, |base_theme| must be non-null; consult the code to see which
 // color IDs fall into this category.
-SkColor NATIVE_THEME_EXPORT GetAuraColor(NativeTheme::ColorId color_id,
-                                         const NativeTheme* base_theme);
+SkColor NATIVE_THEME_EXPORT GetAuraColor(
+    NativeTheme::ColorId color_id,
+    const NativeTheme* base_theme,
+    NativeTheme::ColorScheme color_scheme = NativeTheme::ColorScheme::kDefault);
 
 void NATIVE_THEME_EXPORT CommonThemePaintMenuItemBackground(
     const NativeTheme* theme,
     cc::PaintCanvas* canvas,
     NativeTheme::State state,
     const gfx::Rect& rect,
-    const NativeTheme::MenuItemExtraParams& menu_item);
+    const NativeTheme::MenuItemExtraParams& menu_item,
+    NativeTheme::ColorScheme color_scheme);
 
 }  // namespace ui
 
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc
index 5970ab2..ef5664f1 100644
--- a/ui/native_theme/native_theme.cc
+++ b/ui/native_theme/native_theme.cc
@@ -111,4 +111,8 @@
     theme_to_update_->NotifyObservers();
 }
 
+NativeTheme::ColorScheme NativeTheme::GetSystemColorScheme() const {
+  return SystemDarkModeEnabled() ? ColorScheme::kDark : ColorScheme::kLight;
+}
+
 }  // namespace ui
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
index 97ced9d2..66d67f8 100644
--- a/ui/native_theme/native_theme.h
+++ b/ui/native_theme/native_theme.h
@@ -100,6 +100,21 @@
     kNumStates = kPressed + 1,
   };
 
+  // OS-level preferred color scheme. (Ex. high contrast or dark mode color
+  // preference.)
+  enum PreferredColorScheme {
+    kNoPreference,
+    kDark,
+    kLight,
+  };
+
+  // The color scheme used for painting the native controls.
+  enum class ColorScheme {
+    kDefault,
+    kLight,
+    kDark,
+  };
+
   // Each structure below holds extra information needed when painting a given
   // part.
 
@@ -254,11 +269,13 @@
                                 const ExtraParams& extra) const = 0;
 
   // Paint the part to the canvas.
-  virtual void Paint(cc::PaintCanvas* canvas,
-                     Part part,
-                     State state,
-                     const gfx::Rect& rect,
-                     const ExtraParams& extra) const = 0;
+  virtual void Paint(
+      cc::PaintCanvas* canvas,
+      Part part,
+      State state,
+      const gfx::Rect& rect,
+      const ExtraParams& extra,
+      ColorScheme color_scheme = ColorScheme::kDefault) const = 0;
 
   // Paint part during state transition, used for overlay scrollbar state
   // transition animation.
@@ -383,7 +400,9 @@
   };
 
   // Return a color from the system theme.
-  virtual SkColor GetSystemColor(ColorId color_id) const = 0;
+  virtual SkColor GetSystemColor(
+      ColorId color_id,
+      ColorScheme color_scheme = ColorScheme::kDefault) const = 0;
 
   // Returns a shared instance of the native theme that should be used for web
   // rendering. Do not use it in a normal application context (i.e. browser).
@@ -413,14 +432,6 @@
   // Whether OS-level dark mode is available in the current OS.
   virtual bool SystemDarkModeSupported() const;
 
-  // OS-level preferred color scheme. (Ex. high contrast or dark mode color
-  // preference.)
-  enum PreferredColorScheme {
-    kNoPreference,
-    kDark,
-    kLight,
-  };
-
   // Returns the OS-level user preferred color scheme. See the comment for
   // CalculatePreferredColorScheme() for details on how preferred color scheme
   // is calculated.
@@ -429,6 +440,8 @@
   // Returns the system's caption style.
   virtual base::Optional<CaptionStyle> GetSystemCaptionStyle() const;
 
+  ColorScheme GetSystemColorScheme() const;
+
  protected:
   NativeTheme();
   virtual ~NativeTheme();
diff --git a/ui/native_theme/native_theme_android.cc b/ui/native_theme/native_theme_android.cc
index 3ddb6434..ac53a989 100644
--- a/ui/native_theme/native_theme_android.cc
+++ b/ui/native_theme/native_theme_android.cc
@@ -41,7 +41,8 @@
   return NativeThemeBase::GetPartSize(part, state, extra);
 }
 
-SkColor NativeThemeAndroid::GetSystemColor(ColorId color_id) const {
+SkColor NativeThemeAndroid::GetSystemColor(ColorId color_id,
+                                           ColorScheme color_scheme) const {
   NOTIMPLEMENTED();
   return SK_ColorBLACK;
 }
diff --git a/ui/native_theme/native_theme_android.h b/ui/native_theme/native_theme_android.h
index 5736f97..6d5c381 100644
--- a/ui/native_theme/native_theme_android.h
+++ b/ui/native_theme/native_theme_android.h
@@ -18,7 +18,8 @@
   gfx::Size GetPartSize(Part part,
                         State state,
                         const ExtraParams& extra) const override;
-  SkColor GetSystemColor(ColorId color_id) const override;
+  SkColor GetSystemColor(ColorId color_id,
+                         ColorScheme color_scheme) const override;
 
  protected:
   friend class NativeTheme;
diff --git a/ui/native_theme/native_theme_aura.cc b/ui/native_theme/native_theme_aura.cc
index 817ad21..416cf4a 100644
--- a/ui/native_theme/native_theme_aura.cc
+++ b/ui/native_theme/native_theme_aura.cc
@@ -146,15 +146,18 @@
 }
 
 // This implementation returns hardcoded colors.
-SkColor NativeThemeAura::GetSystemColor(ColorId color_id) const {
-  return GetAuraColor(color_id, this);
+SkColor NativeThemeAura::GetSystemColor(ColorId color_id,
+                                        ColorScheme color_scheme) const {
+  return GetAuraColor(color_id, this, color_scheme);
 }
 
 void NativeThemeAura::PaintMenuPopupBackground(
     cc::PaintCanvas* canvas,
     const gfx::Size& size,
-    const MenuBackgroundExtraParams& menu_background) const {
-  SkColor color = GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor);
+    const MenuBackgroundExtraParams& menu_background,
+    ColorScheme color_scheme) const {
+  SkColor color =
+      GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor, color_scheme);
   if (menu_background.corner_radius > 0) {
     cc::PaintFlags flags;
     flags.setStyle(cc::PaintFlags::kFill_Style);
@@ -179,20 +182,23 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const MenuItemExtraParams& menu_item) const {
-  CommonThemePaintMenuItemBackground(this, canvas, state, rect, menu_item);
+    const MenuItemExtraParams& menu_item,
+    ColorScheme color_scheme) const {
+  CommonThemePaintMenuItemBackground(this, canvas, state, rect, menu_item,
+                                     color_scheme);
 }
 
 void NativeThemeAura::PaintArrowButton(cc::PaintCanvas* canvas,
                                        const gfx::Rect& rect,
                                        Part direction,
-                                       State state) const {
+                                       State state,
+                                       ColorScheme color_scheme) const {
   SkColor bg_color = kTrackColor;
   // Aura-win uses slightly different arrow colors.
   SkColor arrow_color = gfx::kPlaceholderColor;
   switch (state) {
     case kDisabled:
-      arrow_color = GetArrowColor(state);
+      arrow_color = GetArrowColor(state, color_scheme);
       break;
     case kHovered:
       bg_color = SkColorSetRGB(0xD2, 0xD2, 0xD2);
@@ -221,7 +227,8 @@
     Part part,
     State state,
     const ScrollbarTrackExtraParams& extra_params,
-    const gfx::Rect& rect) const {
+    const gfx::Rect& rect,
+    ColorScheme color_scheme) const {
   // Overlay Scrollbar should never paint a scrollbar track.
   DCHECK(!use_overlay_scrollbars_);
   cc::PaintFlags flags;
@@ -229,12 +236,12 @@
   canvas->drawIRect(gfx::RectToSkIRect(rect), flags);
 }
 
-void NativeThemeAura::PaintScrollbarThumb(
-    cc::PaintCanvas* canvas,
-    Part part,
-    State state,
-    const gfx::Rect& rect,
-    ScrollbarOverlayColorTheme theme) const {
+void NativeThemeAura::PaintScrollbarThumb(cc::PaintCanvas* canvas,
+                                          Part part,
+                                          State state,
+                                          const gfx::Rect& rect,
+                                          ScrollbarOverlayColorTheme theme,
+                                          ColorScheme color_scheme) const {
   // Do not paint if state is disabled.
   if (state == kDisabled)
     return;
@@ -339,7 +346,8 @@
 
 void NativeThemeAura::PaintScrollbarCorner(cc::PaintCanvas* canvas,
                                            State state,
-                                           const gfx::Rect& rect) const {
+                                           const gfx::Rect& rect,
+                                           ColorScheme color_scheme) const {
   // Overlay Scrollbar should never paint a scrollbar corner.
   DCHECK(!use_overlay_scrollbars_);
   cc::PaintFlags flags;
@@ -350,13 +358,15 @@
 void NativeThemeAura::PaintCheckbox(cc::PaintCanvas* canvas,
                                     State state,
                                     const gfx::Rect& rect,
-                                    const ButtonExtraParams& button) const {
+                                    const ButtonExtraParams& button,
+                                    ColorScheme color_scheme) const {
   if (!features::IsFormControlsRefreshEnabled()) {
-    return NativeThemeBase::PaintCheckbox(canvas, state, rect, button);
+    return NativeThemeBase::PaintCheckbox(canvas, state, rect, button,
+                                          color_scheme);
   }
 
   SkRect skrect = PaintCheckboxRadioCommon(
-      canvas, state, rect, SkIntToScalar(kCheckboxBorderRadius));
+      canvas, state, rect, SkIntToScalar(kCheckboxBorderRadius), color_scheme);
 
   if (!skrect.isEmpty()) {
     // Draw the checkmark / dash.
@@ -391,9 +401,11 @@
 void NativeThemeAura::PaintRadio(cc::PaintCanvas* canvas,
                                  State state,
                                  const gfx::Rect& rect,
-                                 const ButtonExtraParams& button) const {
+                                 const ButtonExtraParams& button,
+                                 ColorScheme color_scheme) const {
   if (!features::IsFormControlsRefreshEnabled()) {
-    return NativeThemeBase::PaintRadio(canvas, state, rect, button);
+    return NativeThemeBase::PaintRadio(canvas, state, rect, button,
+                                       color_scheme);
   }
 
   // Most of a radio button is the same as a checkbox, except the the rounded
@@ -401,7 +413,8 @@
   const SkScalar radius = SkFloatToScalar(
       static_cast<float>(std::max(rect.width(), rect.height())) * 0.5);
 
-  SkRect skrect = PaintCheckboxRadioCommon(canvas, state, rect, radius);
+  SkRect skrect =
+      PaintCheckboxRadioCommon(canvas, state, rect, radius, color_scheme);
   if (!skrect.isEmpty() && button.checked) {
     // Draw the dot.
     cc::PaintFlags flags;
@@ -426,7 +439,8 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const SkScalar borderRadius) const {
+    const SkScalar borderRadius,
+    ColorScheme color_scheme) const {
   SkRect skrect = gfx::RectToSkRect(rect);
 
   // Use the largest square that fits inside the provided rectangle.
@@ -479,9 +493,11 @@
 void NativeThemeAura::PaintTextField(cc::PaintCanvas* canvas,
                                      State state,
                                      const gfx::Rect& rect,
-                                     const TextFieldExtraParams& text) const {
+                                     const TextFieldExtraParams& text,
+                                     ColorScheme color_scheme) const {
   if (!features::IsFormControlsRefreshEnabled()) {
-    return NativeThemeBase::PaintTextField(canvas, state, rect, text);
+    return NativeThemeBase::PaintTextField(canvas, state, rect, text,
+                                           color_scheme);
   }
 
   SkRect bounds = gfx::RectToSkRect(rect);
@@ -513,9 +529,11 @@
 void NativeThemeAura::PaintButton(cc::PaintCanvas* canvas,
                                   State state,
                                   const gfx::Rect& rect,
-                                  const ButtonExtraParams& button) const {
+                                  const ButtonExtraParams& button,
+                                  ColorScheme color_scheme) const {
   if (!features::IsFormControlsRefreshEnabled()) {
-    return NativeThemeBase::PaintButton(canvas, state, rect, button);
+    return NativeThemeBase::PaintButton(canvas, state, rect, button,
+                                        color_scheme);
   }
 
   cc::PaintFlags flags;
@@ -592,9 +610,11 @@
 void NativeThemeAura::PaintSliderTrack(cc::PaintCanvas* canvas,
                                        State state,
                                        const gfx::Rect& rect,
-                                       const SliderExtraParams& slider) const {
+                                       const SliderExtraParams& slider,
+                                       ColorScheme color_scheme) const {
   if (!features::IsFormControlsRefreshEnabled()) {
-    return NativeThemeBase::PaintSliderTrack(canvas, state, rect, slider);
+    return NativeThemeBase::PaintSliderTrack(canvas, state, rect, slider,
+                                             color_scheme);
   }
 
   // Paint the entire slider track.
@@ -630,9 +650,11 @@
 void NativeThemeAura::PaintSliderThumb(cc::PaintCanvas* canvas,
                                        State state,
                                        const gfx::Rect& rect,
-                                       const SliderExtraParams& slider) const {
+                                       const SliderExtraParams& slider,
+                                       ColorScheme color_scheme) const {
   if (!features::IsFormControlsRefreshEnabled()) {
-    return NativeThemeBase::PaintSliderThumb(canvas, state, rect, slider);
+    return NativeThemeBase::PaintSliderThumb(canvas, state, rect, slider,
+                                             color_scheme);
   }
 
   const SkScalar radius = SkFloatToScalar(
@@ -660,13 +682,14 @@
   canvas->drawRoundRect(thumb_rect, radius, radius, flags);
 }
 
-void NativeThemeAura::PaintMenuList(
-    cc::PaintCanvas* canvas,
-    State state,
-    const gfx::Rect& rect,
-    const MenuListExtraParams& menu_list) const {
+void NativeThemeAura::PaintMenuList(cc::PaintCanvas* canvas,
+                                    State state,
+                                    const gfx::Rect& rect,
+                                    const MenuListExtraParams& menu_list,
+                                    ColorScheme color_scheme) const {
   if (!features::IsFormControlsRefreshEnabled()) {
-    return NativeThemeBase::PaintMenuList(canvas, state, rect, menu_list);
+    return NativeThemeBase::PaintMenuList(canvas, state, rect, menu_list,
+                                          color_scheme);
   }
 
   // If a border radius is specified paint the background and the border of
@@ -676,7 +699,7 @@
   if (!menu_list.has_border_radius) {
     TextFieldExtraParams text_field = {0};
     text_field.background_color = menu_list.background_color;
-    PaintTextField(canvas, state, rect, text_field);
+    PaintTextField(canvas, state, rect, text_field, color_scheme);
   }
 
   // Paint the arrow.
diff --git a/ui/native_theme/native_theme_aura.h b/ui/native_theme/native_theme_aura.h
index 1217b87..71e6ca30 100644
--- a/ui/native_theme/native_theme_aura.h
+++ b/ui/native_theme/native_theme_aura.h
@@ -25,61 +25,74 @@
   static NativeThemeAura* web_instance();
 
   // NativeThemeBase:
-  SkColor GetSystemColor(ColorId color_id) const override;
+  SkColor GetSystemColor(ColorId color_id,
+                         ColorScheme color_scheme) const override;
   void PaintMenuPopupBackground(
       cc::PaintCanvas* canvas,
       const gfx::Size& size,
-      const MenuBackgroundExtraParams& menu_background) const override;
-  void PaintMenuItemBackground(
-      cc::PaintCanvas* canvas,
-      State state,
-      const gfx::Rect& rect,
-      const MenuItemExtraParams& menu_item) const override;
+      const MenuBackgroundExtraParams& menu_background,
+      ColorScheme color_scheme) const override;
+  void PaintMenuItemBackground(cc::PaintCanvas* canvas,
+                               State state,
+                               const gfx::Rect& rect,
+                               const MenuItemExtraParams& menu_item,
+                               ColorScheme color_scheme) const override;
   void PaintArrowButton(cc::PaintCanvas* gc,
                         const gfx::Rect& rect,
                         Part direction,
-                        State state) const override;
+                        State state,
+                        ColorScheme color_scheme) const override;
   void PaintScrollbarTrack(cc::PaintCanvas* canvas,
                            Part part,
                            State state,
                            const ScrollbarTrackExtraParams& extra_params,
-                           const gfx::Rect& rect) const override;
+                           const gfx::Rect& rect,
+                           ColorScheme color_scheme) const override;
   void PaintScrollbarThumb(cc::PaintCanvas* canvas,
                            Part part,
                            State state,
                            const gfx::Rect& rect,
-                           ScrollbarOverlayColorTheme theme) const override;
+                           ScrollbarOverlayColorTheme theme,
+                           ColorScheme color_scheme) const override;
   void PaintScrollbarCorner(cc::PaintCanvas* canvas,
                             State state,
-                            const gfx::Rect& rect) const override;
+                            const gfx::Rect& rect,
+                            ColorScheme color_scheme) const override;
   void PaintCheckbox(cc::PaintCanvas* canvas,
                      State state,
                      const gfx::Rect& rect,
-                     const ButtonExtraParams& button) const override;
+                     const ButtonExtraParams& button,
+                     ColorScheme color_scheme) const override;
   void PaintRadio(cc::PaintCanvas* canvas,
                   State state,
                   const gfx::Rect& rect,
-                  const ButtonExtraParams& button) const override;
+                  const ButtonExtraParams& button,
+                  ColorScheme color_scheme) const override;
   void PaintTextField(cc::PaintCanvas* canvas,
                       State state,
                       const gfx::Rect& rect,
-                      const TextFieldExtraParams& text) const override;
+                      const TextFieldExtraParams& text,
+                      ColorScheme color_scheme) const override;
   void PaintButton(cc::PaintCanvas* canvas,
                    State state,
                    const gfx::Rect& rect,
-                   const ButtonExtraParams& button) const override;
+                   const ButtonExtraParams& button,
+                   ColorScheme color_scheme) const override;
   void PaintSliderTrack(cc::PaintCanvas* canvas,
                         State state,
                         const gfx::Rect& rect,
-                        const SliderExtraParams& slider) const override;
+                        const SliderExtraParams& slider,
+                        ColorScheme color_scheme) const override;
   void PaintSliderThumb(cc::PaintCanvas* canvas,
                         State state,
                         const gfx::Rect& rect,
-                        const SliderExtraParams& slider) const override;
+                        const SliderExtraParams& slider,
+                        ColorScheme color_scheme) const override;
   void PaintMenuList(cc::PaintCanvas* canvas,
                      State state,
                      const gfx::Rect& rect,
-                     const MenuListExtraParams& menu_list) const override;
+                     const MenuListExtraParams& menu_list,
+                     ColorScheme color_scheme) const override;
   gfx::Size GetPartSize(Part part,
                         State state,
                         const ExtraParams& extra) const override;
@@ -93,7 +106,8 @@
   SkRect PaintCheckboxRadioCommon(cc::PaintCanvas* canvas,
                                   State state,
                                   const gfx::Rect& rect,
-                                  const SkScalar borderRadius) const;
+                                  const SkScalar borderRadius,
+                                  ColorScheme color_scheme) const;
 
   bool use_overlay_scrollbars_;
 
diff --git a/ui/native_theme/native_theme_base.cc b/ui/native_theme/native_theme_base.cc
index b07dd41..c27d4e7 100644
--- a/ui/native_theme/native_theme_base.cc
+++ b/ui/native_theme/native_theme_base.cc
@@ -164,7 +164,8 @@
                             Part part,
                             State state,
                             const gfx::Rect& rect,
-                            const ExtraParams& extra) const {
+                            const ExtraParams& extra,
+                            ColorScheme color_scheme) const {
   if (rect.IsEmpty())
     return;
 
@@ -174,52 +175,57 @@
   switch (part) {
     // Please keep these in the order of NativeTheme::Part.
     case kCheckbox:
-      PaintCheckbox(canvas, state, rect, extra.button);
+      PaintCheckbox(canvas, state, rect, extra.button, color_scheme);
       break;
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
     case kFrameTopArea:
-      PaintFrameTopArea(canvas, state, rect, extra.frame_top_area);
+      PaintFrameTopArea(canvas, state, rect, extra.frame_top_area,
+                        color_scheme);
       break;
 #endif
     case kInnerSpinButton:
-      PaintInnerSpinButton(canvas, state, rect, extra.inner_spin);
+      PaintInnerSpinButton(canvas, state, rect, extra.inner_spin, color_scheme);
       break;
     case kMenuList:
-      PaintMenuList(canvas, state, rect, extra.menu_list);
+      PaintMenuList(canvas, state, rect, extra.menu_list, color_scheme);
       break;
     case kMenuPopupBackground:
-      PaintMenuPopupBackground(canvas, rect.size(), extra.menu_background);
+      PaintMenuPopupBackground(canvas, rect.size(), extra.menu_background,
+                               color_scheme);
       break;
     case kMenuPopupSeparator:
-      PaintMenuSeparator(canvas, state, rect, extra.menu_separator);
+      PaintMenuSeparator(canvas, state, rect, extra.menu_separator,
+                         color_scheme);
       break;
     case kMenuItemBackground:
-      PaintMenuItemBackground(canvas, state, rect, extra.menu_item);
+      PaintMenuItemBackground(canvas, state, rect, extra.menu_item,
+                              color_scheme);
       break;
     case kProgressBar:
-      PaintProgressBar(canvas, state, rect, extra.progress_bar);
+      PaintProgressBar(canvas, state, rect, extra.progress_bar, color_scheme);
       break;
     case kPushButton:
-      PaintButton(canvas, state, rect, extra.button);
+      PaintButton(canvas, state, rect, extra.button, color_scheme);
       break;
     case kRadio:
-      PaintRadio(canvas, state, rect, extra.button);
+      PaintRadio(canvas, state, rect, extra.button, color_scheme);
       break;
     case kScrollbarDownArrow:
     case kScrollbarUpArrow:
     case kScrollbarLeftArrow:
     case kScrollbarRightArrow:
       if (scrollbar_button_length_ > 0)
-        PaintArrowButton(canvas, rect, part, state);
+        PaintArrowButton(canvas, rect, part, state, color_scheme);
       break;
     case kScrollbarHorizontalThumb:
     case kScrollbarVerticalThumb:
       PaintScrollbarThumb(canvas, part, state, rect,
-                          extra.scrollbar_thumb.scrollbar_theme);
+                          extra.scrollbar_thumb.scrollbar_theme, color_scheme);
       break;
     case kScrollbarHorizontalTrack:
     case kScrollbarVerticalTrack:
-      PaintScrollbarTrack(canvas, part, state, extra.scrollbar_track, rect);
+      PaintScrollbarTrack(canvas, part, state, extra.scrollbar_track, rect,
+                          color_scheme);
       break;
     case kScrollbarHorizontalGripper:
     case kScrollbarVerticalGripper:
@@ -227,19 +233,19 @@
       // implementations, so no NOTIMPLEMENTED.
       break;
     case kScrollbarCorner:
-      PaintScrollbarCorner(canvas, state, rect);
+      PaintScrollbarCorner(canvas, state, rect, color_scheme);
       break;
     case kSliderTrack:
-      PaintSliderTrack(canvas, state, rect, extra.slider);
+      PaintSliderTrack(canvas, state, rect, extra.slider, color_scheme);
       break;
     case kSliderThumb:
-      PaintSliderThumb(canvas, state, rect, extra.slider);
+      PaintSliderThumb(canvas, state, rect, extra.slider, color_scheme);
       break;
     case kTabPanelBackground:
       NOTIMPLEMENTED();
       break;
     case kTextField:
-      PaintTextField(canvas, state, rect, extra.text_field);
+      PaintTextField(canvas, state, rect, extra.text_field, color_scheme);
       break;
     case kTrackbarThumb:
     case kTrackbarTrack:
@@ -279,7 +285,8 @@
 void NativeThemeBase::PaintArrowButton(cc::PaintCanvas* canvas,
                                        const gfx::Rect& rect,
                                        Part direction,
-                                       State state) const {
+                                       State state,
+                                       ColorScheme color_scheme) const {
   cc::PaintFlags flags;
 
   // Calculate button color.
@@ -355,7 +362,7 @@
   flags.setColor(OutlineColor(trackHSV, thumbHSV));
   canvas->drawPath(outline, flags);
 
-  PaintArrow(canvas, rect, direction, GetArrowColor(state));
+  PaintArrow(canvas, rect, direction, GetArrowColor(state, color_scheme));
 }
 
 void NativeThemeBase::PaintArrow(cc::PaintCanvas* gc,
@@ -420,7 +427,8 @@
     Part part,
     State state,
     const ScrollbarTrackExtraParams& extra_params,
-    const gfx::Rect& rect) const {
+    const gfx::Rect& rect,
+    ColorScheme color_scheme) const {
   cc::PaintFlags flags;
   SkIRect skrect;
 
@@ -441,7 +449,8 @@
                                           Part part,
                                           State state,
                                           const gfx::Rect& rect,
-                                          ScrollbarOverlayColorTheme) const {
+                                          ScrollbarOverlayColorTheme,
+                                          ColorScheme color_scheme) const {
   const bool hovered = state == kHovered;
   const int midx = rect.x() + rect.width() / 2;
   const int midy = rect.y() + rect.height() / 2;
@@ -501,14 +510,16 @@
 
 void NativeThemeBase::PaintScrollbarCorner(cc::PaintCanvas* canvas,
                                            State state,
-                                           const gfx::Rect& rect) const {}
+                                           const gfx::Rect& rect,
+                                           ColorScheme color_scheme) const {}
 
 void NativeThemeBase::PaintCheckbox(cc::PaintCanvas* canvas,
                                     State state,
                                     const gfx::Rect& rect,
-                                    const ButtonExtraParams& button) const {
+                                    const ButtonExtraParams& button,
+                                    ColorScheme color_scheme) const {
   SkRect skrect = PaintCheckboxRadioCommon(canvas, state, rect,
-                                           SkIntToScalar(2));
+                                           SkIntToScalar(2), color_scheme);
   if (!skrect.isEmpty()) {
     // Draw the checkmark / dash.
     cc::PaintFlags flags;
@@ -545,7 +556,8 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const SkScalar borderRadius) const {
+    const SkScalar borderRadius,
+    ColorScheme color_scheme) const {
   SkRect skrect = gfx::RectToSkRect(rect);
 
   // Use the largest square that fits inside the provided rectangle.
@@ -630,12 +642,14 @@
 void NativeThemeBase::PaintRadio(cc::PaintCanvas* canvas,
                                  State state,
                                  const gfx::Rect& rect,
-                                 const ButtonExtraParams& button) const {
+                                 const ButtonExtraParams& button,
+                                 ColorScheme color_scheme) const {
   // Most of a radio button is the same as a checkbox, except the the rounded
   // square is a circle (i.e. border radius >= 100%).
   const SkScalar radius = SkFloatToScalar(
       static_cast<float>(std::max(rect.width(), rect.height())) / 2);
-  SkRect skrect = PaintCheckboxRadioCommon(canvas, state, rect, radius);
+  SkRect skrect =
+      PaintCheckboxRadioCommon(canvas, state, rect, radius, color_scheme);
   if (!skrect.isEmpty() && button.checked) {
     // Draw the dot.
     cc::PaintFlags flags;
@@ -655,7 +669,8 @@
 void NativeThemeBase::PaintButton(cc::PaintCanvas* canvas,
                                   State state,
                                   const gfx::Rect& rect,
-                                  const ButtonExtraParams& button) const {
+                                  const ButtonExtraParams& button,
+                                  ColorScheme color_scheme) const {
   cc::PaintFlags flags;
   SkRect skrect = gfx::RectToSkRect(rect);
   SkColor base_color = button.background_color;
@@ -695,7 +710,7 @@
     int border_alpha = state == kHovered ? 0x80 : 0x55;
     if (button.is_focused) {
       border_alpha = 0xff;
-      flags.setColor(GetSystemColor(kColorId_FocusedBorderColor));
+      flags.setColor(GetSystemColor(kColorId_FocusedBorderColor, color_scheme));
     }
     flags.setStyle(cc::PaintFlags::kStroke_Style);
     flags.setStrokeWidth(SkIntToScalar(1));
@@ -708,7 +723,8 @@
 void NativeThemeBase::PaintTextField(cc::PaintCanvas* canvas,
                                      State state,
                                      const gfx::Rect& rect,
-                                     const TextFieldExtraParams& text) const {
+                                     const TextFieldExtraParams& text,
+                                     ColorScheme color_scheme) const {
   SkRect bounds;
   bounds.set(rect.x(), rect.y(), rect.right() - 1, rect.bottom() - 1);
 
@@ -725,18 +741,18 @@
   canvas->drawRect(bounds, stroke_flags);
 }
 
-void NativeThemeBase::PaintMenuList(
-    cc::PaintCanvas* canvas,
-    State state,
-    const gfx::Rect& rect,
-    const MenuListExtraParams& menu_list) const {
+void NativeThemeBase::PaintMenuList(cc::PaintCanvas* canvas,
+                                    State state,
+                                    const gfx::Rect& rect,
+                                    const MenuListExtraParams& menu_list,
+                                    ColorScheme color_scheme) const {
   // If a border radius is specified, we let the WebCore paint the background
   // and the border of the control.
   if (!menu_list.has_border_radius) {
     ButtonExtraParams button = { 0 };
     button.background_color = menu_list.background_color;
     button.has_border = menu_list.has_border;
-    PaintButton(canvas, state, rect, button);
+    PaintButton(canvas, state, rect, button, color_scheme);
   }
 
   cc::PaintFlags flags;
@@ -765,7 +781,8 @@
 void NativeThemeBase::PaintMenuPopupBackground(
     cc::PaintCanvas* canvas,
     const gfx::Size& size,
-    const MenuBackgroundExtraParams& menu_background) const {
+    const MenuBackgroundExtraParams& menu_background,
+    ColorScheme color_scheme) const {
   canvas->drawColor(kMenuPopupBackgroundColor, SkBlendMode::kSrc);
 }
 
@@ -773,7 +790,8 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const MenuItemExtraParams& menu_item) const {
+    const MenuItemExtraParams& menu_item,
+    ColorScheme color_scheme) const {
   // By default don't draw anything over the normal background.
 }
 
@@ -781,16 +799,19 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const MenuSeparatorExtraParams& menu_separator) const {
+    const MenuSeparatorExtraParams& menu_separator,
+    ColorScheme color_scheme) const {
   cc::PaintFlags flags;
-  flags.setColor(GetSystemColor(ui::NativeTheme::kColorId_MenuSeparatorColor));
+  flags.setColor(GetSystemColor(ui::NativeTheme::kColorId_MenuSeparatorColor,
+                                color_scheme));
   canvas->drawRect(gfx::RectToSkRect(*menu_separator.paint_rect), flags);
 }
 
 void NativeThemeBase::PaintSliderTrack(cc::PaintCanvas* canvas,
                                        State state,
                                        const gfx::Rect& rect,
-                                       const SliderExtraParams& slider) const {
+                                       const SliderExtraParams& slider,
+                                       ColorScheme color_scheme) const {
   const int kMidX = rect.x() + rect.width() / 2;
   const int kMidY = rect.y() + rect.height() / 2;
 
@@ -815,7 +836,8 @@
 void NativeThemeBase::PaintSliderThumb(cc::PaintCanvas* canvas,
                                        State state,
                                        const gfx::Rect& rect,
-                                       const SliderExtraParams& slider) const {
+                                       const SliderExtraParams& slider,
+                                       ColorScheme color_scheme) const {
   const bool hovered = (state == kHovered) || slider.in_drag;
   const int kMidX = rect.x() + rect.width() / 2;
   const int kMidY = rect.y() + rect.height() / 2;
@@ -854,7 +876,8 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const InnerSpinButtonExtraParams& spin_button) const {
+    const InnerSpinButtonExtraParams& spin_button,
+    ColorScheme color_scheme) const {
   if (spin_button.read_only)
     state = kDisabled;
 
@@ -867,17 +890,19 @@
 
   gfx::Rect half = rect;
   half.set_height(rect.height() / 2);
-  PaintArrowButton(canvas, half, kScrollbarUpArrow, north_state);
+  PaintArrowButton(canvas, half, kScrollbarUpArrow, north_state, color_scheme);
 
   half.set_y(rect.y() + rect.height() / 2);
-  PaintArrowButton(canvas, half, kScrollbarDownArrow, south_state);
+  PaintArrowButton(canvas, half, kScrollbarDownArrow, south_state,
+                   color_scheme);
 }
 
 void NativeThemeBase::PaintProgressBar(
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const ProgressBarExtraParams& progress_bar) const {
+    const ProgressBarExtraParams& progress_bar,
+    ColorScheme color_scheme) const {
   DCHECK(!rect.IsEmpty());
 
   canvas->drawColor(SK_ColorWHITE);
@@ -919,7 +944,8 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const FrameTopAreaExtraParams& frame_top_area) const {
+    const FrameTopAreaExtraParams& frame_top_area,
+    ColorScheme color_scheme) const {
   cc::PaintFlags flags;
   flags.setColor(frame_top_area.default_background_color);
   canvas->drawRect(gfx::RectToSkRect(rect), flags);
@@ -940,7 +966,8 @@
   return SkHSVToColor(color);
 }
 
-SkColor NativeThemeBase::GetArrowColor(State state) const {
+SkColor NativeThemeBase::GetArrowColor(State state,
+                                       ColorScheme color_scheme) const {
   if (state != kDisabled)
     return SK_ColorBLACK;
 
diff --git a/ui/native_theme/native_theme_base.h b/ui/native_theme/native_theme_base.h
index 0e349c5d..e9a292a 100644
--- a/ui/native_theme/native_theme_base.h
+++ b/ui/native_theme/native_theme_base.h
@@ -31,7 +31,8 @@
              Part part,
              State state,
              const gfx::Rect& rect,
-             const ExtraParams& extra) const override;
+             const ExtraParams& extra,
+             ColorScheme color_scheme) const override;
 
   bool SupportsNinePatch(Part part) const override;
   gfx::Size GetNinePatchCanvasSize(Part part) const override;
@@ -45,7 +46,8 @@
   virtual void PaintArrowButton(cc::PaintCanvas* gc,
                                 const gfx::Rect& rect,
                                 Part direction,
-                                State state) const;
+                                State state,
+                                ColorScheme color_scheme) const;
   // Paint the scrollbar track. Done before the thumb so that it can contain
   // alpha.
   virtual void PaintScrollbarTrack(
@@ -53,88 +55,101 @@
       Part part,
       State state,
       const ScrollbarTrackExtraParams& extra_params,
-      const gfx::Rect& rect) const;
+      const gfx::Rect& rect,
+      ColorScheme color_scheme) const;
   // Draw the scrollbar thumb over the track.
   virtual void PaintScrollbarThumb(
       cc::PaintCanvas* canvas,
       Part part,
       State state,
       const gfx::Rect& rect,
-      NativeTheme::ScrollbarOverlayColorTheme theme) const;
+      NativeTheme::ScrollbarOverlayColorTheme theme,
+      ColorScheme color_scheme) const;
 
   virtual void PaintScrollbarCorner(cc::PaintCanvas* canvas,
                                     State state,
-                                    const gfx::Rect& rect) const;
+                                    const gfx::Rect& rect,
+                                    ColorScheme color_scheme) const;
 
   virtual void PaintCheckbox(cc::PaintCanvas* canvas,
                              State state,
                              const gfx::Rect& rect,
-                             const ButtonExtraParams& button) const;
+                             const ButtonExtraParams& button,
+                             ColorScheme color_scheme) const;
 
   virtual void PaintRadio(cc::PaintCanvas* canvas,
                           State state,
                           const gfx::Rect& rect,
-                          const ButtonExtraParams& button) const;
+                          const ButtonExtraParams& button,
+                          ColorScheme color_scheme) const;
 
   virtual void PaintButton(cc::PaintCanvas* canvas,
                            State state,
                            const gfx::Rect& rect,
-                           const ButtonExtraParams& button) const;
+                           const ButtonExtraParams& button,
+                           ColorScheme color_scheme) const;
 
   virtual void PaintTextField(cc::PaintCanvas* canvas,
                               State state,
                               const gfx::Rect& rect,
-                              const TextFieldExtraParams& text) const;
+                              const TextFieldExtraParams& text,
+                              ColorScheme color_scheme) const;
 
   virtual void PaintMenuList(cc::PaintCanvas* canvas,
                              State state,
                              const gfx::Rect& rect,
-                             const MenuListExtraParams& menu_list) const;
+                             const MenuListExtraParams& menu_list,
+                             ColorScheme color_scheme) const;
 
   virtual void PaintMenuPopupBackground(
       cc::PaintCanvas* canvas,
       const gfx::Size& size,
-      const MenuBackgroundExtraParams& menu_background) const;
+      const MenuBackgroundExtraParams& menu_background,
+      ColorScheme color_scheme) const;
 
-  virtual void PaintMenuItemBackground(
-      cc::PaintCanvas* canvas,
-      State state,
-      const gfx::Rect& rect,
-      const MenuItemExtraParams& menu_item) const;
+  virtual void PaintMenuItemBackground(cc::PaintCanvas* canvas,
+                                       State state,
+                                       const gfx::Rect& rect,
+                                       const MenuItemExtraParams& menu_item,
+                                       ColorScheme color_scheme) const;
 
   virtual void PaintMenuSeparator(
       cc::PaintCanvas* canvas,
       State state,
       const gfx::Rect& rect,
-      const MenuSeparatorExtraParams& menu_separator) const;
+      const MenuSeparatorExtraParams& menu_separator,
+      ColorScheme color_scheme) const;
 
   virtual void PaintSliderTrack(cc::PaintCanvas* canvas,
                                 State state,
                                 const gfx::Rect& rect,
-                                const SliderExtraParams& slider) const;
+                                const SliderExtraParams& slider,
+                                ColorScheme color_scheme) const;
 
   virtual void PaintSliderThumb(cc::PaintCanvas* canvas,
                                 State state,
                                 const gfx::Rect& rect,
-                                const SliderExtraParams& slider) const;
+                                const SliderExtraParams& slider,
+                                ColorScheme color_scheme) const;
 
   virtual void PaintInnerSpinButton(
       cc::PaintCanvas* canvas,
       State state,
       const gfx::Rect& rect,
-      const InnerSpinButtonExtraParams& spin_button) const;
+      const InnerSpinButtonExtraParams& spin_button,
+      ColorScheme color_scheme) const;
 
-  virtual void PaintProgressBar(
-      cc::PaintCanvas* canvas,
-      State state,
-      const gfx::Rect& rect,
-      const ProgressBarExtraParams& progress_bar) const;
+  virtual void PaintProgressBar(cc::PaintCanvas* canvas,
+                                State state,
+                                const gfx::Rect& rect,
+                                const ProgressBarExtraParams& progress_bar,
+                                ColorScheme color_scheme) const;
 
-  virtual void PaintFrameTopArea(
-      cc::PaintCanvas* canvas,
-      State state,
-      const gfx::Rect& rect,
-      const FrameTopAreaExtraParams& frame_top_area) const;
+  virtual void PaintFrameTopArea(cc::PaintCanvas* canvas,
+                                 State state,
+                                 const gfx::Rect& rect,
+                                 const FrameTopAreaExtraParams& frame_top_area,
+                                 ColorScheme color_scheme) const;
 
   // Shrinks checkbox/radio button rect, if necessary, to make room for padding
   // and drop shadow.
@@ -159,7 +174,7 @@
                   SkColor color) const;
 
   // Returns the color used to draw the arrow.
-  SkColor GetArrowColor(State state) const;
+  SkColor GetArrowColor(State state, ColorScheme color_scheme) const;
 
   int scrollbar_width_;
 
@@ -192,7 +207,8 @@
   SkRect PaintCheckboxRadioCommon(cc::PaintCanvas* canvas,
                                   State state,
                                   const gfx::Rect& rect,
-                                  const SkScalar borderRadius) const;
+                                  const SkScalar borderRadius,
+                                  ColorScheme color_scheme) const;
 
   // The length of the arrow buttons, 0 means no buttons are drawn.
   int scrollbar_button_length_;
diff --git a/ui/native_theme/native_theme_dark_aura.cc b/ui/native_theme/native_theme_dark_aura.cc
index 609320c7..5b81ed9ac 100644
--- a/ui/native_theme/native_theme_dark_aura.cc
+++ b/ui/native_theme/native_theme_dark_aura.cc
@@ -14,8 +14,9 @@
   return s_native_theme.get();
 }
 
-SkColor NativeThemeDarkAura::GetSystemColor(ColorId color_id) const {
-  return GetAuraColor(color_id, this);
+SkColor NativeThemeDarkAura::GetSystemColor(ColorId color_id,
+                                            ColorScheme color_scheme) const {
+  return GetAuraColor(color_id, this, color_scheme);
 }
 
 bool NativeThemeDarkAura::SystemDarkModeEnabled() const {
diff --git a/ui/native_theme/native_theme_dark_aura.h b/ui/native_theme/native_theme_dark_aura.h
index 40a3024b..afa54669 100644
--- a/ui/native_theme/native_theme_dark_aura.h
+++ b/ui/native_theme/native_theme_dark_aura.h
@@ -18,7 +18,8 @@
   static NativeThemeDarkAura* instance();
 
   // NativeThemeAura:
-  SkColor GetSystemColor(ColorId color_id) const override;
+  SkColor GetSystemColor(ColorId color_id,
+                         ColorScheme color_scheme) const override;
   bool SystemDarkModeEnabled() const override;
   PreferredColorScheme GetPreferredColorScheme() const override;
 
diff --git a/ui/native_theme/native_theme_mac.h b/ui/native_theme/native_theme_mac.h
index 817bb7c..608db43 100644
--- a/ui/native_theme/native_theme_mac.h
+++ b/ui/native_theme/native_theme_mac.h
@@ -37,18 +37,20 @@
   static SkColor ApplySystemControlTint(SkColor color);
 
   // Overridden from NativeTheme:
-  SkColor GetSystemColor(ColorId color_id) const override;
+  SkColor GetSystemColor(ColorId color_id,
+                         ColorScheme color_scheme) const override;
 
   // Overridden from NativeThemeBase:
   void PaintMenuPopupBackground(
       cc::PaintCanvas* canvas,
       const gfx::Size& size,
-      const MenuBackgroundExtraParams& menu_background) const override;
-  void PaintMenuItemBackground(
-      cc::PaintCanvas* canvas,
-      State state,
-      const gfx::Rect& rect,
-      const MenuItemExtraParams& menu_item) const override;
+      const MenuBackgroundExtraParams& menu_background,
+      ColorScheme color_scheme) const override;
+  void PaintMenuItemBackground(cc::PaintCanvas* canvas,
+                               State state,
+                               const gfx::Rect& rect,
+                               const MenuItemExtraParams& menu_item,
+                               ColorScheme color_scheme) const override;
   bool SystemDarkModeSupported() const override;
 
   // Paints the styled button shape used for default controls on Mac. The basic
@@ -74,7 +76,8 @@
   // Paint the selected menu item background, and a border for emphasis when in
   // high contrast.
   void PaintSelectedMenuItem(cc::PaintCanvas* canvas,
-                             const gfx::Rect& rect) const;
+                             const gfx::Rect& rect,
+                             ColorScheme color_scheme) const;
 
   void InitializeDarkModeStateAndObserver();
 
diff --git a/ui/native_theme/native_theme_mac.mm b/ui/native_theme/native_theme_mac.mm
index 8a5635a..6591ccb 100644
--- a/ui/native_theme/native_theme_mac.mm
+++ b/ui/native_theme/native_theme_mac.mm
@@ -176,7 +176,11 @@
   return color;
 }
 
-SkColor NativeThemeMac::GetSystemColor(ColorId color_id) const {
+SkColor NativeThemeMac::GetSystemColor(ColorId color_id,
+                                       ColorScheme color_scheme) const {
+  if (color_scheme == ColorScheme::kDefault)
+    color_scheme = GetSystemColorScheme();
+
   // Empirically, currentAppearance is incorrect when switching
   // appearances. It's unclear exactly why right now, so work
   // around it for the time being by resynchronizing.
@@ -190,9 +194,11 @@
   if (UsesHighContrastColors()) {
     switch (color_id) {
       case kColorId_SelectedMenuItemForegroundColor:
-        return SystemDarkModeEnabled() ? SK_ColorBLACK : SK_ColorWHITE;
+        return color_scheme == ColorScheme::kDark ? SK_ColorBLACK
+                                                  : SK_ColorWHITE;
       case kColorId_FocusedMenuItemBackgroundColor:
-        return SystemDarkModeEnabled() ? SK_ColorLTGRAY : SK_ColorDKGRAY;
+        return color_scheme == ColorScheme::kDark ? SK_ColorLTGRAY
+                                                  : SK_ColorDKGRAY;
       default:
         break;
     }
@@ -205,8 +211,9 @@
     case kColorId_DisabledMenuItemForegroundColor:
       return NSSystemColorToSkColor([NSColor disabledControlTextColor]);
     case kColorId_MenuSeparatorColor:
-      return SystemDarkModeEnabled() ? SkColorSetA(gfx::kGoogleGrey800, 0xCC)
-                                     : SkColorSetA(SK_ColorBLACK, 0x26);
+      return color_scheme == ColorScheme::kDark
+                 ? SkColorSetA(gfx::kGoogleGrey800, 0xCC)
+                 : SkColorSetA(SK_ColorBLACK, 0x26);
     case kColorId_MenuBorderColor:
       return SkColorSetA(SK_ColorBLACK, 0x60);
 
@@ -232,16 +239,17 @@
       break;
   }
 
-  return ApplySystemControlTint(GetAuraColor(color_id, this));
+  return ApplySystemControlTint(GetAuraColor(color_id, this, color_scheme));
 }
 
 void NativeThemeMac::PaintMenuPopupBackground(
     cc::PaintCanvas* canvas,
     const gfx::Size& size,
-    const MenuBackgroundExtraParams& menu_background) const {
+    const MenuBackgroundExtraParams& menu_background,
+    ColorScheme color_scheme) const {
   cc::PaintFlags flags;
   flags.setAntiAlias(true);
-  flags.setColor(GetSystemColor(kColorId_MenuBackgroundColor));
+  flags.setColor(GetSystemColor(kColorId_MenuBackgroundColor, color_scheme));
   const SkScalar radius = SkIntToScalar(menu_background.corner_radius);
   SkRect rect = gfx::RectToSkRect(gfx::Rect(size));
   canvas->drawRoundRect(rect, radius, radius, flags);
@@ -251,14 +259,15 @@
     cc::PaintCanvas* canvas,
     State state,
     const gfx::Rect& rect,
-    const MenuItemExtraParams& menu_item) const {
+    const MenuItemExtraParams& menu_item,
+    ColorScheme color_scheme) const {
   switch (state) {
     case NativeTheme::kNormal:
     case NativeTheme::kDisabled:
       // Draw nothing over the regular background.
       break;
     case NativeTheme::kHovered:
-      PaintSelectedMenuItem(canvas, rect);
+      PaintSelectedMenuItem(canvas, rect, color_scheme);
       break;
     default:
       NOTREACHED();
@@ -298,10 +307,12 @@
 }
 
 void NativeThemeMac::PaintSelectedMenuItem(cc::PaintCanvas* canvas,
-                                           const gfx::Rect& rect) const {
+                                           const gfx::Rect& rect,
+                                           ColorScheme color_scheme) const {
   // Draw the background.
   cc::PaintFlags flags;
-  flags.setColor(GetSystemColor(kColorId_FocusedMenuItemBackgroundColor));
+  flags.setColor(
+      GetSystemColor(kColorId_FocusedMenuItemBackgroundColor, color_scheme));
   canvas->drawRect(gfx::RectToSkRect(rect), flags);
 }
 
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index c6a0c1b9..7f662b0 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -206,23 +206,24 @@
                            Part part,
                            State state,
                            const gfx::Rect& rect,
-                           const ExtraParams& extra) const {
+                           const ExtraParams& extra,
+                           ColorScheme color_scheme) const {
   if (rect.IsEmpty())
     return;
 
   switch (part) {
     case kMenuPopupGutter:
-      PaintMenuGutter(canvas, rect);
+      PaintMenuGutter(canvas, rect, color_scheme);
       return;
     case kMenuPopupSeparator:
-      PaintMenuSeparator(canvas, extra.menu_separator);
+      PaintMenuSeparator(canvas, extra.menu_separator, color_scheme);
       return;
     case kMenuPopupBackground:
-      PaintMenuBackground(canvas, rect);
+      PaintMenuBackground(canvas, rect, color_scheme);
       return;
     case kMenuItemBackground:
       CommonThemePaintMenuItemBackground(this, canvas, state, rect,
-                                         extra.menu_item);
+                                         extra.menu_item, color_scheme);
       return;
     default:
       PaintIndirect(canvas, part, state, rect, extra);
@@ -332,9 +333,9 @@
     system_colors_[kSystemColor] = color_utils::GetSysSkColor(kSystemColor);
 }
 
-void NativeThemeWin::PaintMenuSeparator(
-    cc::PaintCanvas* canvas,
-    const MenuSeparatorExtraParams& params) const {
+void NativeThemeWin::PaintMenuSeparator(cc::PaintCanvas* canvas,
+                                        const MenuSeparatorExtraParams& params,
+                                        ColorScheme color_scheme) const {
   const gfx::RectF rect(*params.paint_rect);
   gfx::PointF start = rect.CenterPoint();
   gfx::PointF end = start;
@@ -347,22 +348,27 @@
   }
 
   cc::PaintFlags flags;
-  flags.setColor(GetSystemColor(NativeTheme::kColorId_MenuSeparatorColor));
+  flags.setColor(
+      GetSystemColor(NativeTheme::kColorId_MenuSeparatorColor, color_scheme));
   canvas->drawLine(start.x(), start.y(), end.x(), end.y(), flags);
 }
 
 void NativeThemeWin::PaintMenuGutter(cc::PaintCanvas* canvas,
-                                     const gfx::Rect& rect) const {
+                                     const gfx::Rect& rect,
+                                     ColorScheme color_scheme) const {
   cc::PaintFlags flags;
-  flags.setColor(GetSystemColor(NativeTheme::kColorId_MenuSeparatorColor));
+  flags.setColor(
+      GetSystemColor(NativeTheme::kColorId_MenuSeparatorColor, color_scheme));
   int position_x = rect.x() + rect.width() / 2;
   canvas->drawLine(position_x, rect.y(), position_x, rect.bottom(), flags);
 }
 
 void NativeThemeWin::PaintMenuBackground(cc::PaintCanvas* canvas,
-                                         const gfx::Rect& rect) const {
+                                         const gfx::Rect& rect,
+                                         ColorScheme color_scheme) const {
   cc::PaintFlags flags;
-  flags.setColor(GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor));
+  flags.setColor(
+      GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor, color_scheme));
   canvas->drawRect(gfx::RectToSkRect(rect), flags);
 }
 
@@ -444,14 +450,18 @@
   }
 }
 
-SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const {
+SkColor NativeThemeWin::GetSystemColor(ColorId color_id,
+                                       ColorScheme color_scheme) const {
+  if (color_scheme == ColorScheme::kDefault)
+    color_scheme = GetSystemColorScheme();
+
   // Win32 system colors currently don't support Dark Mode. As a result,
   // fallback on the Aura colors. Inverted color schemes can be ignored here
   // as it's only true when Chrome is running on a high-contrast AND when the
   // relative luminance of COLOR_WINDOWTEXT is greater than COLOR_WINDOW (e.g.
   // white on black), which is basically like dark mode.
-  if (SystemDarkModeEnabled())
-    return GetAuraColor(color_id, this);
+  if (color_scheme == ColorScheme::kDark)
+    return GetAuraColor(color_id, this, color_scheme);
 
   // TODO: Obtain the correct colors for these using GetSysColor.
   // Button:
@@ -559,11 +569,12 @@
       case NativeTheme::kColorId_ProminentButtonColor:
         return kProminentButtonColorInvert;
       default:
-        return color_utils::InvertColor(GetAuraColor(color_id, this));
+        return color_utils::InvertColor(
+            GetAuraColor(color_id, this, color_scheme));
     }
   }
 
-  return GetAuraColor(color_id, this);
+  return GetAuraColor(color_id, this, color_scheme);
 }
 
 bool NativeThemeWin::SupportsNinePatch(Part part) const {
diff --git a/ui/native_theme/native_theme_win.h b/ui/native_theme/native_theme_win.h
index 03be75f..8019839 100644
--- a/ui/native_theme/native_theme_win.h
+++ b/ui/native_theme/native_theme_win.h
@@ -75,8 +75,10 @@
              Part part,
              State state,
              const gfx::Rect& rect,
-             const ExtraParams& extra) const override;
-  SkColor GetSystemColor(ColorId color_id) const override;
+             const ExtraParams& extra,
+             ColorScheme color_scheme) const override;
+  SkColor GetSystemColor(ColorId color_id,
+                         ColorScheme color_scheme) const override;
   bool SupportsNinePatch(Part part) const override;
   gfx::Size GetNinePatchCanvasSize(Part part) const override;
   gfx::Rect GetNinePatchAperture(Part part) const override;
@@ -107,10 +109,14 @@
 
   // Painting functions that paint to PaintCanvas.
   void PaintMenuSeparator(cc::PaintCanvas* canvas,
-                          const MenuSeparatorExtraParams& params) const;
-  void PaintMenuGutter(cc::PaintCanvas* canvas, const gfx::Rect& rect) const;
+                          const MenuSeparatorExtraParams& params,
+                          ColorScheme color_scheme) const;
+  void PaintMenuGutter(cc::PaintCanvas* canvas,
+                       const gfx::Rect& rect,
+                       ColorScheme color_scheme) const;
   void PaintMenuBackground(cc::PaintCanvas* canvas,
-                           const gfx::Rect& rect) const;
+                           const gfx::Rect& rect,
+                           ColorScheme color_scheme) const;
 
   // Paint directly to canvas' HDC.
   void PaintDirect(SkCanvas* destination_canvas,
diff --git a/ui/native_theme/test_native_theme.cc b/ui/native_theme/test_native_theme.cc
index 02db265..863e142 100644
--- a/ui/native_theme/test_native_theme.cc
+++ b/ui/native_theme/test_native_theme.cc
@@ -9,7 +9,8 @@
 TestNativeTheme::TestNativeTheme() {}
 TestNativeTheme::~TestNativeTheme() {}
 
-SkColor TestNativeTheme::GetSystemColor(ColorId color_id) const {
+SkColor TestNativeTheme::GetSystemColor(ColorId color_id,
+                                        ColorScheme color_scheme) const {
   return SK_ColorRED;
 }
 
@@ -23,7 +24,8 @@
                             Part part,
                             State state,
                             const gfx::Rect& rect,
-                            const ExtraParams& extra) const {}
+                            const ExtraParams& extra,
+                            ColorScheme color_scheme) const {}
 
 bool TestNativeTheme::SupportsNinePatch(Part part) const {
   return false;
diff --git a/ui/native_theme/test_native_theme.h b/ui/native_theme/test_native_theme.h
index f10dd89..2c0f9ab 100644
--- a/ui/native_theme/test_native_theme.h
+++ b/ui/native_theme/test_native_theme.h
@@ -16,7 +16,8 @@
   ~TestNativeTheme() override;
 
   // NativeTheme:
-  SkColor GetSystemColor(ColorId color_id) const override;
+  SkColor GetSystemColor(ColorId color_id,
+                         ColorScheme color_scheme) const override;
   gfx::Size GetPartSize(Part part,
                         State state,
                         const ExtraParams& extra) const override;
@@ -24,7 +25,8 @@
              Part part,
              State state,
              const gfx::Rect& rect,
-             const ExtraParams& extra) const override;
+             const ExtraParams& extra,
+             ColorScheme color_scheme) const override;
   bool SupportsNinePatch(Part part) const override;
   gfx::Size GetNinePatchCanvasSize(Part part) const override;
   gfx::Rect GetNinePatchAperture(Part part) const override;
diff --git a/ui/views/controls/button/label_button_label_unittest.cc b/ui/views/controls/button/label_button_label_unittest.cc
index a1254e2c..584b53ac7 100644
--- a/ui/views/controls/button/label_button_label_unittest.cc
+++ b/ui/views/controls/button/label_button_label_unittest.cc
@@ -21,7 +21,8 @@
   void Set(ColorId id, SkColor color) { colors_[id] = color; }
 
   // NativeThemeBase:
-  SkColor GetSystemColor(ColorId color_id) const override {
+  SkColor GetSystemColor(ColorId color_id,
+                         ColorScheme color_scheme) const override {
     return colors_.count(color_id) ? colors_.find(color_id)->second
                                    : SK_ColorMAGENTA;
   }
diff --git a/ui/webui/webui_features.gni b/ui/webui/webui_features.gni
index c20d7c3..e92d2b8 100644
--- a/ui/webui/webui_features.gni
+++ b/ui/webui/webui_features.gni
@@ -12,4 +12,7 @@
   # enables the webui_closure_compile target which does a no-op without this
   # flag enabled. Requires Java.
   closure_compile = is_chromeos || is_linux || is_android
+
+  # Enable the WebUI version of the browser's tab strip.
+  enable_webui_tab_strip = is_chromeos
 }