diff --git a/DEPS b/DEPS
index 3bbf2c1..21119cc 100644
--- a/DEPS
+++ b/DEPS
@@ -175,11 +175,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': '0999bce974ac9f85f3e579b8f8e63eeddbea1a1a',
+  'skia_revision': 'ecd17b9e34516aad4f4e6967efc5c2398503406c',
   # 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': '203b5f85263b3862b258ecf78a5fdee9565f6f28',
+  'v8_revision': '703b9d4881faf3dd412fafbe339a27fcccaacdcc',
   # 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.
@@ -187,15 +187,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': 'e4da6f1598e3486cb2c88e0d653ddf09554f3ec7',
+  'angle_revision': 'a156df23585a92dc813cc88480f1a195467c9d81',
   # 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': 'dc23b088cf8e8a37bfc617579b8ae5f21896f715',
+  'swiftshader_revision': 'ba0c95eb406fb2c36cb2d1515765f4de82cbed9b',
   # 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': '55cc5f2199b1f074c36019a7dd7e70223994eb30',
+  'pdfium_revision': 'afc869eaff5badd31f06eedb5cbd5f269e8db6bb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -238,7 +238,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'bc1001ace1ff6b701688b30823a079e07a164a1d',
+  'catapult_revision': '910f6c87ac65a90489987644607cb011c2efc0a9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -302,7 +302,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '2d10e954cec2a605345e0971c4cf7fc046a27ca8',
+  'dawn_revision': '73ea1f11068a3b85c7cd7cd12b856a681df4ce31',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -323,6 +323,10 @@
   # the commit queue can handle CLs rolling libgifcodec
   # and whatever else without interference from each other.
   'libgifcodec_revision': 'd06d2a6d42baf6c0c91cacc28df2542a911d05fe',
+  # Three lines of non-changing comments so that
+  # the commit queue can handle CLs rolling libavif
+  # and whatever else without interference from each other.
+  'libavif_revision': '78e3c9d2fbfa935638145d017dda6950cc559ad3',
 
   # TODO(crbug.com/941824): The values below need to be kept in sync
   # between //DEPS and //buildtools/DEPS, so if you're updating one,
@@ -877,7 +881,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '3863fc52b9e5fd5c40624e718572d113183a4df6',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c440b23d505b810a49f3ee9ae55693f30b78c30e',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1084,6 +1088,9 @@
   'src/third_party/libaom/source/libaom':
     Var('aomedia_git') + '/aom.git' + '@' +  'c25910f6d213ec5ec45ae53caa5e40bd7ebd218f',
 
+  'src/third_party/libavif/src':
+    Var('chromium_git') + '/external/github.com/AOMediaCodec/libavif.git' + '@' + Var('libavif_revision'),
+
   # Userspace interface to kernel DRM services.
   'src/third_party/libdrm/src': {
       'url': Var('chromium_git') + '/chromiumos/third_party/libdrm.git' + '@' + '0190f49a139e7069d7cad6a6890832831da1aa8b',
@@ -1128,7 +1135,7 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '1717ac939c12e31a358056a36c2fa7a8882e71ed',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '8dc6f353c6d04329cf59529f41a6f46d9dbfcafa',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + '51ca718c3adf0ddedacd7df25fe45f67dc5a9ce1',
@@ -1211,7 +1218,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '6f26bce0b1c4e8ce0e13332f7c0083788def5fdf',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + '9508a74c93b37b13e17c70749883c6790212814b',
+    Var('chromium_git') + '/openscreen' + '@' + '851d4192af51a242f887db5d56138f66bab46137',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '9e97b73e7dd2bfc07745489d728f6a36665c648f',
@@ -1228,7 +1235,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '97d7d4772df77bf2721c7c0fe31805902c29c80f',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4c8ff7ce1c1a4609c994c8a0169e43e22682d5e4',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1458,7 +1465,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '80e5216a11cfdf9e66c352e6cf4f18b2b3d75137',
+    Var('webrtc_git') + '/src.git' + '@' + '43126bb4231c8768825b6710237a52ac06315735',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1533,7 +1540,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@09fdff26a543a871f96102d1220d8547b7d548aa',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5ad624673601376973f44ab125bcf5c509a2bee3',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index f8ad895..b024f1c 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -62,5 +62,7 @@
                     "WebViewBrotliSupport", "Enables brotli compression support in WebView."),
             Flag.baseFeature("SafeBrowsingCommittedInterstitials",
                     "Commits Safe Browsing warning pages like page navigations."),
+            Flag.baseFeature(
+                    "AppCache", "Controls AppCache to facilitate testing against future removal."),
     };
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PlatformMediaCodecTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PlatformMediaCodecTest.java
deleted file mode 100644
index 3e8a30c..0000000
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PlatformMediaCodecTest.java
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.android_webview.test;
-
-import android.support.test.filters.MediumTest;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.test.util.DisabledTest;
-import org.chromium.base.test.util.Feature;
-import org.chromium.content_public.browser.WebContents;
-import org.chromium.content_public.browser.test.util.DOMUtils;
-import org.chromium.content_public.browser.test.util.TestThreadUtils;
-
-/**
- * Test that a page with a non-Chrome media codec can playback correctly; this
- * test is *NOT* exhaustive, but merely spot checks a single instance.
- */
-@RunWith(AwJUnit4ClassRunner.class)
-public class PlatformMediaCodecTest {
-    @Rule
-    public AwActivityTestRule mActivityTestRule = new AwActivityTestRule();
-
-    private TestAwContentsClient mContentsClient;
-    private AwTestContainerView mTestContainerView;
-    private WebContents mWebContents;
-
-    @Before
-    public void setUp() {
-        mContentsClient = new TestAwContentsClient();
-        mTestContainerView = mActivityTestRule.createAwTestContainerViewOnMainSync(mContentsClient);
-        mWebContents = mTestContainerView.getWebContents();
-        AwActivityTestRule.enableJavaScriptOnUiThread(mTestContainerView.getAwContents());
-    }
-
-    @Test
-    @MediumTest
-    @Feature({"AndroidWebView"})
-    @DisabledTest(message = "crbug.com/620890")
-    public void testCanPlayPlatformMediaCodecs() throws Throwable {
-        mActivityTestRule.loadUrlSync(mTestContainerView.getAwContents(),
-                mContentsClient.getOnPageFinishedHelper(),
-                "file:///android_asset/platform-media-codec-test.html");
-        DOMUtils.clickNode(mWebContents, "playButton");
-        DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), "videoTag");
-    }
-
-    private WebContents getWebContentsOnUiThread() {
-        try {
-            return TestThreadUtils.runOnUiThreadBlocking(() -> mWebContents);
-        } catch (Exception e) {
-            Assert.fail(e.getMessage());
-            return null;
-        }
-    }
-}
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 8051351..4fcbc18 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -119,10 +119,8 @@
     "shell/assets/full_screen_video_test.html",
     "shell/assets/full_screen_video_test_not_preloaded.html",
     "shell/assets/key-system-test.html",
-    "shell/assets/platform-media-codec-test.html",
     "shell/assets/star.svg",
     "shell/assets/star.svgz",
-    "shell/assets/video.3gp",
     "shell/assets/video.webm",
     "shell/assets/visual_state_during_fullscreen_test.html",
     "shell/assets/visual_state_on_page_commit_visible_test.html",
@@ -264,7 +262,6 @@
     "../javatests/src/org/chromium/android_webview/test/MemoryMetricsLoggerTest.java",
     "../javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java",
     "../javatests/src/org/chromium/android_webview/test/OnDiskFileTest.java",
-    "../javatests/src/org/chromium/android_webview/test/PlatformMediaCodecTest.java",
     "../javatests/src/org/chromium/android_webview/test/PolicyUrlFilteringTest.java",
     "../javatests/src/org/chromium/android_webview/test/PopupWindowTest.java",
     "../javatests/src/org/chromium/android_webview/test/PostMessageTest.java",
diff --git a/android_webview/test/shell/assets/platform-media-codec-test.html b/android_webview/test/shell/assets/platform-media-codec-test.html
deleted file mode 100644
index c97d16f1..0000000
--- a/android_webview/test/shell/assets/platform-media-codec-test.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<!DOCTYPE html>
-<video id="videoTag" src="file:///android_asset/video.3gp" controls></video>
-<br/>
-<button id="playButton" onclick="document.querySelector('video').play();">Play Video</button>
diff --git a/android_webview/test/shell/assets/video.3gp b/android_webview/test/shell/assets/video.3gp
deleted file mode 100644
index 07b66d5..0000000
--- a/android_webview/test/shell/assets/video.3gp
+++ /dev/null
Binary files differ
diff --git a/ash/ambient/ambient_controller.cc b/ash/ambient/ambient_controller.cc
index 2ea6d71..c8a58f1 100644
--- a/ash/ambient/ambient_controller.cc
+++ b/ash/ambient/ambient_controller.cc
@@ -11,7 +11,6 @@
 #include "ash/ambient/ui/ambient_container_view.h"
 #include "ash/ambient/util/ambient_util.h"
 #include "ash/assistant/assistant_controller.h"
-#include "ash/assistant/util/animation_util.h"
 #include "ash/login/ui/lock_screen.h"
 #include "ash/public/cpp/ambient/ambient_mode_state.h"
 #include "ash/public/cpp/ambient/ambient_prefs.h"
@@ -94,17 +93,20 @@
 }
 
 void AmbientController::OnLockStateChanged(bool locked) {
-  if (locked) {
-    // Show ambient mode when entering lock screen.
+  if (!locked) {
+    // We should already exit ambient mode at this time, as the ambient
+    // container needs to be closed to uncover the login port for
+    // re-authentication.
     DCHECK(!container_view_);
-    Show();
-  } else {
-    // Destroy ambient mode after user re-login.
-    Destroy();
+    return;
   }
+
+  // Show the ambient container on top of the lock screen.
+  DCHECK(!container_view_);
+  Start();
 }
 
-void AmbientController::Show() {
+void AmbientController::Start() {
   if (!CanStartAmbientMode()) {
     // TODO(wutao): Show a toast to indicate that Ambient mode is not ready.
     return;
@@ -119,34 +121,14 @@
   ambient_state_.SetAmbientModeEnabled(true);
 }
 
-void AmbientController::Destroy() {
+void AmbientController::Stop() {
   ambient_state_.SetAmbientModeEnabled(false);
 }
-
 void AmbientController::Toggle() {
   if (container_view_)
-    Destroy();
+    Stop();
   else
-    Show();
-}
-
-void AmbientController::OnBackgroundPhotoEvents() {
-  refresh_timer_.Stop();
-
-  // Move the |AmbientModeContainer| beneath the |LockScreenWidget| to show the
-  // lock screen contents on top before the fade-out animation.
-  auto* ambient_window = container_view_->GetWidget()->GetNativeWindow();
-  ambient_window->parent()->StackChildAtBottom(ambient_window);
-
-  // Start fading out the current background photo.
-  StartFadeOutAnimation();
-}
-
-void AmbientController::StartFadeOutAnimation() {
-  // We fade out the |PhotoView| on its own layer instead of using the general
-  // layer of the widget, otherwise it will reveal the color of the lockscreen
-  // wallpaper beneath.
-  container_view_->FadeOutPhotoView();
+    Start();
 }
 
 void AmbientController::CreateContainerView() {
@@ -164,6 +146,9 @@
 }
 
 void AmbientController::RefreshImage() {
+  if (!PhotoController::Get())
+    return;
+
   if (photo_model_.ShouldFetchImmediately()) {
     // TODO(b/140032139): Defer downloading image if it is animating.
     base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
diff --git a/ash/ambient/ambient_controller.h b/ash/ambient/ambient_controller.h
index 9a2030d..43af2ffb 100644
--- a/ash/ambient/ambient_controller.h
+++ b/ash/ambient/ambient_controller.h
@@ -45,21 +45,12 @@
   // SessionObserver:
   void OnLockStateChanged(bool locked) override;
 
-  // Creates and displays the ambient mode screen on top of the lock screen.
-  void Show();
-  // Destroys the ambient mode screen widget.
-  void Destroy();
-  // Toggle between show and destroy the ambient mode screen.
-  // Should be removed once we delete the shortcut entry point.
+  void Start();
+  void Stop();
   void Toggle();
 
   PhotoModel* photo_model() { return &photo_model_; }
 
-  // Handles user interactions on the background photo. For now the behavior
-  // is showing lock screen contents (login pod and media control view) on top
-  // while fading-out the current shown image.
-  void OnBackgroundPhotoEvents();
-
   AmbientContainerView* get_container_view_for_testing() {
     return container_view_;
   }
@@ -78,8 +69,6 @@
   void GetNextImage();
   void OnPhotoDownloaded(bool success, const gfx::ImageSkia& image);
 
-  void StartFadeOutAnimation();
-
   AmbientViewDelegateImpl delegate_{this};
   AmbientContainerView* container_view_ = nullptr;   // Owned by view hierarchy.
   PhotoModel photo_model_;
diff --git a/ash/ambient/ambient_view_delegate_impl.cc b/ash/ambient/ambient_view_delegate_impl.cc
index 4049c23..863107a 100644
--- a/ash/ambient/ambient_view_delegate_impl.cc
+++ b/ash/ambient/ambient_view_delegate_impl.cc
@@ -21,7 +21,18 @@
 }
 
 void AmbientViewDelegateImpl::OnBackgroundPhotoEvents() {
-  ambient_controller_->OnBackgroundPhotoEvents();
+  // Exit ambient mode by closing the widget when user interacts with the
+  // background photo using mouse or gestures. We do this asynchronously to
+  // ensure that for a mouse moved event, the widget will be destroyed *after*
+  // its cursor has been updated in |RootView::OnMouseMoved|.
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](const base::WeakPtr<AmbientViewDelegateImpl>& weak_ptr) {
+            if (weak_ptr)
+              weak_ptr->ambient_controller_->Stop();
+          },
+          weak_factory_.GetWeakPtr()));
 }
 
 }  // namespace ash
diff --git a/ash/ambient/ui/ambient_container_view.cc b/ash/ambient/ui/ambient_container_view.cc
index 4f1d4a75..3027243 100644
--- a/ash/ambient/ui/ambient_container_view.cc
+++ b/ash/ambient/ui/ambient_container_view.cc
@@ -12,7 +12,6 @@
 #include "ash/ambient/ui/photo_view.h"
 #include "ash/ambient/util/ambient_util.h"
 #include "ash/assistant/assistant_controller.h"
-#include "ash/assistant/util/animation_util.h"
 #include "ash/login/ui/lock_screen.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
@@ -28,12 +27,6 @@
 // Ambient Assistant container view appearance.
 constexpr int kAmbientAssistantContainerViewPreferredHeightDip = 128;
 
-// TODO(meilinw): temporary values for dev purpose, need to be updated with the
-// final spec.
-constexpr float kBackgroundPhotoOpacity = 0.5f;
-constexpr base::TimeDelta kBackgroundPhotoFadeOutAnimationDuration =
-    base::TimeDelta::FromMilliseconds(500);
-
 aura::Window* GetContainer() {
   aura::Window* container = nullptr;
   if (ambient::util::IsShowing(LockScreen::ScreenType::kLock))
@@ -48,7 +41,7 @@
   params.parent = GetContainer();
   params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
   params.delegate = view;
-  params.name = "AmbientModeContainer";
+  params.name = view->GetClassName();
 
   views::Widget* widget = new views::Widget;
   widget->Init(std::move(params));
@@ -83,16 +76,6 @@
                 kAmbientAssistantContainerViewPreferredHeightDip));
 }
 
-void AmbientContainerView::FadeOutPhotoView() {
-  DCHECK(photo_view_);
-
-  photo_view_->layer()->GetAnimator()->StartAnimation(
-      assistant::util::CreateLayerAnimationSequence(
-          assistant::util::CreateOpacityElement(
-              kBackgroundPhotoOpacity,
-              kBackgroundPhotoFadeOutAnimationDuration)));
-}
-
 void AmbientContainerView::Init() {
   CreateWidget(this);
   // TODO(b/139954108): Choose a better dark mode theme color.
diff --git a/ash/ambient/ui/ambient_container_view.h b/ash/ambient/ui/ambient_container_view.h
index 4dba381088..be5308c 100644
--- a/ash/ambient/ui/ambient_container_view.h
+++ b/ash/ambient/ui/ambient_container_view.h
@@ -26,9 +26,6 @@
   gfx::Size CalculatePreferredSize() const override;
   void Layout() override;
 
-  // Fade out the background photo.
-  void FadeOutPhotoView();
-
  private:
   void Init();
 
diff --git a/ash/ambient/ui/ambient_view_delegate.h b/ash/ambient/ui/ambient_view_delegate.h
index 768987ea..9a23080a 100644
--- a/ash/ambient/ui/ambient_view_delegate.h
+++ b/ash/ambient/ui/ambient_view_delegate.h
@@ -17,7 +17,7 @@
 
   virtual PhotoModel* GetPhotoModel() = 0;
 
-  // Invoked when user interacting with the background photo using mouse,
+  // Invoked when user interacts with the background photo using mouse,
   // touchpad, or touchscreen.
   virtual void OnBackgroundPhotoEvents() = 0;
 };
diff --git a/ash/app_list/views/contents_view.cc b/ash/app_list/views/contents_view.cc
index a2cb858..6466294 100644
--- a/ash/app_list/views/contents_view.cc
+++ b/ash/app_list/views/contents_view.cc
@@ -437,25 +437,6 @@
   search_box->GetWidget()->GetLayer()->SetTransform(transform);
 }
 
-void ContentsView::UpdateExpandArrowOpacity(AppListState target_state,
-                                            bool animate) {
-  float expand_arrow_target_opacity = 0.0f;
-  if (target_state == AppListState::kStateApps) {
-    expand_arrow_target_opacity = 1.0f;
-  } else if (target_state == AppListState::kStateSearchResults ||
-             target_state == AppListState::kStateEmbeddedAssistant) {
-    expand_arrow_target_opacity = 0.0f;
-  } else {
-    // not updated.
-    return;
-  }
-
-  std::unique_ptr<ui::ScopedLayerAnimationSettings> settings;
-  if (animate)
-    settings = CreateTransitionAnimationSettings(expand_arrow_view_->layer());
-  expand_arrow_view_->layer()->SetOpacity(expand_arrow_target_opacity);
-}
-
 void ContentsView::UpdateExpandArrowBehavior(AppListViewState target_state) {
   const bool expand_arrow_enabled = target_state == AppListViewState::kPeeking;
   // The expand arrow is only focusable and has InkDropMode on in peeking
@@ -656,8 +637,6 @@
     page->UpdateOpacityForState(current_state);
   }
 
-  UpdateExpandArrowOpacity(current_state, false);
-
   // Update the searchbox bounds.
   auto* search_box = GetSearchBoxView();
   // Convert search box bounds to the search box widget's coordinate system.
@@ -697,7 +676,6 @@
     page->OnAnimationStarted(current_state, target_state);
 
   InitializeSearchBoxAnimation(current_state, target_state);
-  UpdateExpandArrowOpacity(target_state, true);
 }
 
 void ContentsView::TransitionChanged() {
diff --git a/ash/app_list/views/contents_view.h b/ash/app_list/views/contents_view.h
index 11ec5a50..afd1d002 100644
--- a/ash/app_list/views/contents_view.h
+++ b/ash/app_list/views/contents_view.h
@@ -249,10 +249,6 @@
                                 AppListState current_state,
                                 AppListState target_state);
 
-  // Updates the opacity of the expand arrow to the target state. Set |animate|
-  // to true when the opacity changes gradually.
-  void UpdateExpandArrowOpacity(AppListState target_state, bool animate);
-
   // Updates the expand arrow's behavior based on AppListViewState.
   void UpdateExpandArrowBehavior(AppListViewState target_state);
 
diff --git a/ash/assistant/ui/base/assistant_scroll_view.cc b/ash/assistant/ui/base/assistant_scroll_view.cc
index 023a717c..0dd7862 100644
--- a/ash/assistant/ui/base/assistant_scroll_view.cc
+++ b/ash/assistant/ui/base/assistant_scroll_view.cc
@@ -20,6 +20,9 @@
  public:
   ContentView() { AddObserver(this); }
 
+  ContentView(const ContentView&) = delete;
+  ContentView& operator=(const ContentView&) = delete;
+
   ~ContentView() override { RemoveObserver(this); }
 
   // views::View:
@@ -39,18 +42,19 @@
   void OnChildViewRemoved(views::View* view, views::View* child) override {
     PreferredSizeChanged();
   }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ContentView);
 };
 
 // InvisibleScrollBar ----------------------------------------------------------
 
 class InvisibleScrollBar : public views::OverlayScrollBar {
  public:
-  InvisibleScrollBar(AssistantScrollView* parent, bool horizontal)
-      : views::OverlayScrollBar(horizontal), parent_(parent) {}
+  InvisibleScrollBar(
+      base::ObserverList<AssistantScrollView::Observer>* observers,
+      bool horizontal)
+      : views::OverlayScrollBar(horizontal), observers_(observers) {}
 
+  InvisibleScrollBar(const InvisibleScrollBar&) = delete;
+  InvisibleScrollBar& operator=(const InvisibleScrollBar&) = delete;
   ~InvisibleScrollBar() override = default;
 
   // views::OverlayScrollBar:
@@ -61,20 +65,22 @@
               int content_scroll_offset) override {
     views::OverlayScrollBar::Update(viewport_size, content_size,
                                     content_scroll_offset);
-
-    parent_->OnScrollBarUpdated(this, viewport_size, content_size,
-                                content_scroll_offset);
+    for (auto& observer : *observers_) {
+      observer.OnScrollBarUpdated(this, viewport_size, content_size,
+                                  content_scroll_offset);
+    }
   }
 
   void VisibilityChanged(views::View* starting_from, bool is_visible) override {
-    if (starting_from == this)
-      parent_->OnScrollBarVisibilityChanged(this, is_visible);
+    if (starting_from != this)
+      return;
+
+    for (auto& observer : *observers_)
+      observer.OnScrollBarVisibilityChanged(this, is_visible);
   }
 
  private:
-  AssistantScrollView* const parent_;  // Owned by view hierarchy, owns |this|.
-
-  DISALLOW_COPY_AND_ASSIGN(InvisibleScrollBar);
+  base::ObserverList<AssistantScrollView::Observer>* observers_;
 };
 
 }  // namespace
@@ -92,10 +98,22 @@
 }
 
 void AssistantScrollView::OnViewPreferredSizeChanged(views::View* view) {
-  OnContentsPreferredSizeChanged(content_view_);
+  DCHECK_EQ(content_view_, view);
+
+  for (auto& observer : observers_)
+    observer.OnContentsPreferredSizeChanged(content_view_);
+
   PreferredSizeChanged();
 }
 
+void AssistantScrollView::AddScrollViewObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void AssistantScrollView::RemoveScrollViewObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void AssistantScrollView::InitLayout() {
   SetBackgroundColor(base::nullopt);
   SetDrawOverflowIndicator(false);
@@ -107,10 +125,10 @@
 
   // Scroll bars.
   horizontal_scroll_bar_ = SetHorizontalScrollBar(
-      std::make_unique<InvisibleScrollBar>(this, /*horizontal=*/true));
+      std::make_unique<InvisibleScrollBar>(&observers_, /*horizontal=*/true));
 
   vertical_scroll_bar_ = SetVerticalScrollBar(
-      std::make_unique<InvisibleScrollBar>(this, /*horizontal=*/false));
+      std::make_unique<InvisibleScrollBar>(&observers_, /*horizontal=*/false));
 }
 
 }  // namespace ash
diff --git a/ash/assistant/ui/base/assistant_scroll_view.h b/ash/assistant/ui/base/assistant_scroll_view.h
index b0cce9c..497c498 100644
--- a/ash/assistant/ui/base/assistant_scroll_view.h
+++ b/ash/assistant/ui/base/assistant_scroll_view.h
@@ -6,7 +6,7 @@
 #define ASH_ASSISTANT_UI_BASE_ASSISTANT_SCROLL_VIEW_H_
 
 #include "base/component_export.h"
-#include "base/macros.h"
+#include "base/observer_list.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/view_observer.h"
 
@@ -14,9 +14,31 @@
 
 class COMPONENT_EXPORT(ASSISTANT_UI) AssistantScrollView
     : public views::ScrollView,
-      views::ViewObserver {
+      public views::ViewObserver {
  public:
+  class Observer : public base::CheckedObserver {
+   public:
+    // Invoked when the scrollable contents' preferred size has changed.
+    virtual void OnContentsPreferredSizeChanged(views::View* content_view) {}
+
+    // Invoked when the specified |scroll_bar| has been updated.
+    virtual void OnScrollBarUpdated(views::ScrollBar* scroll_bar,
+                                    int viewport_size,
+                                    int content_size,
+                                    int content_scroll_offset) {}
+
+    // Invoked when the visibility for the specified |scroll_bar| has changed.
+    virtual void OnScrollBarVisibilityChanged(views::ScrollBar* scroll_bar,
+                                              bool is_visible) {}
+
+   protected:
+    Observer() = default;
+    ~Observer() override = default;
+  };
+
   AssistantScrollView();
+  AssistantScrollView(const AssistantScrollView&) = delete;
+  AssistantScrollView& operator=(const AssistantScrollView) = delete;
   ~AssistantScrollView() override;
 
   // views::ScrollView:
@@ -25,17 +47,10 @@
   // views::ViewObserver:
   void OnViewPreferredSizeChanged(views::View* view) override;
 
-  virtual void OnContentsPreferredSizeChanged(views::View* content_view) = 0;
+  // Adds/removes the specified |observer|.
+  void AddScrollViewObserver(Observer* observer);
+  void RemoveScrollViewObserver(Observer* observer);
 
-  virtual void OnScrollBarUpdated(views::ScrollBar* scroll_bar,
-                                  int viewport_size,
-                                  int content_size,
-                                  int content_scroll_offset) {}
-
-  virtual void OnScrollBarVisibilityChanged(views::ScrollBar* scroll_bar,
-                                            bool is_visible) {}
-
- protected:
   views::View* content_view() { return content_view_; }
   const views::View* content_view() const { return content_view_; }
 
@@ -45,11 +60,11 @@
  private:
   void InitLayout();
 
+  base::ObserverList<Observer> observers_;
+
   views::View* content_view_;                // Owned by view hierarchy.
   views::ScrollBar* horizontal_scroll_bar_;  // Owned by view hierarchy.
   views::ScrollBar* vertical_scroll_bar_;    // Owned by view hierarchy.
-
-  DISALLOW_COPY_AND_ASSIGN(AssistantScrollView);
 };
 
 }  // namespace ash
diff --git a/ash/assistant/ui/main_stage/animated_container_view.cc b/ash/assistant/ui/main_stage/animated_container_view.cc
index 772bc294..338aae9 100644
--- a/ash/assistant/ui/main_stage/animated_container_view.cc
+++ b/ash/assistant/ui/main_stage/animated_container_view.cc
@@ -44,12 +44,14 @@
     : delegate_(delegate) {
   // The AssistantViewDelegate should outlive AnimatedContainerView.
   delegate_->AddInteractionModelObserver(this);
+  AddScrollViewObserver(this);
 }
 
 AnimatedContainerView::~AnimatedContainerView() {
   if (IsResponseProcessingV2Enabled() && response_)
     response_.get()->RemoveObserver(this);
 
+  RemoveScrollViewObserver(this);
   delegate_->RemoveInteractionModelObserver(this);
 }
 
diff --git a/ash/assistant/ui/main_stage/animated_container_view.h b/ash/assistant/ui/main_stage/animated_container_view.h
index d12a18eb..ff2253fd 100644
--- a/ash/assistant/ui/main_stage/animated_container_view.h
+++ b/ash/assistant/ui/main_stage/animated_container_view.h
@@ -52,6 +52,7 @@
 //       through OnAllViewsAnimatedIn().
 class COMPONENT_EXPORT(ASSISTANT_UI) AnimatedContainerView
     : public AssistantScrollView,
+      public AssistantScrollView::Observer,
       public AssistantInteractionModelObserver,
       public AssistantResponseObserver {
  public:
diff --git a/ash/assistant/ui/main_stage/assistant_timers_element_view.cc b/ash/assistant/ui/main_stage/assistant_timers_element_view.cc
index cfc98cb..86dfb96 100644
--- a/ash/assistant/ui/main_stage/assistant_timers_element_view.cc
+++ b/ash/assistant/ui/main_stage/assistant_timers_element_view.cc
@@ -5,26 +5,97 @@
 #include "ash/assistant/ui/main_stage/assistant_timers_element_view.h"
 
 #include "ash/assistant/model/assistant_alarm_timer_model.h"
+#include "ash/assistant/model/assistant_alarm_timer_model_observer.h"
 #include "ash/assistant/model/ui/assistant_timers_element.h"
+#include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/assistant/ui/assistant_view_delegate.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
 
 namespace ash {
 
+// AssistantTimerView ----------------------------------------------------------
+
+class AssistantTimerView : public views::View,
+                           public AssistantAlarmTimerModelObserver {
+ public:
+  AssistantTimerView(AssistantViewDelegate* delegate,
+                     const std::string& timer_id)
+      : delegate_(delegate), timer_id_(timer_id) {
+    InitLayout();
+    UpdateLayout();
+
+    delegate_->AddAlarmTimerModelObserver(this);
+  }
+
+  AssistantTimerView(const AssistantTimerView&) = delete;
+  AssistantTimerView& operator=(const AssistantTimerView&) = delete;
+
+  ~AssistantTimerView() override {
+    delegate_->RemoveAlarmTimerModelObserver(this);
+  }
+
+  // views::View:
+  const char* GetClassName() const override { return "AssistantTimerView"; }
+
+  void ChildPreferredSizeChanged(views::View* child) override {
+    PreferredSizeChanged();
+  }
+
+  std::string ToStringForTesting() const {
+    return base::UTF16ToUTF8(label_->GetText());
+  }
+
+ private:
+  // AssistantAlarmTimerModelObserver:
+  void OnTimerUpdated(const mojom::AssistantTimer& timer) override {
+    if (timer.id == timer_id_)
+      UpdateLayout();
+  }
+
+  // TODO(dmblack): Update w/ actual UI adhering to the spec.
+  void InitLayout() {
+    // Layout.
+    SetLayoutManager(std::make_unique<views::FillLayout>());
+
+    // Label.
+    label_ = AddChildView(std::make_unique<views::Label>());
+  }
+
+  // TODO(dmblack): Update w/ actual UI adhering to the spec.
+  void UpdateLayout() {
+    // NOTE: The timer for |timer_id| may no longer exist in the model if it has
+    // been removed while Assistant UI is still showing. This will be better
+    // handled in production once the UI spec has been implemented.
+    const auto* timer =
+        delegate_->GetAlarmTimerModel()->GetTimerById(timer_id_);
+    const base::TimeDelta remaining_time =
+        timer ? timer->remaining_time : base::TimeDelta();
+
+    // Update |label_| to reflect remaining time.
+    label_->SetText(
+        base::UTF8ToUTF16(base::NumberToString(remaining_time.InSeconds())));
+  }
+
+  AssistantViewDelegate* const delegate_;  // Owned (indirectly) by Shell.
+  views::Label* label_;                    // Owned by view hierarchy.
+
+  const std::string timer_id_;
+};
+
+// AssistantTimersElementView --------------------------------------------------
+
 AssistantTimersElementView::AssistantTimersElementView(
     AssistantViewDelegate* delegate,
-    const AssistantTimersElement* timers_element)
-    : delegate_(delegate), timers_element_(timers_element) {
-  InitLayout();
-  UpdateLayout();
-
-  delegate_->AddAlarmTimerModelObserver(this);
+    const AssistantTimersElement* timers_element) {
+  InitLayout(delegate, timers_element);
 }
 
 AssistantTimersElementView::~AssistantTimersElementView() {
-  delegate_->RemoveAlarmTimerModelObserver(this);
+  scroll_view_->RemoveScrollViewObserver(this);
 }
 
 const char* AssistantTimersElementView::GetClassName() const {
@@ -36,46 +107,59 @@
 }
 
 std::string AssistantTimersElementView::ToStringForTesting() const {
-  return base::UTF16ToUTF8(label_->GetText());
+  std::stringstream result;
+  for (auto* child : scroll_view_->content_view()->children()) {
+    AssistantTimerView* timer_view = static_cast<AssistantTimerView*>(child);
+    result << timer_view->ToStringForTesting() << "\n";
+  }
+  return result.str();
+}
+
+gfx::Size AssistantTimersElementView::CalculatePreferredSize() const {
+  return gfx::Size(INT_MAX, GetHeightForWidth(INT_MAX));
+}
+
+int AssistantTimersElementView::GetHeightForWidth(int width) const {
+  return scroll_view_->content_view()->GetHeightForWidth(width);
 }
 
 void AssistantTimersElementView::ChildPreferredSizeChanged(views::View* child) {
   PreferredSizeChanged();
 }
 
-void AssistantTimersElementView::OnTimerUpdated(
-    const mojom::AssistantTimer& timer) {
-  UpdateLayout();
+void AssistantTimersElementView::OnContentsPreferredSizeChanged(
+    views::View* content_view) {
+  int width = std::max(content_view->GetPreferredSize().width(), this->width());
+  int height = content_view->GetHeightForWidth(width);
+  content_view->SetSize(gfx::Size(width, height));
 }
 
-// TODO(dmblack): Update w/ actual UI adhering to the spec.
-void AssistantTimersElementView::InitLayout() {
-  // Layout.
-  SetLayoutManager(std::make_unique<views::FillLayout>());
-
-  // Label.
-  label_ = AddChildView(std::make_unique<views::Label>());
-  label_->SetMultiLine(true);
-
+void AssistantTimersElementView::InitLayout(
+    AssistantViewDelegate* delegate,
+    const AssistantTimersElement* timers_element) {
   // Layer.
   SetPaintToLayer();
   layer()->SetFillsBoundsOpaquely(false);
-}
 
-// TODO(dmblack): Update w/ actual UI adhering to the spec.
-void AssistantTimersElementView::UpdateLayout() {
-  std::stringstream stream;
+  // Layout.
+  SetLayoutManager(std::make_unique<views::FillLayout>());
 
-  for (const auto& timer_id : timers_element_->timer_ids()) {
-    // NOTE: The timer for |timer_id| may no longer exist in the model if it
-    // has been removed while Assistant UI is still showing. This will be better
-    // handled in production once the UI spec has been implemented.
-    const auto* timer = delegate_->GetAlarmTimerModel()->GetTimerById(timer_id);
-    stream << (timer ? timer->remaining_time : base::TimeDelta()).InSeconds();
-    stream << "\n";
+  // Scroll view.
+  scroll_view_ = AddChildView(std::make_unique<AssistantScrollView>());
+  scroll_view_->AddScrollViewObserver(this);
+
+  auto* lm = scroll_view_->content_view()->SetLayoutManager(
+      std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
+          kSpacingDip));
+  lm->set_cross_axis_alignment(views::BoxLayout::CrossAxisAlignment::kStart);
+  lm->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kStart);
+
+  // Timers.
+  for (const auto& timer_id : timers_element->timer_ids()) {
+    scroll_view_->content_view()->AddChildView(
+        std::make_unique<AssistantTimerView>(delegate, timer_id));
   }
-
-  label_->SetText(base::UTF8ToUTF16(stream.str()));
 }
 
 }  // namespace ash
diff --git a/ash/assistant/ui/main_stage/assistant_timers_element_view.h b/ash/assistant/ui/main_stage/assistant_timers_element_view.h
index 0d6ea3df..10e6324 100644
--- a/ash/assistant/ui/main_stage/assistant_timers_element_view.h
+++ b/ash/assistant/ui/main_stage/assistant_timers_element_view.h
@@ -7,14 +7,10 @@
 
 #include <string>
 
-#include "ash/assistant/model/assistant_alarm_timer_model_observer.h"
+#include "ash/assistant/ui/base/assistant_scroll_view.h"
 #include "ash/assistant/ui/main_stage/assistant_ui_element_view.h"
 #include "base/component_export.h"
 
-namespace views {
-class Label;
-}  // namespace views
-
 namespace ash {
 
 class AssistantTimersElement;
@@ -24,7 +20,7 @@
 // AssistantTimersElement. It is a child view of UiElementContainerView.
 class COMPONENT_EXPORT(ASSISTANT_UI) AssistantTimersElementView
     : public AssistantUiElementView,
-      public AssistantAlarmTimerModelObserver {
+      public AssistantScrollView::Observer {
  public:
   AssistantTimersElementView(AssistantViewDelegate* delegate,
                              const AssistantTimersElement* timers_element);
@@ -37,19 +33,18 @@
   const char* GetClassName() const override;
   ui::Layer* GetLayerForAnimating() override;
   std::string ToStringForTesting() const override;
+  gfx::Size CalculatePreferredSize() const override;
+  int GetHeightForWidth(int width) const override;
   void ChildPreferredSizeChanged(views::View* child) override;
 
-  // AssistantAlarmTimerModelObserver:
-  void OnTimerUpdated(const mojom::AssistantTimer& timer) override;
+  // AssistantScrollView::Observer:
+  void OnContentsPreferredSizeChanged(views::View* content_view) override;
 
  private:
-  void InitLayout();
-  void UpdateLayout();
+  void InitLayout(AssistantViewDelegate* delegate,
+                  const AssistantTimersElement* timers_element);
 
-  AssistantViewDelegate* const delegate_;  // Owned (indirectly) by Shell.
-  views::Label* label_;                    // Owned by view hierarchy.
-
-  const AssistantTimersElement* timers_element_;
+  AssistantScrollView* scroll_view_;  // Owned by view hierarchy.
 };
 
 }  // namespace ash
diff --git a/ash/lock_screen_action/lock_screen_action_background_controller.cc b/ash/lock_screen_action/lock_screen_action_background_controller.cc
index 9c0a8197..2aabede 100644
--- a/ash/lock_screen_action/lock_screen_action_background_controller.cc
+++ b/ash/lock_screen_action/lock_screen_action_background_controller.cc
@@ -7,7 +7,6 @@
 #include "ash/lock_screen_action/lock_screen_action_background_controller_impl.h"
 #include "ash/lock_screen_action/lock_screen_action_background_controller_stub.h"
 #include "ash/lock_screen_action/lock_screen_action_background_observer.h"
-#include "ash/public/cpp/ash_switches.h"
 #include "base/callback.h"
 
 namespace ash {
@@ -24,11 +23,6 @@
 LockScreenActionBackgroundController::Create() {
   if (g_testing_factory_callback)
     return g_testing_factory_callback->Run();
-  // Web UI based lock screen implements its own background - use the stub
-  // lock action background controller implementation unless md-based lock UI
-  // is used.
-  if (!switches::IsUsingViewsLock())
-    return std::make_unique<LockScreenActionBackgroundControllerStub>();
   return std::make_unique<LockScreenActionBackgroundControllerImpl>();
 }
 
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index d085b0a..fa7c226 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -337,7 +337,7 @@
   Shelf* shelf = Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow());
   // Tell the focus direction to the status area or the shelf so they can focus
   // the correct child view.
-  if (reverse || !ShelfWidget::IsUsingViewsShelf()) {
+  if (reverse) {
     if (!Shell::GetPrimaryRootWindowController()->IsSystemTrayVisible())
       return;
     shelf->GetStatusAreaWidget()
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index 6e8b09d..acbccbc1 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -93,8 +93,6 @@
 const base::Feature kUnlockWithExternalBinary{
     "UnlockWithExternalBinary", base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kViewsLogin{"ViewsLogin", base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kUseBluetoothSystemInAsh{"UseBluetoothSystemInAsh",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -182,15 +180,6 @@
   return use_trilinear_filtering;
 }
 
-bool IsViewsLoginEnabled() {
-  // Always show webui login if --show-webui-login is present, which is passed
-  // by session manager for automatic recovery. Otherwise, only show views
-  // login if the feature is enabled.
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-             ash::switches::kShowWebUiLogin) &&
-         base::FeatureList::IsEnabled(kViewsLogin);
-}
-
 bool IsSupervisedUserDeprecationNoticeEnabled() {
   return base::FeatureList::IsEnabled(kSupervisedUserDeprecationNotice);
 }
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h
index 3e1dab1..f8ff502c 100644
--- a/ash/public/cpp/ash_features.h
+++ b/ash/public/cpp/ash_features.h
@@ -114,9 +114,6 @@
 // Enables running an external binary which provides lock screen authentication.
 ASH_PUBLIC_EXPORT extern const base::Feature kUnlockWithExternalBinary;
 
-// Enables views login.
-ASH_PUBLIC_EXPORT extern const base::Feature kViewsLogin;
-
 // Enables using the BluetoothSystem Mojo interface for Bluetooth operations.
 ASH_PUBLIC_EXPORT extern const base::Feature kUseBluetoothSystemInAsh;
 
@@ -187,8 +184,6 @@
 
 ASH_PUBLIC_EXPORT bool IsTrilinearFilteringEnabled();
 
-ASH_PUBLIC_EXPORT bool IsViewsLoginEnabled();
-
 ASH_PUBLIC_EXPORT bool IsSupervisedUserDeprecationNoticeEnabled();
 
 ASH_PUBLIC_EXPORT bool IsSwapSideVolumeButtonsForOrientationEnabled();
diff --git a/ash/public/cpp/ash_switches.cc b/ash/public/cpp/ash_switches.cc
index 07d9780..7cdd579 100644
--- a/ash/public/cpp/ash_switches.cc
+++ b/ash/public/cpp/ash_switches.cc
@@ -134,13 +134,6 @@
 // option "Show taps".
 const char kShowTaps[] = "show-taps";
 
-// If true, the webui lock screen will be shown. This is deprecated and will be
-// removed in the future.
-const char kShowWebUiLock[] = "show-webui-lock";
-
-// Forces the webui login implementation.
-const char kShowWebUiLogin[] = "show-webui-login";
-
 // Chromebases' touchscreens can be used to wake from suspend, unlike the
 // touchscreens on other Chrome OS devices. If set, the touchscreen is kept
 // enabled while the screen is off so that it can be used to turn the screen
@@ -179,10 +172,5 @@
   return base::CommandLine::ForCurrentProcess()->HasSwitch(kEnableDimShelf);
 }
 
-// Returns true if the device will NOT show the webui lock screen.
-bool IsUsingViewsLock() {
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(kShowWebUiLock);
-}
-
 }  // namespace switches
 }  // namespace ash
diff --git a/ash/public/cpp/ash_switches.h b/ash/public/cpp/ash_switches.h
index d20e1b1..0141e0b 100644
--- a/ash/public/cpp/ash_switches.h
+++ b/ash/public/cpp/ash_switches.h
@@ -57,15 +57,12 @@
 ASH_PUBLIC_EXPORT extern const char kForceTabletPowerButton[];
 ASH_PUBLIC_EXPORT extern const char kHasInternalStylus[];
 ASH_PUBLIC_EXPORT extern const char kShowTaps[];
-ASH_PUBLIC_EXPORT extern const char kShowWebUiLock[];
-ASH_PUBLIC_EXPORT extern const char kShowWebUiLogin[];
 ASH_PUBLIC_EXPORT extern const char kSuppressMessageCenterPopups[];
 ASH_PUBLIC_EXPORT extern const char kTouchscreenUsableWhileScreenOff[];
 
 ASH_PUBLIC_EXPORT base::Optional<base::TimeDelta> ContextualNudgesInterval();
 ASH_PUBLIC_EXPORT bool ContextualNudgesResetShownCount();
 ASH_PUBLIC_EXPORT bool IsUsingShelfAutoDim();
-ASH_PUBLIC_EXPORT bool IsUsingViewsLock();
 
 }  // namespace switches
 }  // namespace ash
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 12aa022..08142e6 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -246,24 +246,6 @@
 
 ShelfWidget::DelegateView::~DelegateView() = default;
 
-// static
-bool ShelfWidget::IsUsingViewsShelf() {
-  switch (Shell::Get()->session_controller()->GetSessionState()) {
-    case session_manager::SessionState::ACTIVE:
-      return true;
-    // See https://crbug.com/798869.
-    case session_manager::SessionState::OOBE:
-    case session_manager::SessionState::LOGIN_PRIMARY:
-      return true;
-    case session_manager::SessionState::LOCKED:
-    case session_manager::SessionState::LOGIN_SECONDARY:
-      return switches::IsUsingViewsLock();
-    case session_manager::SessionState::UNKNOWN:
-    case session_manager::SessionState::LOGGED_IN_NOT_ACTIVE:
-      return features::IsViewsLoginEnabled();
-  }
-}
-
 void ShelfWidget::DelegateView::SetParentLayer(ui::Layer* layer) {
   layer->Add(opaque_background());
   ReorderLayers();
@@ -436,9 +418,6 @@
 }
 
 views::View* ShelfWidget::DelegateView::GetDefaultFocusableChild() {
-  if (!IsUsingViewsShelf())
-    return GetFirstFocusableChild();
-
   if (login_shelf_view_->GetVisible()) {
     return FindFirstOrLastFocusableChild(login_shelf_view_,
                                          default_last_focusable_child_);
@@ -925,24 +904,9 @@
   // * when views based shelf is disabled
   // * in UNKNOWN state - it might be called before shelf was initialized
   // * on secondary screens in states other than ACTIVE
-  //
-  // TODO(alemate): better handle show-hide for some UI screens:
-  // https://crbug.com/935842
-  // https://crbug.com/935844
-  // https://crbug.com/935846
-  // https://crbug.com/935847
-  // https://crbug.com/935852
-  // https://crbug.com/935853
-  // https://crbug.com/935856
-  // https://crbug.com/935857
-  // https://crbug.com/935858
-  // https://crbug.com/935860
-  // https://crbug.com/935861
-  // https://crbug.com/935863
-  bool using_views_shelf = IsUsingViewsShelf();
   bool unknown_state = state == session_manager::SessionState::UNKNOWN;
   bool hide_on_secondary_screen = shelf_->ShouldHideOnSecondaryDisplay(state);
-  if (!using_views_shelf || unknown_state || hide_on_secondary_screen) {
+  if (unknown_state || hide_on_secondary_screen) {
     HideIfShown();
   } else {
     bool show_hotseat = (state == session_manager::SessionState::ACTIVE);
diff --git a/ash/shelf/shelf_widget.h b/ash/shelf/shelf_widget.h
index f0f91b5..97769411 100644
--- a/ash/shelf/shelf_widget.h
+++ b/ash/shelf/shelf_widget.h
@@ -58,9 +58,6 @@
   // Clean up prior to deletion.
   void Shutdown();
 
-  // Returns true if the views-based shelf is being shown.
-  static bool IsUsingViewsShelf();
-
   void OnTabletModeChanged();
 
   ShelfBackgroundType GetBackgroundType() const;
diff --git a/ash/shelf/shelf_widget_unittest.cc b/ash/shelf/shelf_widget_unittest.cc
index 36454647..f83e32e 100644
--- a/ash/shelf/shelf_widget_unittest.cc
+++ b/ash/shelf/shelf_widget_unittest.cc
@@ -7,7 +7,6 @@
 #include "ash/keyboard/ui/keyboard_ui_controller.h"
 #include "ash/keyboard/ui/keyboard_util.h"
 #include "ash/keyboard/ui/test/keyboard_test_util.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/keyboard/keyboard_switches.h"
 #include "ash/public/cpp/shelf_config.h"
@@ -29,8 +28,6 @@
 #include "ash/wm/window_util.h"
 #include "base/bind_helpers.h"
 #include "base/run_loop.h"
-#include "base/test/scoped_feature_list.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/session_manager/session_manager_types.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -839,33 +836,7 @@
   DISALLOW_COPY_AND_ASSIGN(ShelfWidgetViewsVisibilityTest);
 };
 
-TEST_F(ShelfWidgetViewsVisibilityTest, LoginWebUiLockViews) {
-  // Enable web UI login.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kShowWebUiLogin);
-  ASSERT_NO_FATAL_FAILURE(InitShelfVariables());
-
-  // Both shelf views are hidden when session state hasn't been initialized.
-  ExpectVisible(SessionState::UNKNOWN, kNone /*primary*/, kNone /*secondary*/);
-  // Web UI login is used, so views shelf is not visible during login.
-  ExpectVisible(SessionState::OOBE, kLoginShelf, kNone);
-  ExpectVisible(SessionState::LOGIN_PRIMARY, kLoginShelf, kNone);
-
-  SimulateUserLogin("user1@test.com");
-
-  ExpectVisible(SessionState::LOGGED_IN_NOT_ACTIVE, kNone, kNone);
-  ExpectVisible(SessionState::ACTIVE, kShelf, kShelf);
-  ExpectVisible(SessionState::LOCKED, kLoginShelf, kNone);
-  ExpectVisible(SessionState::ACTIVE, kShelf, kShelf);
-  ExpectVisible(SessionState::LOGIN_SECONDARY, kLoginShelf, kNone);
-  ExpectVisible(SessionState::ACTIVE, kShelf, kShelf);
-}
-
 TEST_F(ShelfWidgetViewsVisibilityTest, LoginViewsLockViews) {
-  // Enable views login. Views lock enabled by default.
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(ash::features::kViewsLogin);
-
   ASSERT_NO_FATAL_FAILURE(InitShelfVariables());
 
   ExpectVisible(SessionState::UNKNOWN, kNone /*primary*/, kNone /*secondary*/);
diff --git a/ash/system/bluetooth/tray_bluetooth_helper_legacy.cc b/ash/system/bluetooth/tray_bluetooth_helper_legacy.cc
index 21c05f9..ae41890 100644
--- a/ash/system/bluetooth/tray_bluetooth_helper_legacy.cc
+++ b/ash/system/bluetooth/tray_bluetooth_helper_legacy.cc
@@ -38,6 +38,24 @@
 // System tray shows a limited number of bluetooth devices.
 const int kMaximumDevicesShown = 50;
 
+device::ConnectionFailureReason GetConnectionFailureReason(
+    device::BluetoothDevice::ConnectErrorCode error_code) {
+  switch (error_code) {
+    case device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_FAILED:
+      return device::ConnectionFailureReason::kAuthFailed;
+    case device::BluetoothDevice::ConnectErrorCode::ERROR_AUTH_TIMEOUT:
+      return device::ConnectionFailureReason::kAuthTimeout;
+    case device::BluetoothDevice::ConnectErrorCode::ERROR_FAILED:
+      return device::ConnectionFailureReason::kFailed;
+    case device::BluetoothDevice::ConnectErrorCode::ERROR_UNKNOWN:
+      return device::ConnectionFailureReason::kUnknownConnectionError;
+    case device::BluetoothDevice::ConnectErrorCode::ERROR_UNSUPPORTED_DEVICE:
+      return device::ConnectionFailureReason::kUnsupportedDevice;
+    default:
+      return device::ConnectionFailureReason::kUnknownError;
+  }
+}
+
 void BluetoothSetDiscoveringError() {
   LOG(ERROR) << "BluetoothSetDiscovering failed.";
 }
@@ -45,7 +63,8 @@
 void OnBluetoothDeviceConnect(bool was_device_already_paired) {
   if (was_device_already_paired) {
     device::RecordUserInitiatedReconnectionAttemptResult(
-        true /* success */, device::BluetoothUiSurface::kSystemTray);
+        base::nullopt /* failure_reason */,
+        device::BluetoothUiSurface::kSystemTray);
   }
 }
 
@@ -58,7 +77,8 @@
 
   if (was_device_already_paired) {
     device::RecordUserInitiatedReconnectionAttemptResult(
-        false /* success */, device::BluetoothUiSurface::kSystemTray);
+        GetConnectionFailureReason(error_code),
+        device::BluetoothUiSurface::kSystemTray);
   }
 }
 
@@ -225,7 +245,8 @@
 
     if (!device->IsConnectable()) {
       device::RecordUserInitiatedReconnectionAttemptResult(
-          false /* success */, device::BluetoothUiSurface::kSystemTray);
+          device::ConnectionFailureReason::kNotConnectable,
+          device::BluetoothUiSurface::kSystemTray);
       return;
     }
 
diff --git a/ash/system/status_area_widget_delegate.cc b/ash/system/status_area_widget_delegate.cc
index 367b7515..987c60c 100644
--- a/ash/system/status_area_widget_delegate.cc
+++ b/ash/system/status_area_widget_delegate.cc
@@ -96,10 +96,6 @@
 }
 
 bool StatusAreaWidgetDelegate::ShouldFocusOut(bool reverse) {
-  // Never bring the focus out if it's not a views-based shelf as it is visually
-  // not on par with the status widget.
-  if (!ShelfWidget::IsUsingViewsShelf())
-    return false;
   views::View* focused_view = GetFocusManager()->GetFocusedView();
   return (reverse && focused_view == GetFirstFocusableChild()) ||
          (!reverse && focused_view == GetLastFocusableChild());
diff --git a/ash/system/status_area_widget_unittest.cc b/ash/system/status_area_widget_unittest.cc
index 6663011..e143a4d 100644
--- a/ash/system/status_area_widget_unittest.cc
+++ b/ash/system/status_area_widget_unittest.cc
@@ -100,9 +100,6 @@
 
   // AshTestBase:
   void SetUp() override {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kShowWebUiLock);
-
     AshTestBase::SetUp();
     test_observer_.reset(new SystemTrayFocusTestObserver);
     Shell::Get()->system_tray_notifier()->AddSystemTrayFocusObserver(
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 178415a..96b7a02 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -963,8 +963,8 @@
                                         const gfx::Rect& new_bounds,
                                         ui::PropertyChangeReason reason) {
   DCHECK_EQ(this->window(), window);
-  if (window_->transparent() &&
-      window_->type() == aura::client::WINDOW_TYPE_NORMAL) {
+  if (window_->transparent() && IsNormalStateType() &&
+      window_->GetProperty(ash::kWindowManagerManagesOpacityKey)) {
     window_->SetOpaqueRegionsForOcclusion({gfx::Rect(new_bounds.size())});
   }
 }
diff --git a/base/allocator/partition_allocator/OWNERS b/base/allocator/partition_allocator/OWNERS
index b0a2a850..816b0f2 100644
--- a/base/allocator/partition_allocator/OWNERS
+++ b/base/allocator/partition_allocator/OWNERS
@@ -1,5 +1,6 @@
 ajwong@chromium.org
 haraken@chromium.org
+lizeb@chromium.org
 palmer@chromium.org
 tsepez@chromium.org
 
diff --git a/base/check_unittest.cc b/base/check_unittest.cc
index b613b9a..8f7095f 100644
--- a/base/check_unittest.cc
+++ b/base/check_unittest.cc
@@ -6,6 +6,7 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/strings/string_piece.h"
+#include "base/test/gtest_util.h"
 #include "build/build_config.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -56,7 +57,7 @@
 #if defined(OFFICIAL_BUILD) && defined(NDEBUG)
 #define EXPECT_CHECK(msg, check_expr) \
   do {                                \
-    EXPECT_DEATH(check_expr, "");     \
+    EXPECT_CHECK_DEATH(check_expr);   \
   } while (0)
 #else
 #define EXPECT_CHECK(msg, check_expr)                          \
diff --git a/build/config/fuchsia/generate_runner_scripts.gni b/build/config/fuchsia/generate_runner_scripts.gni
index 1afbfa4..3d45f12 100644
--- a/build/config/fuchsia/generate_runner_scripts.gni
+++ b/build/config/fuchsia/generate_runner_scripts.gni
@@ -81,18 +81,13 @@
     }
     wrapper_script = generated_run_pkg_script_path
 
-    data_deps = [
-      invoker.package,
-
-      # Runner scripts require access to "ids.txt" for symbolization, and to
-      # the "package" from which to get the name & version to deploy, which
-      # are outputs of the archive manifest generation action.
-      invoker.package + "__archive-manifest",
-    ]
-    if (defined(invoker.data_deps)) {
-      data_deps += invoker.data_deps
+    deps = [ invoker.package ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
     }
 
+    data_deps = [ invoker.package ]
+
     # Declares the files that are needed for test execution on the
     # swarming test client.
     data = [
@@ -138,10 +133,7 @@
         package_dep_target = package_dep[0]
         package_dep_name = package_dep[1]
 
-        data_deps += [
-          package_dep_target,
-          package_dep_target + "__archive-manifest",
-        ]
+        deps += [ package_dep_target ]
         package_dep_path = rebase_path(
                 get_label_info(package_dep_target, "target_gen_dir") + "/" +
                     package_dep_name + "/" + package_dep_name + ".far",
@@ -186,9 +178,9 @@
     executable = rebase_path("//build/fuchsia/deploy_to_amber_repo.py")
     wrapper_script = generated_install_pkg_script_path
 
-    data_deps = [ invoker.package ]
-    if (defined(invoker.data_deps)) {
-      data_deps += invoker.data_deps
+    deps = [ invoker.package ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
     }
 
     # Build a list of all packages to install, and pass the list to the runner
@@ -199,7 +191,7 @@
         package_dep_target = package_dep[0]
         package_dep_name = package_dep[1]
 
-        data_deps += [ package_dep_target ]
+        deps += [ package_dep_target ]
         package_dep_path = rebase_path(
                 get_label_info(package_dep_target, "target_gen_dir") + "/" +
                     package_dep_name + "/" + package_dep_name + ".far",
diff --git a/build/config/fuchsia/package.gni b/build/config/fuchsia/package.gni
index 3324738..8fe34fe0 100644
--- a/build/config/fuchsia/package.gni
+++ b/build/config/fuchsia/package.gni
@@ -2,12 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//third_party/fuchsia-sdk/sdk/build/component.gni")
-import("//third_party/fuchsia-sdk/sdk/build/package.gni")
+import("//build/config/sysroot.gni")
 
-# DEPRECATED: Use the Fuchsia SDK's fuchsia_component() and fuchsia_package()
-# templates directly, in new code.
-#
 # Creates a Fuchsia .far package file containing a Fuchsia component.
 #
 # Parameters are:
@@ -32,97 +28,210 @@
 #
 # TODO(https://crbug.com/1050703): Migrate consumers to GN SDK equivalents.
 template("cr_fuchsia_package") {
-  assert(defined(invoker.binary))
+  pkg = {
+    forward_variables_from(invoker, "*")
 
-  if (defined(invoker.package_name_override)) {
-    _package_name = invoker.package_name_override
-  } else {
-    _package_name = invoker.target_name
-  }
+    if (defined(package_name_override)) {
+      package_name = package_name_override
+    } else {
+      package_name = invoker.target_name
+    }
 
-  _package_contents = [ invoker.binary ]
-  if (defined(invoker.deps)) {
-    _package_contents += invoker.deps
-  }
+    if (defined(archive_name_override)) {
+      archive_filename = archive_name_override
+    } else {
+      archive_filename = package_name
+    }
 
-  _component_target = target_name + "__cr-component"
-  _package_components = [ ":${_component_target}" ]
-
-  # Declare the primary component for this package.
-  fuchsia_component(_component_target) {
-    forward_variables_from(invoker,
-                           [
-                             #"data",
-                             "testonly",
-                           ])
-
-    if (!defined(invoker.manifest)) {
+    if (!defined(manifest)) {
       assert(testonly == true)
 
       # TODO(1019938): switch the default to tests.cmx which doesn't request
       # the deprecated-ambient-replace-as-executable feature.
-      manifest_fragment = "//build/config/fuchsia/tests-with-exec.cmx"
-    } else {
-      manifest_fragment = invoker.manifest
+      manifest = "//build/config/fuchsia/tests-with-exec.cmx"
     }
+  }
+  assert(defined(pkg.binary))
 
-    manifest_fragment_data = read_file(manifest_fragment, "json")
-    if (!defined(manifest_fragment_data.program)) {
-      manifest_fragment_data.program = {
-        binary = get_label_info(invoker.binary, "name")
+  _pm_tool_path = "//third_party/fuchsia-sdk/sdk/tools/pm"
+
+  _pkg_out_dir = "${target_gen_dir}/${pkg.archive_filename}"
+  _runtime_deps_file = "$_pkg_out_dir/${pkg.archive_filename}.runtime_deps"
+  _archive_manifest = "$_pkg_out_dir/${pkg.archive_filename}.archive_manifest"
+  _build_ids_file = "$_pkg_out_dir/ids.txt"
+  _meta_far_file = "$_pkg_out_dir/meta.far"
+  _combined_far_file = "$_pkg_out_dir/${pkg.package_name}-0.far"
+  _final_far_file = "$_pkg_out_dir/${pkg.archive_filename}.far"
+  _package_info_path = "$_pkg_out_dir/package"
+
+  if (defined(pkg.component_name_override)) {
+    _generated_cmx = "$_pkg_out_dir/${pkg.component_name_override}.cmx"
+  } else {
+    _generated_cmx = "$_pkg_out_dir/${pkg.package_name}.cmx"
+  }
+
+  _write_manifest_target = "${pkg.package_name}__write_manifest"
+  _package_target = "${pkg.package_name}__pkg"
+  _bundle_target = "${pkg.package_name}__bundle"
+
+  # Generates a manifest file based on the GN runtime deps
+  # suitable for "pm" tool consumption.
+  action(_write_manifest_target) {
+    _depfile = "${target_gen_dir}/${target_name}_stamp.d"
+
+    forward_variables_from(invoker,
+                           [
+                             "data",
+                             "deps",
+                             "testonly",
+                           ])
+
+    script = "//build/config/fuchsia/prepare_package_inputs.py"
+
+    inputs = [
+      _runtime_deps_file,
+      pkg.manifest,
+    ]
+
+    outputs = [
+      _archive_manifest,
+      _build_ids_file,
+      _generated_cmx,
+    ]
+
+    if (!defined(deps)) {
+      deps = []
+    }
+    deps += [ pkg.binary ]
+    data_deps = deps
+
+    # Use a depfile to trigger package rebuilds if any of the files (static
+    # assets, shared libraries, etc.) included by the package have changed.
+    depfile = _depfile
+
+    args = [
+      "--root-dir",
+      rebase_path("//", root_build_dir),
+      "--out-dir",
+      rebase_path(root_out_dir, root_build_dir),
+      "--app-name",
+      pkg.package_name,
+      "--app-filename",
+      get_label_info(pkg.binary, "name"),
+      "--manifest-input-path",
+      rebase_path(pkg.manifest, root_build_dir),
+      "--runtime-deps-file",
+      rebase_path(_runtime_deps_file, root_build_dir),
+      "--depfile-path",
+      rebase_path(_depfile, root_build_dir),
+      "--package-manifest-path",
+      rebase_path(_archive_manifest, root_build_dir),
+      "--component-manifest-path",
+      rebase_path(_generated_cmx, root_build_dir),
+      "--build-ids-file",
+      rebase_path(_build_ids_file, root_build_dir),
+    ]
+
+    if (defined(pkg.excluded_files)) {
+      foreach(filename, pkg.excluded_files) {
+        args += [
+          "--exclude-file",
+          filename,
+        ]
       }
     }
-    manifest = "$target_out_dir/" + target_name + "__component-manifest.cmx"
-    write_file(manifest, manifest_fragment_data, "json")
 
-    if (defined(invoker.component_name_override)) {
-      manifest_output_name = "${invoker.component_name_override}"
-    } else {
-      manifest_output_name = "${_package_name}"
-    }
-
-    data_deps = _package_contents
-  }
-
-  # Bundle manifests providing additional entrypoints into the package.
-  if (defined(invoker.additional_manifests)) {
-    foreach(filename, invoker.additional_manifests) {
-      _additional_component_target = target_name + "_" + filename
-      _package_components += [ ":${_additional_component_target}" ]
-      fuchsia_component(_additional_component_target) {
-        forward_variables_from(invoker, [ "testonly" ])
-        data_deps = _package_contents
-        manifest = filename
+    if (defined(pkg.additional_manifests)) {
+      foreach(filename, pkg.additional_manifests) {
+        args += [
+          "--additional-manifest",
+          rebase_path(filename),
+        ]
       }
     }
+
+    write_runtime_deps = _runtime_deps_file
   }
 
-  # Generate a Fuchsia ARchive (FAR) of the requested name.
-  if (defined(invoker.archive_name_override)) {
-    _archive_name = invoker.archive_name_override
-  } else {
-    _archive_name = _package_name
-  }
-
-  if (_archive_name != _package_name) {
-    _archive_target = target_name + "__cr-archive"
-
-    copy(target_name) {
-      deps = [ ":${_archive_target}" ]
-      _pkg_out_dir = "${target_gen_dir}/${_package_name}"
-      sources = [ "${_pkg_out_dir}/${_package_name}.far" ]
-      outputs = [ "${_pkg_out_dir}/${_archive_name}.far" ]
-    }
-  } else {
-    _archive_target = target_name
-  }
-
-  fuchsia_package(_archive_target) {
+  # Creates a signed Fuchsia metadata package.
+  action(_package_target) {
     forward_variables_from(invoker, [ "testonly" ])
-    package_name = _package_name
-    if (defined(invoker.excluded_files)) {
-      excluded_files = invoker.excluded_files
+
+    script = "//build/gn_run_binary.py"
+
+    deps = [ ":$_write_manifest_target" ]
+
+    inputs = [
+      # Depend on the SDK hash, to ensure rebuild if the SDK tools change.
+      "//third_party/fuchsia-sdk/sdk/.hash",
+    ]
+
+    if (defined(pkg.additional_manifests)) {
+      inputs += pkg.additional_manifests
     }
-    deps = _package_components
+
+    outputs = [ _meta_far_file ]
+
+    args = [
+      rebase_path(_pm_tool_path, root_build_dir),
+      "-o",
+      rebase_path(_pkg_out_dir, root_build_dir),
+      "-m",
+      rebase_path(_archive_manifest, root_build_dir),
+      "build",
+    ]
+  }
+
+  # Creates a package containing the metadata archive and blob data.
+  action(_bundle_target) {
+    forward_variables_from(invoker, [ "testonly" ])
+
+    script = "//build/gn_run_binary.py"
+
+    deps = [
+      ":$_package_target",
+      ":$_write_manifest_target",
+    ]
+
+    inputs = [
+      # Depend on the SDK hash, to ensure rebuild if the SDK tools change.
+      "//third_party/fuchsia-sdk/sdk/.hash",
+      _meta_far_file,
+      _archive_manifest,
+    ]
+
+    outputs = [ _combined_far_file ]
+
+    args = [
+      rebase_path(_pm_tool_path, root_build_dir),
+      "-o",
+      rebase_path(_pkg_out_dir, root_build_dir),
+      "-m",
+      rebase_path(_archive_manifest, root_build_dir),
+      "archive",
+    ]
+  }
+
+  # Copies the archive to a well-known path.
+  # TODO(kmarshall): Use a 'pm' output flag to write directly to the desired
+  # file path instead.
+  copy(target_name) {
+    forward_variables_from(invoker, [ "testonly" ])
+
+    # Allows dependent targets to make use of "ids.txt".
+    public_deps = [ ":$_write_manifest_target" ]
+
+    deps = [ ":$_bundle_target" ]
+
+    data = [
+      _final_far_file,
+
+      # Files specified here so that they can be read by isolated testbots.
+      _package_info_path,
+      _build_ids_file,
+    ]
+
+    sources = [ _combined_far_file ]
+    outputs = [ _final_far_file ]
   }
 }
diff --git a/build/config/fuchsia/symbol_archive.gni b/build/config/fuchsia/symbol_archive.gni
index 9dcb53c..28fa248 100644
--- a/build/config/fuchsia/symbol_archive.gni
+++ b/build/config/fuchsia/symbol_archive.gni
@@ -8,7 +8,6 @@
 # ".build_ids" convention used by the symbolizer and GNU GDB.
 #
 # Parameters:
-#   deps: Must all be cr_fuchsia_package() or fuchsia_package() targets.
 #   ids_txt: The "ids.txt" file which lists the relative paths to unstripped
 #            executables and libraries, along with their build IDs.
 #   archive_name: The path to the compressed tarball that will be generated.
@@ -25,16 +24,7 @@
 
     outputs = [ _build_ids ]
 
-    # For each package in |deps| it is necessary to additionally depend upon
-    # the corresponding archive-manifest target, which is what creates the
-    # ids.txt file.
-    deps = []
-    foreach(package, invoker.deps) {
-      deps += [
-        package,
-        package + "__archive-manifest",
-      ]
-    }
+    deps = invoker.deps
 
     args = [
       rebase_path(_ids_txt),
diff --git a/cc/paint/paint_image.h b/cc/paint/paint_image.h
index e7d38dd..274deba 100644
--- a/cc/paint/paint_image.h
+++ b/cc/paint/paint_image.h
@@ -27,7 +27,7 @@
 class PaintWorkletInput;
 using PaintRecord = PaintOpBuffer;
 
-enum class ImageType { kPNG, kJPEG, kWEBP, kGIF, kICO, kBMP, kInvalid };
+enum class ImageType { kPNG, kJPEG, kWEBP, kGIF, kICO, kBMP, kAVIF, kInvalid };
 
 enum class YUVSubsampling { k410, k411, k420, k422, k440, k444, kUnknown };
 
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 806d223..79b2941 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -329,6 +329,7 @@
   "javatests/src/org/chromium/chrome/browser/payments/ExpandablePaymentHandlerChangePaymentMethodTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/IsReadyToPayServiceHelperTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/MockPackageManagerDelegate.java",
+  "javatests/src/org/chromium/chrome/browser/payments/PaymentErrorStringsTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentHandlerChangePaymentMethodTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentHandlerEnableDelegationsTest.java",
   "javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java",
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java
index 0aa976c..0029b58 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java
@@ -7,9 +7,9 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import static org.chromium.chrome.browser.multiwindow.MultiWindowTestHelper.moveActivityToFront;
 import static org.chromium.chrome.browser.multiwindow.MultiWindowTestHelper.waitForSecondChromeTabbedActivity;
 import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.clickFirstCardFromTabSwitcher;
+import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.createTabs;
 
 import android.annotation.TargetApi;
 import android.os.Build;
@@ -26,7 +26,6 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
@@ -38,7 +37,6 @@
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
-import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.MenuUtils;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.content_public.browser.test.util.Criteria;
@@ -77,12 +75,11 @@
     @Test
     @MediumTest
     @TargetApi(Build.VERSION_CODES.N)
-    @DisableIf.Build(message = "crbug.com/1017141", sdk_is_less_than = Build.VERSION_CODES.P)
     public void testMoveTabsAcrossWindow_GTS_WithoutGroup() {
         final ChromeTabbedActivity cta1 = mActivityTestRule.getActivity();
         // Initially, we have 4 normal tabs and 3 incognito tabs in cta1.
-        initializeTabModel(cta1, false, 4);
-        initializeTabModel(cta1, true, 3);
+        createTabs(cta1, false, 4);
+        createTabs(cta1, true, 3);
         verifyTabModelTabCount(cta1, 4, 3);
 
         // Enter tab switcher in cta1 in incognito mode.
@@ -105,7 +102,6 @@
         CriteriaHelper.pollUiThread(Criteria.equals(1, recyclerView1::getChildCount));
 
         // Enter tab switcher in cta2.
-        moveActivityToFront(cta2);
         enterTabSwitcher(cta2);
 
         // There should be two incognito tabs in tab switcher in cta2.
@@ -122,10 +118,8 @@
         enterTabSwitcher(cta2);
         CriteriaHelper.pollUiThread(Criteria.equals(1, recyclerView2::getChildCount));
 
-        // Enter tab switcher in cta1.
-        moveActivityToFront(cta1);
-
-        // There should be two incognito tabs in tab switcher in cta1.
+        // Enter tab switcher in cta1. Verify there are two incognito tabs in tab switcher in cta1.
+        enterTabSwitcher(cta1);
         CriteriaHelper.pollUiThread(Criteria.equals(2, recyclerView1::getChildCount));
 
         // Switch to normal tab list in cta1.
@@ -148,7 +142,6 @@
         CriteriaHelper.pollUiThread(Criteria.equals(1, recyclerView1::getChildCount));
 
         // Enter tab switcher in cta2.
-        moveActivityToFront(cta2);
         enterTabSwitcher(cta2);
 
         // There should be 3 normal tabs in tab switcher in cta2.
@@ -165,13 +158,6 @@
         CriteriaHelper.pollUiThread(Criteria.equals(1, recyclerView2::getChildCount));
     }
 
-    private void initializeTabModel(ChromeTabbedActivity cta, boolean isIncognito, int tabsCount) {
-        for (int i = 0; i < (isIncognito ? tabsCount : tabsCount - 1); i++) {
-            ChromeTabUtils.newTabFromMenu(
-                    InstrumentationRegistry.getInstrumentation(), cta, isIncognito, true);
-        }
-    }
-
     private void moveTabsToOtherWindow(ChromeTabbedActivity cta, int number) {
         for (int i = 0; i < number; i++) {
             MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(), cta,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateImpl.java
index 436d2d1..5ddbb35c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateImpl.java
@@ -18,6 +18,7 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.core.graphics.drawable.DrawableCompat;
@@ -417,6 +418,14 @@
     }
 
     /**
+     * @param currentTab The currentTab for which the app menu is showing.
+     * @return Whether the translate menu item should be displayed.
+     */
+    protected boolean shouldShowTranslateMenuItem(@NonNull Tab currentTab) {
+        return TranslateUtils.canTranslateCurrentTab(currentTab);
+    }
+
+    /**
      * @param isChromeScheme Whether URL for the current tab starts with the chrome:// scheme.
      * @param isFileScheme Whether URL for the current tab starts with the file:// scheme.
      * @param isContentScheme Whether URL for the current tab starts with the file:// scheme.
@@ -465,7 +474,7 @@
                 homescreenItem.setVisible(false);
                 openWebApkItem.setVisible(true);
             } else {
-                homescreenItem.setTitle(AppBannerManager.getHomescreenLanguageOption());
+                homescreenItem.setTitle(getAddToHomeScreenTitle());
                 homescreenItem.setVisible(true);
                 openWebApkItem.setVisible(false);
             }
@@ -475,6 +484,12 @@
         }
     }
 
+    @VisibleForTesting
+    @StringRes
+    int getAddToHomeScreenTitle() {
+        return AppBannerManager.getHomescreenLanguageOption();
+    }
+
     @Override
     public Bundle getBundleForMenuItem(MenuItem item) {
         return null;
@@ -484,7 +499,7 @@
      * Sets the visibility of the "Translate" menu item.
      */
     protected void prepareTranslateMenuItem(Menu menu, Tab currentTab) {
-        boolean isTranslateVisible = TranslateUtils.canTranslateCurrentTab(currentTab);
+        boolean isTranslateVisible = shouldShowTranslateMenuItem(currentTab);
         RecordHistogram.recordBooleanHistogram(
                 "Translate.MobileMenuTranslate.Shown", isTranslateVisible);
         menu.findItem(R.id.translate_id).setVisible(isTranslateVisible);
@@ -515,7 +530,8 @@
         }
     }
 
-    private boolean shouldShowIconRow() {
+    @VisibleForTesting
+    boolean shouldShowIconRow() {
         boolean shouldShowIconRow = !mIsTablet
                 || mDecorView.getWidth()
                         < DeviceFormFactor.getNonMultiDisplayMinimumTabletWidthPx(mContext);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
index 2a37a65..7d3b3b3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java
@@ -242,7 +242,7 @@
 
     private int getMaxSheetHeight() {
         Tab tab = mTabProvider.get();
-        if (tab == null) return 0;
+        if (tab == null || tab.getView() == null) return 0;
         return (int) (tab.getView().getHeight() * 0.9f);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java
index fa582e9..e411b831 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/NavigationHandlerTest.java
@@ -6,6 +6,7 @@
 
 import android.app.Activity;
 import android.graphics.Point;
+import android.os.Build;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
@@ -22,7 +23,7 @@
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
+import org.chromium.base.test.util.DisableIf;
 import org.chromium.chrome.browser.compositor.animation.CompositorAnimationHandler;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tab.Tab;
@@ -117,6 +118,8 @@
 
     @Test
     @SmallTest
+    @DisableIf.
+    Build(sdk_is_greater_than = Build.VERSION_CODES.O_MR1, message = "Flaky on P crbug.com/1041233")
     public void testSwipeNavigateOnNativePage() {
         mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
         mActivityTestRule.loadUrl(UrlConstants.RECENT_TABS_URL);
@@ -126,7 +129,8 @@
 
     @Test
     @SmallTest
-    @DisabledTest(message = "crbug.com/1068661")
+    @DisableIf.
+    Build(sdk_is_greater_than = Build.VERSION_CODES.O_MR1, message = "Flaky on P crbug.com/1041233")
     public void testSwipeNavigateOnRenderedPage() {
         mTestServer = EmbeddedTestServer.createAndStartServer(
                 InstrumentationRegistry.getInstrumentation().getContext());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentErrorStringsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentErrorStringsTest.java
new file mode 100644
index 0000000..12b153a2
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentErrorStringsTest.java
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.payments;
+
+import android.support.test.filters.SmallTest;
+import android.text.TextUtils;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.components.payments.ErrorStrings;
+
+import java.lang.reflect.Field;
+
+/**
+ * Tests for generated {@link ErrorStrings.java}.
+ **/
+@RunWith(ChromeJUnit4ClassRunner.class)
+public class PaymentErrorStringsTest {
+    // Tests that error strings are generated successfully and have non-empty values.
+    @Test
+    @SmallTest
+    @Feature({"Payments"})
+    public void checkNonemptyTest() throws Throwable {
+        Field[] fields = ErrorStrings.class.getFields();
+        for (Field f : fields) {
+            Assert.assertTrue(f.getType().equals(String.class));
+            String errorMessage = (String) f.get(null);
+            Assert.assertFalse(TextUtils.isEmpty(errorMessage));
+        }
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/WebPaymentIntentHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/WebPaymentIntentHelperTest.java
index 13b43a3a..d48b549 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/WebPaymentIntentHelperTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/WebPaymentIntentHelperTest.java
@@ -53,6 +53,33 @@
     private String mMethodName;
     private PayerData mPayerData;
 
+    private Intent createPaymentResponseWithMissingField(String missingField) {
+        Intent intent = new Intent();
+        Bundle extras = new Bundle();
+        extras.putString(WebPaymentIntentHelper.EXTRA_RESPONSE_DETAILS, "\"key\":\"value\"}");
+        extras.putString(WebPaymentIntentHelper.EXTRA_RESPONSE_METHOD_NAME, "maxPay");
+        Bundle addressBundle = new Bundle();
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_COUNTRY, "Canada");
+        String[] addressLine = {"111 Richmond Street West"};
+        addressBundle.putStringArray(WebPaymentIntentHelper.EXTRA_ADDRESS_LINES, addressLine);
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_REGION, "Ontario");
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_CITY, "Toronto");
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_POSTAL_CODE, "M5H2G4");
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_RECIPIENT, "John Smith");
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_PHONE, "4169158200");
+        extras.putBundle(WebPaymentIntentHelper.EXTRA_SHIPPING_ADDRESS, addressBundle);
+        extras.putString(WebPaymentIntentHelper.EXTRA_RESPONSE_PAYER_NAME, "John Smith");
+        extras.putString(WebPaymentIntentHelper.EXTRA_RESPONSE_PAYER_PHONE, "4169158200");
+        extras.putString(WebPaymentIntentHelper.EXTRA_RESPONSE_PAYER_EMAIL, "JohnSmith@google.com");
+        extras.putString(WebPaymentIntentHelper.EXTRA_SHIPPING_OPTION_ID, "shippingId");
+
+        // Redact the entry with missingField key.
+        extras.remove(missingField);
+
+        intent.putExtras(extras);
+        return intent;
+    }
+
     // Test the happy path of createPayIntent and verify the non-deprecated extras.
     @Test
     @SmallTest
@@ -595,19 +622,136 @@
     @Test
     @SmallTest
     @Feature({"Payments"})
+    public void parsePaymentResponseMissingDetailsTest() throws Throwable {
+        Intent intent = createPaymentResponseWithMissingField(
+                WebPaymentIntentHelper.EXTRA_RESPONSE_DETAILS);
+        mErrorString = null;
+        WebPaymentIntentHelper.parsePaymentResponse(Activity.RESULT_OK, intent,
+                /*requestedPaymentOptions=*/null,
+                (errorString)
+                        -> mErrorString = errorString,
+                (methodName, details, payerData) -> Assert.fail("Parsing should fail."));
+        Assert.assertEquals(ErrorStrings.MISSING_DETAILS_FROM_PAYMENT_APP, mErrorString);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Payments"})
+    public void parsePaymentResponseMissingMethodNameTest() throws Throwable {
+        Intent intent = createPaymentResponseWithMissingField(
+                WebPaymentIntentHelper.EXTRA_RESPONSE_METHOD_NAME);
+        mErrorString = null;
+        WebPaymentIntentHelper.parsePaymentResponse(Activity.RESULT_OK, intent,
+                /*requestedPaymentOptions=*/null,
+                (errorString)
+                        -> mErrorString = errorString,
+                (methodName, details, payerData) -> Assert.fail("Parsing should fail."));
+        Assert.assertEquals(ErrorStrings.MISSING_METHOD_NAME_FROM_PAYMENT_APP, mErrorString);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Payments"})
+    public void parsePaymentResponseMissingShippingAddressTest() throws Throwable {
+        Intent intent = createPaymentResponseWithMissingField(
+                WebPaymentIntentHelper.EXTRA_SHIPPING_ADDRESS);
+        mErrorString = null;
+        WebPaymentIntentHelper.parsePaymentResponse(Activity.RESULT_OK, intent,
+                new PaymentOptions(/*requestPayerName=*/false, /*requestPayerEmail=*/false,
+                        /*requestPayerPhone=*/false, /*requestShipping=*/true,
+                        /*shippingType=*/"shipping"),
+                (errorString)
+                        -> mErrorString = errorString,
+                (methodName, details, payerData) -> Assert.fail("Parsing should fail."));
+        Assert.assertEquals(ErrorStrings.SHIPPING_ADDRESS_INVALID, mErrorString);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Payments"})
+    public void parsePaymentResponseMissingShippingOptionTest() throws Throwable {
+        Intent intent = createPaymentResponseWithMissingField(
+                WebPaymentIntentHelper.EXTRA_SHIPPING_OPTION_ID);
+        mErrorString = null;
+        WebPaymentIntentHelper.parsePaymentResponse(Activity.RESULT_OK, intent,
+                new PaymentOptions(/*requestPayerName=*/false, /*requestPayerEmail=*/false,
+                        /*requestPayerPhone=*/false, /*requestShipping=*/true,
+                        /*shippingType=*/"shipping"),
+                (errorString)
+                        -> mErrorString = errorString,
+                (methodName, details, payerData) -> Assert.fail("Parsing should fail."));
+        Assert.assertEquals(ErrorStrings.SHIPPING_OPTION_EMPTY, mErrorString);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Payments"})
+    public void parsePaymentResponseMissingPayerNameTest() throws Throwable {
+        Intent intent = createPaymentResponseWithMissingField(
+                WebPaymentIntentHelper.EXTRA_RESPONSE_PAYER_NAME);
+        mErrorString = null;
+        WebPaymentIntentHelper.parsePaymentResponse(Activity.RESULT_OK, intent,
+                new PaymentOptions(/*requestPayerName=*/true, /*requestPayerEmail=*/false,
+                        /*requestPayerPhone=*/false, /*requestShipping=*/false,
+                        /*shippingType=*/""),
+                (errorString)
+                        -> mErrorString = errorString,
+                (methodName, details, payerData) -> Assert.fail("Parsing should fail."));
+        Assert.assertEquals(ErrorStrings.PAYER_NAME_EMPTY, mErrorString);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Payments"})
+    public void parsePaymentResponseMissingPayerEmailTest() throws Throwable {
+        Intent intent = createPaymentResponseWithMissingField(
+                WebPaymentIntentHelper.EXTRA_RESPONSE_PAYER_EMAIL);
+        mErrorString = null;
+        WebPaymentIntentHelper.parsePaymentResponse(Activity.RESULT_OK, intent,
+                new PaymentOptions(/*requestPayerName=*/false, /*requestPayerEmail=*/true,
+                        /*requestPayerPhone=*/false, /*requestShipping=*/false,
+                        /*shippingType=*/""),
+                (errorString)
+                        -> mErrorString = errorString,
+                (methodName, details, payerData) -> Assert.fail("Parsing should fail."));
+        Assert.assertEquals(ErrorStrings.PAYER_EMAIL_EMPTY, mErrorString);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Payments"})
+    public void parsePaymentResponseMissingPayerPhoneTest() throws Throwable {
+        Intent intent = createPaymentResponseWithMissingField(
+                WebPaymentIntentHelper.EXTRA_RESPONSE_PAYER_PHONE);
+        mErrorString = null;
+        WebPaymentIntentHelper.parsePaymentResponse(Activity.RESULT_OK, intent,
+                new PaymentOptions(/*requestPayerName=*/false, /*requestPayerEmail=*/false,
+                        /*requestPayerPhone=*/true, /*requestShipping=*/false,
+                        /*shippingType=*/""),
+                (errorString)
+                        -> mErrorString = errorString,
+                (methodName, details, payerData) -> Assert.fail("Parsing should fail."));
+        Assert.assertEquals(ErrorStrings.PAYER_PHONE_EMPTY, mErrorString);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Payments"})
     public void parsePaymentResponseOKTest() throws Throwable {
         Intent intent = new Intent();
         Bundle extras = new Bundle();
         extras.putString(WebPaymentIntentHelper.EXTRA_RESPONSE_DETAILS, "\"key\":\"value\"}");
         extras.putString(WebPaymentIntentHelper.EXTRA_RESPONSE_METHOD_NAME, "maxPay");
-        extras.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_COUNTRY, "Canada");
+        Bundle addressBundle = new Bundle();
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_COUNTRY, "Canada");
         String[] addressLine = {"111 Richmond Street West"};
-        extras.putStringArray(WebPaymentIntentHelper.EXTRA_ADDRESS_LINES, addressLine);
-        extras.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_REGION, "Ontario");
-        extras.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_CITY, "Toronto");
-        extras.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_POSTAL_CODE, "M5H2G4");
-        extras.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_RECIPIENT, "John Smith");
-        extras.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_PHONE, "4169158200");
+        addressBundle.putStringArray(WebPaymentIntentHelper.EXTRA_ADDRESS_LINES, addressLine);
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_REGION, "Ontario");
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_CITY, "Toronto");
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_POSTAL_CODE, "M5H2G4");
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_RECIPIENT, "John Smith");
+        addressBundle.putString(WebPaymentIntentHelper.EXTRA_ADDRESS_PHONE, "4169158200");
+        extras.putBundle(WebPaymentIntentHelper.EXTRA_SHIPPING_ADDRESS, addressBundle);
         extras.putString(WebPaymentIntentHelper.EXTRA_RESPONSE_PAYER_NAME, "John Smith");
         extras.putString(WebPaymentIntentHelper.EXTRA_RESPONSE_PAYER_PHONE, "4169158200");
         extras.putString(WebPaymentIntentHelper.EXTRA_RESPONSE_PAYER_EMAIL, "JohnSmith@google.com");
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateUnitTest.java
index 9501f1b..5154287 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegateUnitTest.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.appmenu;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
 
@@ -62,6 +63,8 @@
     @Mock
     private TabModel mTabModel;
     @Mock
+    private TabModel mIncognitoTabModel;
+    @Mock
     private ToolbarManager mToolbarManager;
     @Mock
     private View mDecorView;
@@ -85,6 +88,10 @@
         when(mNavigationController.getUseDesktopUserAgent()).thenReturn(false);
         when(mToolbarManager.isMenuFromBottom()).thenReturn(false);
         when(mTabModelSelector.getCurrentModel()).thenReturn(mTabModel);
+        when(mTabModelSelector.getModel(false)).thenReturn((mTabModel));
+        when(mTabModelSelector.getModel(true)).thenReturn((mIncognitoTabModel));
+        when(mTabModel.isIncognito()).thenReturn(false);
+        when(mIncognitoTabModel.isIncognito()).thenReturn(true);
 
         mAppMenuPropertiesDelegate = Mockito.spy(new AppMenuPropertiesDelegateImpl(
                 ContextUtils.getApplicationContext(), mActivityTabProvider,
@@ -101,15 +108,6 @@
     }
 
     @Test
-    @Config(qualifiers = "sw320dp")
-    public void testShouldShowOverviewMenu_Phone() {
-        when(mOverviewModeBehavior.overviewVisible()).thenReturn(true);
-        Assert.assertFalse(mAppMenuPropertiesDelegate.shouldShowPageMenu());
-        Assert.assertEquals(
-                MenuGroup.OVERVIEW_MODE_MENU, mAppMenuPropertiesDelegate.getMenuGroup());
-    }
-
-    @Test
     @Config(qualifiers = "sw600dp")
     public void testShouldShowPageMenu_Tablet() {
         when(mOverviewModeBehavior.overviewVisible()).thenReturn(false);
@@ -129,13 +127,33 @@
     }
 
     @Test
+    @Config(qualifiers = "sw320dp")
+    public void testShouldShowIconRow_Phone() {
+        Assert.assertTrue(mAppMenuPropertiesDelegate.shouldShowIconRow());
+    }
+
+    @Test
     @Config(qualifiers = "sw600dp")
-    public void testShouldShowOverviewMenu_Tablet_NoTabs() {
-        when(mOverviewModeBehavior.overviewVisible()).thenReturn(false);
-        when(mTabModel.getCount()).thenReturn(0);
-        Assert.assertFalse(mAppMenuPropertiesDelegate.shouldShowPageMenu());
-        Assert.assertEquals(
-                MenuGroup.TABLET_EMPTY_MODE_MENU, mAppMenuPropertiesDelegate.getMenuGroup());
+    public void testShouldShowIconRow_Tablet() {
+        when(mDecorView.getWidth())
+                .thenReturn((int) (600
+                        * ContextUtils.getApplicationContext()
+                                  .getResources()
+                                  .getDisplayMetrics()
+                                  .density));
+        Assert.assertFalse(mAppMenuPropertiesDelegate.shouldShowIconRow());
+    }
+
+    @Test
+    @Config(qualifiers = "sw600dp")
+    public void testShouldShowIconRow_TabletNarrow() {
+        when(mDecorView.getWidth())
+                .thenReturn((int) (100
+                        * ContextUtils.getApplicationContext()
+                                  .getResources()
+                                  .getDisplayMetrics()
+                                  .density));
+        Assert.assertTrue(mAppMenuPropertiesDelegate.shouldShowIconRow());
     }
 
     @Test
@@ -156,13 +174,86 @@
         assertMenuItemsAreEqual(menu, expectedItems);
     }
 
+    @Test
+    @Config(qualifiers = "sw320dp")
+    public void testPageMenuItems_Phone_RegularPage() {
+        setUpMocksForPageMenu();
+        when(mTab.getUrlString()).thenReturn("https://google.com");
+        when(mTab.isNativePage()).thenReturn(false);
+        doReturn(false)
+                .when(mAppMenuPropertiesDelegate)
+                .shouldShowPaintPreview(anyBoolean(), any(Tab.class), anyBoolean());
+        doReturn(true).when(mAppMenuPropertiesDelegate).shouldShowTranslateMenuItem(any(Tab.class));
+        doReturn(R.string.menu_add_to_homescreen)
+                .when(mAppMenuPropertiesDelegate)
+                .getAddToHomeScreenTitle();
+
+        Assert.assertEquals(MenuGroup.PAGE_MENU, mAppMenuPropertiesDelegate.getMenuGroup());
+        Menu menu = createTestMenu();
+        mAppMenuPropertiesDelegate.prepareMenu(menu, null);
+
+        Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.new_tab_menu_id,
+                R.id.new_incognito_tab_menu_id, R.id.all_bookmarks_menu_id,
+                R.id.recent_tabs_menu_id, R.id.open_history_menu_id, R.id.downloads_menu_id,
+                R.id.translate_id, R.id.share_row_menu_id, R.id.find_in_page_id,
+                R.id.add_to_homescreen_id, R.id.request_desktop_site_row_menu_id,
+                R.id.preferences_id, R.id.help_id};
+        assertMenuItemsAreEqual(menu, expectedItems);
+    }
+
+    @Test
+    @Config(qualifiers = "sw320dp")
+    public void testOverviewMenuItems_Phone() {
+        setUpMocksForOverviewMenu();
+        when(mIncognitoTabModel.getCount()).thenReturn(0);
+
+        Assert.assertFalse(mAppMenuPropertiesDelegate.shouldShowPageMenu());
+        Assert.assertEquals(
+                MenuGroup.OVERVIEW_MODE_MENU, mAppMenuPropertiesDelegate.getMenuGroup());
+
+        Menu menu = createTestMenu();
+        mAppMenuPropertiesDelegate.prepareMenu(menu, null);
+
+        Integer[] expectedItems = {R.id.new_tab_menu_id, R.id.new_incognito_tab_menu_id,
+                R.id.close_all_tabs_menu_id, R.id.preferences_id};
+        assertMenuItemsAreEqual(menu, expectedItems);
+    }
+
+    @Test
+    @Config(qualifiers = "sw600dp")
+    public void testOverviewMenuItems_Tablet_NoTabs() {
+        setUpIncognitoMocks();
+        when(mOverviewModeBehavior.overviewVisible()).thenReturn(false);
+        when(mTabModel.getCount()).thenReturn(0);
+
+        Assert.assertEquals(
+                MenuGroup.TABLET_EMPTY_MODE_MENU, mAppMenuPropertiesDelegate.getMenuGroup());
+        Assert.assertFalse(mAppMenuPropertiesDelegate.shouldShowPageMenu());
+
+        Menu menu = createTestMenu();
+        mAppMenuPropertiesDelegate.prepareMenu(menu, null);
+
+        Integer[] expectedItems = {
+                R.id.new_tab_menu_id, R.id.new_incognito_tab_menu_id, R.id.preferences_id};
+        assertMenuItemsAreEqual(menu, expectedItems);
+    }
+
     private void setUpMocksForPageMenu() {
         when(mActivityTabProvider.get()).thenReturn(mTab);
         when(mOverviewModeBehavior.overviewVisible()).thenReturn(false);
-        when(mTabModel.isIncognito()).thenReturn(false);
         doReturn(false).when(mAppMenuPropertiesDelegate).shouldCheckBookmarkStar(any(Tab.class));
         doReturn(false).when(mAppMenuPropertiesDelegate).shouldEnableDownloadPage(any(Tab.class));
         doReturn(false).when(mAppMenuPropertiesDelegate).shouldShowReaderModePrefs(any(Tab.class));
+        setUpIncognitoMocks();
+    }
+
+    private void setUpMocksForOverviewMenu() {
+        when(mOverviewModeBehavior.overviewVisible()).thenReturn(true);
+        when(mTabModelSelector.getTotalTabCount()).thenReturn(1);
+        setUpIncognitoMocks();
+    }
+
+    private void setUpIncognitoMocks() {
         doReturn(true).when(mAppMenuPropertiesDelegate).isIncognitoEnabled();
         doReturn(false).when(mAppMenuPropertiesDelegate).isIncognitoManaged();
     }
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index e8ed41d..c3cae3ed 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -231,6 +231,23 @@
     System text is shown in this language
   </message>
 
+  <!-- Smart Inputs Section -->
+  <message name="IDS_SETTINGS_SMART_INPUTS_TITLE" desc="The label for the smart inputs section, which contains features to help users type faster or more expressively such as suggesting personal information or suggesting emoji to use.">
+    Smart inputs
+  </message>
+  <message name="IDS_SETTINGS_SMART_INPUTS_PERSONAL_INFO_TITLE" desc="The label for personal information suggestion section.">
+    Personal information suggestions
+  </message>
+  <message name="IDS_SETTINGS_SMART_INPUTS_PERSONAL_INFO_DESCRIPTION" desc="The description for personal information suggestion section.">
+    Personal information suggestions help you write faster by suggesting your name, address or phone number when you type some specific words. Only you see your own private, personalized suggestions for your account.
+  </message>
+  <message name="IDS_SETTINGS_SMART_INPUTS_SHOW_PERSONAL_INFO" desc="The label for the toggle button controlling showing personal information suggestions.">
+    Show input personal information suggestions
+  </message>
+  <message name="IDS_SETTINGS_SMART_INPUTS_MANAGE_PERSONAL_INFO" desc="The label for opening Chrome's browser settings page for managing personal addresses">
+    Manage personal information
+  </message>
+
   <!-- Device Page (OS Settings) -->
   <message name="IDS_OS_SETTINGS_TOUCHPAD_REVERSE_SCROLL_LABEL">
     Reverse scrolling <ph name="LINK_BEGIN">&lt;a&gt;</ph>Learn more<ph name="LINK_END">&lt;/a&gt;</ph>
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_MANAGE_PERSONAL_INFO.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_MANAGE_PERSONAL_INFO.png.sha1
new file mode 100644
index 0000000..729717c1
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_MANAGE_PERSONAL_INFO.png.sha1
@@ -0,0 +1 @@
+00668dc066697ae5495e6f014b2b537e19d01968
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_PERSONAL_INFO_DESCRIPTION.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_PERSONAL_INFO_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..eb74e2c
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_PERSONAL_INFO_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+e958f3cbebd3520e82f51986c61fc4985ae14f94
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_PERSONAL_INFO_TITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_PERSONAL_INFO_TITLE.png.sha1
new file mode 100644
index 0000000..4aa79e4
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_PERSONAL_INFO_TITLE.png.sha1
@@ -0,0 +1 @@
+f3b9202b9cc8da0fde1045ca3d5c9fd48cdeb7d3
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_SHOW_PERSONAL_INFO.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_SHOW_PERSONAL_INFO.png.sha1
new file mode 100644
index 0000000..f3c2099d
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_SHOW_PERSONAL_INFO.png.sha1
@@ -0,0 +1 @@
+8ec56ee81850db8fb7eed35985e27d3bab1b8708
\ No newline at end of file
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_TITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_TITLE.png.sha1
new file mode 100644
index 0000000..2216622
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_SMART_INPUTS_TITLE.png.sha1
@@ -0,0 +1 @@
+94652a66acbbe7508cf91cc96f6d084d82aa2aaf
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index ef07679..eb264ff9 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -290,8 +290,6 @@
     "chrome_notification_types.h",
     "chrome_resource_bundle_helper.cc",
     "chrome_resource_bundle_helper.h",
-    "client_hints/client_hints.cc",
-    "client_hints/client_hints.h",
     "client_hints/client_hints_factory.cc",
     "client_hints/client_hints_factory.h",
     "clipboard/clipboard_read_write_permission_context.cc",
@@ -2035,6 +2033,7 @@
     "//components/captive_portal/core:buildflags",
     "//components/certificate_matching",
     "//components/certificate_transparency",
+    "//components/client_hints/browser",
     "//components/cloud_devices/common",
     "//components/component_updater",
     "//components/component_updater:crl_set_remover",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index b6d3b72..0d4ea0c4 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -57,6 +57,7 @@
   "+components/chrome_cleaner/public",
   "+components/chrome_cleaner/test",
   "+components/chromeos_camera",
+  "+components/client_hints/browser",
   "+components/cloud_devices/common",
   "+components/component_updater",
   "+components/component_updater/installer_policies",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b6b857e..b28a6ff 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3359,13 +3359,6 @@
      flag_descriptions::kPrefetchPrivacyChangesDescription, kOsAll,
      FEATURE_VALUE_TYPE(blink::features::kPrefetchPrivacyChanges)},
 
-    {"prefetch-main-resource-network-isolation-key",
-     flag_descriptions::kPrefetchMainResourceNetworkIsolationKeyName,
-     flag_descriptions::kPrefetchMainResourceNetworkIsolationKeyDescription,
-     kOsAll,
-     FEATURE_VALUE_TYPE(
-         network::features::kPrefetchMainResourceNetworkIsolationKey)},
-
 #if defined(OS_ANDROID)
     {"omnibox-spare-renderer", flag_descriptions::kOmniboxSpareRendererName,
      flag_descriptions::kOmniboxSpareRendererDescription, kOsAndroid,
diff --git a/chrome/browser/autofill/autofill_uitest.cc b/chrome/browser/autofill/autofill_uitest.cc
index 6623fec6..7d1068b58 100644
--- a/chrome/browser/autofill/autofill_uitest.cc
+++ b/chrome/browser/autofill/autofill_uitest.cc
@@ -78,6 +78,9 @@
                          /* new_host = */ GetWebContents()->GetMainFrame());
   Observe(GetWebContents());
 
+  disable_animation_ = std::make_unique<ui::ScopedAnimationDurationScaleMode>(
+      ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+
   // If the mouse happened to be over where the suggestions are shown, then
   // the preview will show up and will fail the tests. We need to give it a
   // point that's within the browser frame, or else the method hangs.
diff --git a/chrome/browser/autofill/autofill_uitest.h b/chrome/browser/autofill/autofill_uitest.h
index 7dcbd09..9062172f 100644
--- a/chrome/browser/autofill/autofill_uitest.h
+++ b/chrome/browser/autofill/autofill_uitest.h
@@ -16,6 +16,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/events/keycodes/dom/dom_key.h"
 #include "ui/events/keycodes/keyboard_code_conversion.h"
 #include "ui/events/keycodes/keyboard_codes.h"
@@ -114,6 +115,8 @@
   // with it.
   content::RenderWidgetHost::KeyPressEventCallback key_press_event_sink_;
 
+  std::unique_ptr<ui::ScopedAnimationDurationScaleMode> disable_animation_;
+
   DISALLOW_COPY_AND_ASSIGN(AutofillUiTest);
 };
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 82980a63..2cdc9273 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2124,6 +2124,8 @@
     "printing/cups_print_job_notification.h",
     "printing/cups_print_job_notification_manager.cc",
     "printing/cups_print_job_notification_manager.h",
+    "printing/cups_printer_status_creator.cc",
+    "printing/cups_printer_status_creator.h",
     "printing/cups_printers_manager.cc",
     "printing/cups_printers_manager.h",
     "printing/cups_printers_manager_factory.cc",
@@ -3096,6 +3098,7 @@
     "printing/automatic_usb_printer_configurer_unittest.cc",
     "printing/bulk_printers_calculator_unittest.cc",
     "printing/calculators_policies_binder_unittest.cc",
+    "printing/cups_printer_status_creator_unittest.cc",
     "printing/cups_printers_manager_unittest.cc",
     "printing/enterprise_printers_provider_unittest.cc",
     "printing/history/mock_print_job_history_service.cc",
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index fc94885..f961eac 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -71,6 +71,8 @@
 #include "chrome/browser/chromeos/guest_os/guest_os_registry_service.h"
 #include "chrome/browser/chromeos/guest_os/guest_os_registry_service_factory.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
+#include "chrome/browser/chromeos/plugin_vm/plugin_vm_installer.h"
+#include "chrome/browser/chromeos/plugin_vm/plugin_vm_installer_factory.h"
 #include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
 #include "chrome/browser/chromeos/printing/cups_printers_manager.h"
 #include "chrome/browser/chromeos/settings/stats_reporting_controller.h"
@@ -1836,8 +1838,12 @@
            << ", " << params->image_hash << ", " << params->license_key;
 
   Profile* profile = Profile::FromBrowserContext(browser_context());
+  plugin_vm::PluginVmInstallerFactory::GetForProfile(profile)
+      ->SetFreeDiskSpaceForTesting(
+          plugin_vm::PluginVmInstaller::kRecommendedFreeDiskSpace);
   plugin_vm::SetFakePluginVmPolicy(profile, params->image_url,
                                    params->image_hash, params->license_key);
+
   plugin_vm::ShowPluginVmInstallerView(profile);
   PluginVmInstallerView::GetActiveViewForTesting()
       ->SetFinishedCallbackForTesting(base::BindOnce(
diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc
index bd516d9..e34a8a51 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.cc
+++ b/chrome/browser/chromeos/login/app_launch_controller.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/chromeos/login/app_launch_controller.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
@@ -27,7 +26,6 @@
 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
 #include "chrome/browser/chromeos/login/enterprise_user_session_metrics.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
-#include "chrome/browser/chromeos/login/ui/webui_login_view.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
@@ -167,18 +165,7 @@
 
   RecordKioskLaunchUMA(is_auto_launch);
 
-  // Ensure WebUILoginView is enabled so that bailout shortcut key works.
-  if (ash::features::IsViewsLoginEnabled()) {
-    host_->GetLoginDisplay()->SetUIEnabled(true);
-    login_screen_visible_ = true;
-  } else {
-    host_->GetWebUILoginView()->SetUIEnabled(true);
-    login_screen_visible_ = host_->GetWebUILoginView()->webui_visible();
-    if (!login_screen_visible_) {
-      registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
-                     content::NotificationService::AllSources());
-    }
-  }
+  host_->GetLoginDisplay()->SetUIEnabled(true);
 
   launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
 
@@ -271,17 +258,6 @@
   signin_screen_.reset();
 }
 
-void AppLaunchController::Observe(int type,
-                                  const content::NotificationSource& source,
-                                  const content::NotificationDetails& details) {
-  DCHECK_EQ(chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, type);
-  DCHECK(!login_screen_visible_);
-  login_screen_visible_ = true;
-  launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
-  if (launcher_ready_)
-    OnReadyToLaunch();
-}
-
 void AppLaunchController::OnCancelAppLaunch() {
   if (KioskAppManager::Get()->GetDisableBailoutShortcut())
     return;
@@ -519,9 +495,6 @@
   if (network_config_requested_)
     return;
 
-  if (!login_screen_visible_)
-    return;
-
   if (splash_wait_timer_.IsRunning())
     return;
 
diff --git a/chrome/browser/chromeos/login/app_launch_controller.h b/chrome/browser/chromeos/login/app_launch_controller.h
index 034a45cb6..4015003e 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.h
+++ b/chrome/browser/chromeos/login/app_launch_controller.h
@@ -18,8 +18,6 @@
 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
 #include "chrome/browser/chromeos/login/app_launch_signin_screen.h"
 #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 
 class Profile;
 
@@ -35,8 +33,7 @@
 class AppLaunchController : public KioskProfileLoader::Delegate,
                             public StartupAppLauncher::Delegate,
                             public AppLaunchSigninScreen::Delegate,
-                            public AppLaunchSplashScreenView::Delegate,
-                            public content::NotificationObserver {
+                            public AppLaunchSplashScreenView::Delegate {
  public:
   typedef base::Callback<bool()> ReturnBoolCallback;
 
@@ -116,11 +113,6 @@
   // AppLaunchSigninScreen::Delegate overrides:
   void OnOwnerSigninSuccess() override;
 
-  // content::NotificationObserver overrides:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
   Profile* profile_ = nullptr;
   const std::string app_id_;
   const bool diagnostic_mode_;
@@ -132,8 +124,6 @@
   std::unique_ptr<AppLaunchSigninScreen> signin_screen_;
   std::unique_ptr<AppWindowWatcher> app_window_watcher_;
 
-  content::NotificationRegistrar registrar_;
-  bool login_screen_visible_ = false;
   bool launcher_ready_ = false;
   bool cleaned_up_ = false;
 
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 933ea42..7fb4cfa 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -171,8 +171,6 @@
     ash::switches::kAuraLegacyPowerButton,
     ash::switches::kEnableDimShelf,
     ash::switches::kShowTaps,
-    ash::switches::kShowWebUiLock,
-    ash::switches::kShowWebUiLogin,
     chromeos::switches::kDefaultWallpaperLarge,
     chromeos::switches::kDefaultWallpaperSmall,
     chromeos::switches::kGuestWallpaperLarge,
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index 9d9cb7b1..cbe7fca 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -7,7 +7,6 @@
 #include <string>
 #include <utility>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/login_screen_test_api.h"
 #include "base/base64.h"
 #include "base/bind.h"
@@ -1716,7 +1715,6 @@
 // pages is controlled by the kLoginVideoCaptureAllowedUrls pref rather than the
 // underlying user content setting.
 IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, TestLoginMediaPermission) {
-  EXPECT_TRUE(ash::features::IsViewsLoginEnabled());
   fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
 
   const GURL url1("https://google.com");
diff --git a/chrome/browser/chromeos/login/screens/base_screen.cc b/chrome/browser/chromeos/login/screens/base_screen.cc
index 0c2be62..ca087c6 100644
--- a/chrome/browser/chromeos/login/screens/base_screen.cc
+++ b/chrome/browser/chromeos/login/screens/base_screen.cc
@@ -26,14 +26,10 @@
   is_hidden_ = true;
 }
 
-bool BaseScreen::ShouldSkipScreen() {
+bool BaseScreen::MaybeSkip() {
   return false;
 }
 
-void BaseScreen::Skip() {
-  NOTREACHED() << "Skip methog should be overriden along with ShouldSkipScreen";
-}
-
 void BaseScreen::HandleUserAction(const std::string& action_id) {
   if (is_hidden_) {
     LOG(WARNING) << "User action came when screen is hidden: action_id="
diff --git a/chrome/browser/chromeos/login/screens/base_screen.h b/chrome/browser/chromeos/login/screens/base_screen.h
index 98bedfd..8aeddeb 100644
--- a/chrome/browser/chromeos/login/screens/base_screen.h
+++ b/chrome/browser/chromeos/login/screens/base_screen.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "chrome/browser/chromeos/login/oobe_screen.h"
@@ -35,11 +36,8 @@
   void Hide();
 
   // Returns whether the screen should be skipped i. e. should be exited due to
-  // specific unmet conditions. Override along with Skip method.
-  virtual bool ShouldSkipScreen();
-
-  // Skips the screen. Override along with ShouldSkipScreen method.
-  virtual void Skip();
+  // specific unmet conditions. Returns true if skips the screen.
+  virtual bool MaybeSkip() WARN_UNUSED_RESULT;
 
   // Forwards user action if screen is shown.
   void HandleUserAction(const std::string& action_id);
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc b/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc
index 9064f36..11369db 100644
--- a/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc
+++ b/chrome/browser/chromeos/login/screens/recommend_apps_screen.cc
@@ -58,7 +58,7 @@
   view_ = nullptr;
 }
 
-bool RecommendAppsScreen::ShouldSkipScreen() {
+bool RecommendAppsScreen::MaybeSkip() {
   const user_manager::UserManager* user_manager =
       user_manager::UserManager::Get();
   DCHECK(user_manager->IsUserLoggedIn());
@@ -66,12 +66,11 @@
                                 ->GetProfilePolicyConnector()
                                 ->IsManaged();
   bool is_child_account = user_manager->IsLoggedInAsChildUser();
-  return is_managed_account || is_child_account;
-}
-
-void RecommendAppsScreen::Skip() {
-  DCHECK(ShouldSkipScreen());
-  exit_callback_.Run(Result::NOT_APPLICABLE);
+  if (is_managed_account || is_child_account) {
+    exit_callback_.Run(Result::NOT_APPLICABLE);
+    return true;
+  }
+  return false;
 }
 
 void RecommendAppsScreen::ShowImpl() {
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps_screen.h b/chrome/browser/chromeos/login/screens/recommend_apps_screen.h
index 9f49500..759c37a 100644
--- a/chrome/browser/chromeos/login/screens/recommend_apps_screen.h
+++ b/chrome/browser/chromeos/login/screens/recommend_apps_screen.h
@@ -54,8 +54,7 @@
   void OnParseResponseError() override;
 
   // BaseScreen:
-  bool ShouldSkipScreen() override;
-  void Skip() override;
+  bool MaybeSkip() override;
 
  private:
   // BaseScreen:
diff --git a/chrome/browser/chromeos/login/test/scoped_policy_update.h b/chrome/browser/chromeos/login/test/scoped_policy_update.h
index 21187bc..0954b79c 100644
--- a/chrome/browser/chromeos/login/test/scoped_policy_update.h
+++ b/chrome/browser/chromeos/login/test/scoped_policy_update.h
@@ -28,6 +28,12 @@
     return &policy_builder_->payload();
   }
 
+  // Accessor to the PolicyData message (will contain serialized
+  // policy_payload() among other things).
+  enterprise_management::PolicyData* policy_data() {
+    return &policy_builder_->policy_data();
+  }
+
  private:
   policy::UserPolicyBuilder* const policy_builder_;
   base::OnceClosure callback_;
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
index 67bc418..6c85c3cf 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "ash/accessibility/focus_ring_controller.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/locale_update_controller.h"
 #include "ash/public/cpp/login_screen.h"
 #include "ash/public/cpp/login_screen_model.h"
@@ -197,8 +196,7 @@
   if (chromeos::LoginDisplayHost::default_host()) {
     // Tests may have already allocated an instance for us to use.
     display_host = chromeos::LoginDisplayHost::default_host();
-  } else if (ash::features::IsViewsLoginEnabled() &&
-             ShouldShowSigninScreen(first_screen)) {
+  } else if (ShouldShowSigninScreen(first_screen)) {
     display_host = new chromeos::LoginDisplayHostMojo();
   } else {
     display_host = new chromeos::LoginDisplayHostWebUI();
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 5cacb52c1..c75cc91 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -1409,10 +1409,8 @@
   if (current_screen_ == new_current || GetOobeUI() == nullptr)
     return;
 
-  if (new_current && new_current->ShouldSkipScreen()) {
-    new_current->Skip();
+  if (new_current && new_current->MaybeSkip())
     return;
-  }
 
   if (current_screen_) {
     current_screen_->Hide();
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service_browsertest.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service_browsertest.cc
new file mode 100644
index 0000000..eb9c2d6
--- /dev/null
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service_browsertest.cc
@@ -0,0 +1,298 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/containers/span.h"
+#include "base/location.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/task/post_task.h"
+#include "chrome/browser/chromeos/login/test/device_state_mixin.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
+#include "chrome/browser/chromeos/login/test/scoped_policy_update.h"
+#include "chrome/browser/chromeos/login/test/user_policy_mixin.h"
+#include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
+#include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.h"
+#include "chrome/browser/policy/policy_test_utils.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/mixin_based_in_process_browser_test.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chromeos/constants/chromeos_switches.h"
+#include "chromeos/login/auth/user_context.h"
+#include "components/policy/core/common/cloud/policy_builder.h"
+#include "components/policy/core/common/policy_switches.h"
+#include "components/signin/public/identity_manager/identity_test_utils.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "crypto/signature_verifier.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace platform_keys {
+namespace {
+
+constexpr char kTestUserEmail[] = "test@example.com";
+constexpr char kTestAffiliationId[] = "test_affiliation_id";
+
+enum class ProfileToUse {
+  // A Profile that belongs to a user that is not affiliated with the device (no
+  // access to the system token).
+  kUnaffiliatedUserProfile,
+  // A Profile that belongs to a user that is affiliated with the device (access
+  // to the system token).
+  kAffiliatedUserProfile,
+  // The sign-in screen profile.
+  kSigninProfile
+};
+
+// Describes a test configuration for the test suite.
+struct TestConfig {
+  // The profile for which PlatformKeysService should be tested.
+  ProfileToUse profile_to_use;
+
+  // The token IDs that are expected to be available. This will be checked by
+  // the GetTokens test, and operation for these tokens will be performed by the
+  // other tests.
+  std::vector<std::string> token_ids;
+};
+
+// A helper that waits until execution of an asynchronous PlatformKeysService
+// operation has finished and provides access to the results.
+// Note: all PlatformKeysService operations have a trailing const std::string&
+// error_message argument that is filled in case of an error.
+template <typename... ResultCallbackArgs>
+class ExecutionWaiter {
+ public:
+  ExecutionWaiter() = default;
+  ~ExecutionWaiter() = default;
+  ExecutionWaiter(const ExecutionWaiter& other) = delete;
+  ExecutionWaiter& operator=(const ExecutionWaiter& other) = delete;
+
+  // Returns the callback to be passed to the PlatformKeysService operation
+  // invocation.
+  base::RepeatingCallback<void(ResultCallbackArgs... result_callback_args,
+                               const std::string& error_message)>
+  GetCallback() {
+    return base::BindRepeating(&ExecutionWaiter::OnExecutionDone,
+                               weak_ptr_factory_.GetWeakPtr());
+  }
+
+  // Waits until the callback returned by GetCallback() has been called.
+  void Wait() { run_loop_.Run(); }
+
+  // Returns the error message passed to the callback.
+  const std::string& error_message() {
+    EXPECT_TRUE(done_);
+    return error_message_;
+  }
+
+ protected:
+  // A std::tuple that is capable of storing the arguments passed to the result
+  // callback.
+  using ResultCallbackArgsTuple =
+      std::tuple<std::decay_t<ResultCallbackArgs>...>;
+
+  // Access to the arguments passed to the callback.
+  const ResultCallbackArgsTuple& result_callback_args() const {
+    EXPECT_TRUE(done_);
+    return result_callback_args_;
+  }
+
+ private:
+  void OnExecutionDone(ResultCallbackArgs... result_callback_args,
+                       const std::string& error_message) {
+    EXPECT_FALSE(done_);
+    done_ = true;
+    result_callback_args_ = ResultCallbackArgsTuple(
+        std::forward<ResultCallbackArgs>(result_callback_args)...);
+    error_message_ = error_message;
+    run_loop_.Quit();
+  }
+
+  base::RunLoop run_loop_;
+  bool done_ = false;
+  ResultCallbackArgsTuple result_callback_args_;
+  std::string error_message_;
+
+  base::WeakPtrFactory<ExecutionWaiter> weak_ptr_factory_{this};
+};
+
+// Supports waiting for the result of PlatformKeysService::GetTokens.
+class GetTokensExecutionWaiter
+    : public ExecutionWaiter<std::unique_ptr<std::vector<std::string>>> {
+ public:
+  GetTokensExecutionWaiter() = default;
+  ~GetTokensExecutionWaiter() = default;
+
+  const std::unique_ptr<std::vector<std::string>>& token_ids() const {
+    return std::get<0>(result_callback_args());
+  }
+};
+
+// Supports waiting for the result of the PlatformKeysService::GenerateKey*
+// function family.
+class GenerateKeyExecutionWaiter : public ExecutionWaiter<const std::string&> {
+ public:
+  GenerateKeyExecutionWaiter() = default;
+  ~GenerateKeyExecutionWaiter() = default;
+
+  const std::string& public_key_spki_der() const {
+    return std::get<0>(result_callback_args());
+  }
+};
+
+// Supports waiting for the result of the PlatformKeysService::Sign* function
+// family.
+class SignExecutionWaiter : public ExecutionWaiter<const std::string&> {
+ public:
+  SignExecutionWaiter() = default;
+  ~SignExecutionWaiter() = default;
+
+  const std::string& signature() const {
+    return std::get<0>(result_callback_args());
+  }
+};
+}  // namespace
+
+class PlatformKeysServiceBrowserTest
+    : public MixinBasedInProcessBrowserTest,
+      public ::testing::WithParamInterface<TestConfig> {
+ public:
+  PlatformKeysServiceBrowserTest() = default;
+  ~PlatformKeysServiceBrowserTest() override = default;
+  PlatformKeysServiceBrowserTest(const PlatformKeysServiceBrowserTest& other) =
+      delete;
+  PlatformKeysServiceBrowserTest& operator=(
+      const PlatformKeysServiceBrowserTest& other) = delete;
+
+  void SetUpInProcessBrowserTestFixture() override {
+    MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+
+    // Call |Request*PolicyUpdate| even if not setting affiliation IDs so
+    // (empty) policy blobs are prepared in FakeSessionManagerClient.
+    auto user_policy_update = user_policy_mixin_.RequestPolicyUpdate();
+    auto device_policy_update = device_state_mixin_.RequestDevicePolicyUpdate();
+    if (GetParam().profile_to_use == ProfileToUse::kAffiliatedUserProfile) {
+      device_policy_update->policy_data()->add_device_affiliation_ids(
+          kTestAffiliationId);
+      user_policy_update->policy_data()->add_user_affiliation_ids(
+          kTestAffiliationId);
+    }
+  }
+
+  void SetUpOnMainThread() override {
+    MixinBasedInProcessBrowserTest::SetUpOnMainThread();
+
+    if (GetParam().profile_to_use == ProfileToUse::kSigninProfile) {
+      profile_ = ProfileHelper::GetSigninProfile();
+    } else {
+      ASSERT_TRUE(login_manager_mixin_.LoginAndWaitForActiveSession(
+          LoginManagerMixin::CreateDefaultUserContext(test_user_info_)));
+      profile_ = ProfileManager::GetActiveUserProfile();
+    }
+    ASSERT_TRUE(profile_);
+
+    platform_keys_service_ =
+        PlatformKeysServiceFactory::GetForBrowserContext(profile_);
+    ASSERT_TRUE(platform_keys_service_);
+  }
+
+ protected:
+  PlatformKeysService* platform_keys_service() {
+    return platform_keys_service_;
+  }
+
+ private:
+  const AccountId test_user_account_id_ = AccountId::FromUserEmailGaiaId(
+      kTestUserEmail,
+      signin::GetTestGaiaIdForEmail(kTestUserEmail));
+  const LoginManagerMixin::TestUserInfo test_user_info_{test_user_account_id_};
+
+  ScopedTestSystemNSSKeySlotMixin system_nss_key_slot_mixin_{&mixin_host_};
+  LoginManagerMixin login_manager_mixin_{&mixin_host_, {test_user_info_}};
+
+  DeviceStateMixin device_state_mixin_{
+      &mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
+  UserPolicyMixin user_policy_mixin_{&mixin_host_, test_user_account_id_};
+
+  // Unowned pointer to the profile selected by the current TestConfig.
+  // Valid after SetUpOnMainThread().
+  Profile* profile_ = nullptr;
+  // Unowned pointer to the PlatformKeysService for |profile_|. Valid after
+  // SetUpOnMainThread().
+  PlatformKeysService* platform_keys_service_ = nullptr;
+};
+
+// Tests that GetTokens() is callable and returns the expected tokens.
+IN_PROC_BROWSER_TEST_P(PlatformKeysServiceBrowserTest, GetTokens) {
+  GetTokensExecutionWaiter get_tokens_waiter;
+  platform_keys_service()->GetTokens(get_tokens_waiter.GetCallback());
+  get_tokens_waiter.Wait();
+
+  EXPECT_TRUE(get_tokens_waiter.error_message().empty());
+  ASSERT_TRUE(get_tokens_waiter.token_ids());
+  EXPECT_THAT(*get_tokens_waiter.token_ids(),
+              ::testing::UnorderedElementsAreArray(GetParam().token_ids));
+}
+
+// Generates a Rsa key pair and tests signing using that key pair.
+IN_PROC_BROWSER_TEST_P(PlatformKeysServiceBrowserTest, GenerateRsaAndSign) {
+  const std::string data_to_sign = "test";
+  const unsigned int key_size = 2048;
+  const HashAlgorithm hash_algorithm = HASH_ALGORITHM_SHA256;
+  const crypto::SignatureVerifier::SignatureAlgorithm signature_algorithm =
+      crypto::SignatureVerifier::RSA_PKCS1_SHA256;
+
+  for (const std::string& token_id : GetParam().token_ids) {
+    GenerateKeyExecutionWaiter generate_key_waiter;
+    platform_keys_service()->GenerateRSAKey(token_id, key_size,
+                                            generate_key_waiter.GetCallback());
+    generate_key_waiter.Wait();
+    EXPECT_TRUE(generate_key_waiter.error_message().empty());
+
+    const std::string public_key_spki_der =
+        generate_key_waiter.public_key_spki_der();
+    EXPECT_FALSE(public_key_spki_der.empty());
+
+    SignExecutionWaiter sign_waiter;
+    platform_keys_service()->SignRSAPKCS1Digest(
+        token_id, data_to_sign, public_key_spki_der, hash_algorithm,
+        sign_waiter.GetCallback());
+    sign_waiter.Wait();
+    EXPECT_TRUE(sign_waiter.error_message().empty());
+
+    crypto::SignatureVerifier signature_verifier;
+    ASSERT_TRUE(signature_verifier.VerifyInit(
+        signature_algorithm,
+        base::as_bytes(base::make_span(sign_waiter.signature())),
+        base::as_bytes(base::make_span(public_key_spki_der))));
+    signature_verifier.VerifyUpdate(
+        base::as_bytes(base::make_span(data_to_sign)));
+    EXPECT_TRUE(signature_verifier.VerifyFinal());
+  }
+}
+
+// TODO(https://crbug.com/1067591): Enable for sign-in screen by adding
+// ProfileToUse::kSigninProfile.
+INSTANTIATE_TEST_SUITE_P(
+    AllSupportedProfileTypes,
+    PlatformKeysServiceBrowserTest,
+    ::testing::Values(
+        TestConfig{ProfileToUse::kSigninProfile, {"system"}},
+        TestConfig{ProfileToUse::kUnaffiliatedUserProfile, {"user"}},
+        TestConfig{ProfileToUse::kAffiliatedUserProfile, {"user", "system"}}));
+
+}  // namespace platform_keys
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/cups_printer_status_creator.cc b/chrome/browser/chromeos/printing/cups_printer_status_creator.cc
new file mode 100644
index 0000000..a3b095d
--- /dev/null
+++ b/chrome/browser/chromeos/printing/cups_printer_status_creator.cc
@@ -0,0 +1,98 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/printing/cups_printer_status_creator.h"
+
+namespace chromeos {
+
+using CupsReason = CupsPrinterStatus::CupsPrinterStatusReason::Reason;
+using CupsSeverity = CupsPrinterStatus::CupsPrinterStatusReason::Severity;
+using ReasonFromPrinter = printing::PrinterStatus::PrinterReason::Reason;
+using SeverityFromPrinter = printing::PrinterStatus::PrinterReason::Severity;
+
+CupsPrinterStatus PrinterStatusToCupsPrinterStatus(
+    const std::string& printer_id,
+    const printing::PrinterStatus& printer_status) {
+  CupsPrinterStatus cups_printer_status(printer_id);
+
+  for (const auto& reason : printer_status.reasons) {
+    cups_printer_status.AddStatusReason(
+        PrinterReasonToCupsReason(reason.reason),
+        PrinterSeverityToCupsSeverity(reason.severity));
+  }
+
+  return cups_printer_status;
+}
+
+CupsReason PrinterReasonToCupsReason(const ReasonFromPrinter& reason) {
+  switch (reason) {
+    case ReasonFromPrinter::CONNECTING_TO_DEVICE:
+      return CupsReason::kConnectingToDevice;
+    case ReasonFromPrinter::FUSER_OVER_TEMP:
+    case ReasonFromPrinter::FUSER_UNDER_TEMP:
+    case ReasonFromPrinter::INTERPRETER_RESOURCE_UNAVAILABLE:
+    case ReasonFromPrinter::OPC_LIFE_OVER:
+    case ReasonFromPrinter::OPC_NEAR_EOL:
+      return CupsReason::kDeviceError;
+    case ReasonFromPrinter::COVER_OPEN:
+    case ReasonFromPrinter::DOOR_OPEN:
+    case ReasonFromPrinter::INTERLOCK_OPEN:
+      return CupsReason::kDoorOpen;
+    case ReasonFromPrinter::DEVELOPER_LOW:
+    case ReasonFromPrinter::MARKER_SUPPLY_LOW:
+    case ReasonFromPrinter::MARKER_WASTE_ALMOST_FULL:
+    case ReasonFromPrinter::TONER_LOW:
+      return CupsReason::kLowOnInk;
+    case ReasonFromPrinter::MEDIA_LOW:
+      return CupsReason::kLowOnPaper;
+    case ReasonFromPrinter::NONE:
+      return CupsReason::kNoError;
+    case ReasonFromPrinter::DEVELOPER_EMPTY:
+    case ReasonFromPrinter::MARKER_SUPPLY_EMPTY:
+    case ReasonFromPrinter::MARKER_WASTE_FULL:
+    case ReasonFromPrinter::TONER_EMPTY:
+      return CupsReason::kOutOfInk;
+    case ReasonFromPrinter::MEDIA_EMPTY:
+    case ReasonFromPrinter::MEDIA_NEEDED:
+      return CupsReason::kOutOfPaper;
+    case ReasonFromPrinter::OUTPUT_AREA_ALMOST_FULL:
+      return CupsReason::kOutputAreaAlmostFull;
+    case ReasonFromPrinter::OUTPUT_AREA_FULL:
+      return CupsReason::kOutputFull;
+    case ReasonFromPrinter::MEDIA_JAM:
+      return CupsReason::kPaperJam;
+    case ReasonFromPrinter::MOVING_TO_PAUSED:
+    case ReasonFromPrinter::PAUSED:
+      return CupsReason::kPaused;
+    case ReasonFromPrinter::SPOOL_AREA_FULL:
+      return CupsReason::kPrinterQueueFull;
+    case ReasonFromPrinter::SHUTDOWN:
+    case ReasonFromPrinter::TIMED_OUT:
+      return CupsReason::kPrinterUnreachable;
+    case ReasonFromPrinter::STOPPED_PARTLY:
+    case ReasonFromPrinter::STOPPING:
+      return CupsReason::kStopped;
+    case ReasonFromPrinter::INPUT_TRAY_MISSING:
+    case ReasonFromPrinter::OUTPUT_TRAY_MISSING:
+      return CupsReason::kTrayMissing;
+    case ReasonFromPrinter::UNKNOWN_REASON:
+      return CupsReason::kUnknownReason;
+  }
+}
+
+CupsSeverity PrinterSeverityToCupsSeverity(
+    const SeverityFromPrinter& severity) {
+  switch (severity) {
+    case SeverityFromPrinter::UNKNOWN_SEVERITY:
+      return CupsSeverity::kUnknownSeverity;
+    case SeverityFromPrinter::REPORT:
+      return CupsSeverity::kReport;
+    case SeverityFromPrinter::WARNING:
+      return CupsSeverity::kWarning;
+    case SeverityFromPrinter::ERROR:
+      return CupsSeverity::kError;
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/cups_printer_status_creator.h b/chrome/browser/chromeos/printing/cups_printer_status_creator.h
new file mode 100644
index 0000000..3ce27834
--- /dev/null
+++ b/chrome/browser/chromeos/printing/cups_printer_status_creator.h
@@ -0,0 +1,34 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_PRINTING_CUPS_PRINTER_STATUS_CREATOR_H_
+#define CHROME_BROWSER_CHROMEOS_PRINTING_CUPS_PRINTER_STATUS_CREATOR_H_
+
+#include <string>
+
+#include "chromeos/printing/cups_printer_status.h"
+#include "printing/printer_status.h"
+
+namespace printing {
+struct PrinterStatus;
+}  // namespace printing
+
+namespace chromeos {
+
+class CupsPrinterStatus;
+
+CupsPrinterStatus PrinterStatusToCupsPrinterStatus(
+    const std::string& printer_id,
+    const printing::PrinterStatus& printer_status);
+
+CupsPrinterStatus::CupsPrinterStatusReason::Reason PrinterReasonToCupsReason(
+    const printing::PrinterStatus::PrinterReason::Reason& reason);
+
+CupsPrinterStatus::CupsPrinterStatusReason::Severity
+PrinterSeverityToCupsSeverity(
+    const printing::PrinterStatus::PrinterReason::Severity& severity);
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_CUPS_PRINTER_STATUS_CREATOR_H_
diff --git a/chrome/browser/chromeos/printing/cups_printer_status_creator_unittest.cc b/chrome/browser/chromeos/printing/cups_printer_status_creator_unittest.cc
new file mode 100644
index 0000000..34267898
--- /dev/null
+++ b/chrome/browser/chromeos/printing/cups_printer_status_creator_unittest.cc
@@ -0,0 +1,149 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/printing/cups_printer_status_creator.h"
+
+#include <vector>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+using CupsReason = CupsPrinterStatus::CupsPrinterStatusReason::Reason;
+using CupsSeverity = CupsPrinterStatus::CupsPrinterStatusReason::Severity;
+using ReasonFromPrinter = printing::PrinterStatus::PrinterReason::Reason;
+using SeverityFromPrinter = printing::PrinterStatus::PrinterReason::Severity;
+
+TEST(CupsPrinterStatusCreatorTest, PrinterStatusToCupsPrinterStatus) {
+  printing::PrinterStatus::PrinterReason reason1;
+  reason1.reason = ReasonFromPrinter::NONE;
+  reason1.severity = SeverityFromPrinter::REPORT;
+
+  printing::PrinterStatus::PrinterReason reason2;
+  reason2.reason = ReasonFromPrinter::COVER_OPEN;
+  reason2.severity = SeverityFromPrinter::WARNING;
+
+  printing::PrinterStatus printer_status;
+  printer_status.reasons.push_back(reason1);
+  printer_status.reasons.push_back(reason2);
+
+  std::string printer_id = "id";
+  CupsPrinterStatus cups_printer_status =
+      PrinterStatusToCupsPrinterStatus(printer_id, printer_status);
+
+  EXPECT_EQ("id", cups_printer_status.GetPrinterId());
+  EXPECT_EQ(2u, cups_printer_status.GetStatusReasons().size());
+
+  std::vector<CupsPrinterStatus::CupsPrinterStatusReason> expected_reasons{
+      CupsPrinterStatus::CupsPrinterStatusReason(CupsReason::kNoError,
+                                                 CupsSeverity::kReport),
+      CupsPrinterStatus::CupsPrinterStatusReason(CupsReason::kDoorOpen,
+                                                 CupsSeverity::kWarning)};
+  EXPECT_THAT(cups_printer_status.GetStatusReasons(), expected_reasons);
+}
+
+TEST(CupsPrinterStatusCreatorTest, PrinterSeverityToCupsSeverity) {
+  EXPECT_EQ(
+      CupsSeverity::kUnknownSeverity,
+      PrinterSeverityToCupsSeverity(SeverityFromPrinter::UNKNOWN_SEVERITY));
+  EXPECT_EQ(CupsSeverity::kReport,
+            PrinterSeverityToCupsSeverity(SeverityFromPrinter::REPORT));
+  EXPECT_EQ(CupsSeverity::kWarning,
+            PrinterSeverityToCupsSeverity(SeverityFromPrinter::WARNING));
+  EXPECT_EQ(CupsSeverity::kError,
+            PrinterSeverityToCupsSeverity(SeverityFromPrinter::ERROR));
+}
+
+TEST(CupsPrinterStatusCreatorTest, PrinterReasonToCupsReason) {
+  EXPECT_EQ(CupsReason::kConnectingToDevice,
+            PrinterReasonToCupsReason(ReasonFromPrinter::CONNECTING_TO_DEVICE));
+
+  EXPECT_EQ(CupsReason::kDeviceError,
+            PrinterReasonToCupsReason(ReasonFromPrinter::FUSER_OVER_TEMP));
+  EXPECT_EQ(CupsReason::kDeviceError,
+            PrinterReasonToCupsReason(ReasonFromPrinter::FUSER_UNDER_TEMP));
+  EXPECT_EQ(CupsReason::kDeviceError,
+            PrinterReasonToCupsReason(
+                ReasonFromPrinter::INTERPRETER_RESOURCE_UNAVAILABLE));
+  EXPECT_EQ(CupsReason::kDeviceError,
+            PrinterReasonToCupsReason(ReasonFromPrinter::OPC_LIFE_OVER));
+  EXPECT_EQ(CupsReason::kDeviceError,
+            PrinterReasonToCupsReason(ReasonFromPrinter::OPC_NEAR_EOL));
+
+  EXPECT_EQ(CupsReason::kDoorOpen,
+            PrinterReasonToCupsReason(ReasonFromPrinter::COVER_OPEN));
+  EXPECT_EQ(CupsReason::kDoorOpen,
+            PrinterReasonToCupsReason(ReasonFromPrinter::DOOR_OPEN));
+  EXPECT_EQ(CupsReason::kDoorOpen,
+            PrinterReasonToCupsReason(ReasonFromPrinter::INTERLOCK_OPEN));
+
+  EXPECT_EQ(CupsReason::kLowOnInk,
+            PrinterReasonToCupsReason(ReasonFromPrinter::DEVELOPER_LOW));
+  EXPECT_EQ(CupsReason::kLowOnInk,
+            PrinterReasonToCupsReason(ReasonFromPrinter::MARKER_SUPPLY_LOW));
+  EXPECT_EQ(
+      CupsReason::kLowOnInk,
+      PrinterReasonToCupsReason(ReasonFromPrinter::MARKER_WASTE_ALMOST_FULL));
+  EXPECT_EQ(CupsReason::kLowOnInk,
+            PrinterReasonToCupsReason(ReasonFromPrinter::TONER_LOW));
+
+  EXPECT_EQ(CupsReason::kLowOnPaper,
+            PrinterReasonToCupsReason(ReasonFromPrinter::MEDIA_LOW));
+
+  EXPECT_EQ(CupsReason::kNoError,
+            PrinterReasonToCupsReason(ReasonFromPrinter::NONE));
+
+  EXPECT_EQ(CupsReason::kOutOfInk,
+            PrinterReasonToCupsReason(ReasonFromPrinter::DEVELOPER_EMPTY));
+  EXPECT_EQ(CupsReason::kOutOfInk,
+            PrinterReasonToCupsReason(ReasonFromPrinter::MARKER_SUPPLY_EMPTY));
+  EXPECT_EQ(CupsReason::kOutOfInk,
+            PrinterReasonToCupsReason(ReasonFromPrinter::MARKER_WASTE_FULL));
+  EXPECT_EQ(CupsReason::kOutOfInk,
+            PrinterReasonToCupsReason(ReasonFromPrinter::TONER_EMPTY));
+
+  EXPECT_EQ(CupsReason::kOutOfPaper,
+            PrinterReasonToCupsReason(ReasonFromPrinter::MEDIA_EMPTY));
+  EXPECT_EQ(CupsReason::kOutOfPaper,
+            PrinterReasonToCupsReason(ReasonFromPrinter::MEDIA_NEEDED));
+
+  EXPECT_EQ(
+      CupsReason::kOutputAreaAlmostFull,
+      PrinterReasonToCupsReason(ReasonFromPrinter::OUTPUT_AREA_ALMOST_FULL));
+
+  EXPECT_EQ(CupsReason::kOutputFull,
+            PrinterReasonToCupsReason(ReasonFromPrinter::OUTPUT_AREA_FULL));
+
+  EXPECT_EQ(CupsReason::kPaperJam,
+            PrinterReasonToCupsReason(ReasonFromPrinter::MEDIA_JAM));
+
+  EXPECT_EQ(CupsReason::kPaused,
+            PrinterReasonToCupsReason(ReasonFromPrinter::MOVING_TO_PAUSED));
+  EXPECT_EQ(CupsReason::kPaused,
+            PrinterReasonToCupsReason(ReasonFromPrinter::PAUSED));
+
+  EXPECT_EQ(CupsReason::kPrinterQueueFull,
+            PrinterReasonToCupsReason(ReasonFromPrinter::SPOOL_AREA_FULL));
+
+  EXPECT_EQ(CupsReason::kPrinterUnreachable,
+            PrinterReasonToCupsReason(ReasonFromPrinter::SHUTDOWN));
+  EXPECT_EQ(CupsReason::kPrinterUnreachable,
+            PrinterReasonToCupsReason(ReasonFromPrinter::TIMED_OUT));
+
+  EXPECT_EQ(CupsReason::kStopped,
+            PrinterReasonToCupsReason(ReasonFromPrinter::STOPPED_PARTLY));
+  EXPECT_EQ(CupsReason::kStopped,
+            PrinterReasonToCupsReason(ReasonFromPrinter::STOPPING));
+
+  EXPECT_EQ(CupsReason::kTrayMissing,
+            PrinterReasonToCupsReason(ReasonFromPrinter::INPUT_TRAY_MISSING));
+  EXPECT_EQ(CupsReason::kTrayMissing,
+            PrinterReasonToCupsReason(ReasonFromPrinter::OUTPUT_TRAY_MISSING));
+
+  EXPECT_EQ(CupsReason::kUnknownReason,
+            PrinterReasonToCupsReason(ReasonFromPrinter::UNKNOWN_REASON));
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/client_hints/client_hints_factory.cc b/chrome/browser/client_hints/client_hints_factory.cc
index 3302c34b..6e3f78e 100644
--- a/chrome/browser/client_hints/client_hints_factory.cc
+++ b/chrome/browser/client_hints/client_hints_factory.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/browser/client_hints/client_hints_factory.h"
 
-#include "chrome/browser/client_hints/client_hints.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_content_browser_client.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
+#include "components/client_hints/browser/client_hints.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "content/public/browser/browser_context.h"
 
@@ -33,11 +36,14 @@
           "ClientHints",
           BrowserContextDependencyManager::GetInstance()) {}
 
-ClientHintsFactory::~ClientHintsFactory() {}
+ClientHintsFactory::~ClientHintsFactory() = default;
 
 KeyedService* ClientHintsFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  return new client_hints::ClientHints(context);
+  return new client_hints::ClientHints(
+      context, g_browser_process->network_quality_tracker(),
+      HostContentSettingsMapFactory::GetForProfile(context),
+      GetUserAgentMetadata());
 }
 
 content::BrowserContext* ClientHintsFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc
index de51731..c89b93c 100644
--- a/chrome/browser/extensions/unpacked_installer.cc
+++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -24,7 +24,7 @@
 #include "components/sync/model/string_ordinal.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "extensions/browser/api/declarative_net_request/ruleset_source.h"
+#include "extensions/browser/api/declarative_net_request/index_helper.h"
 #include "extensions/browser/extension_file_task_runner.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
@@ -33,7 +33,6 @@
 #include "extensions/browser/policy_check.h"
 #include "extensions/browser/preload_check_group.h"
 #include "extensions/browser/requirements_checker.h"
-#include "extensions/common/api/declarative_net_request/dnr_manifest_data.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_l10n_util.h"
@@ -268,30 +267,21 @@
 bool UnpackedInstaller::IndexAndPersistRulesIfNeeded(std::string* error) {
   DCHECK(extension());
 
-  using RulesetSource = declarative_net_request::RulesetSource;
-
-  // TODO(crbug.com/761107): Change this so that we don't need to parse JSON
-  // in the browser process.
-  // TODO(crbug.com/754526): Impose a limit on the total number of rules across
-  // all the rulesets for an extension. Also, limit the number of install
-  // warnings across all rulesets.
-  // Note |sources| may be empty.
-  std::vector<RulesetSource> sources =
-      RulesetSource::CreateStatic(*extension());
-
-  for (const RulesetSource& source : sources) {
-    declarative_net_request::IndexAndPersistJSONRulesetResult result =
-        source.IndexAndPersistJSONRulesetUnsafe();
-    if (!result.success) {
-      *error = std::move(result.error);
-      return false;
-    }
-
-    ruleset_checksums_.emplace_back(result.ruleset_id, result.ruleset_checksum);
-    if (!result.warnings.empty())
-      extension_->AddInstallWarnings(std::move(result.warnings));
+  // TODO(crbug.com/761107): IndexStaticRulesetsUnsafe will read and parse JSON
+  // synchronously. Change this so that we don't need to parse JSON in the
+  // browser process.
+  declarative_net_request::IndexHelper::Result result =
+      declarative_net_request::IndexHelper::IndexStaticRulesetsUnsafe(
+          *extension());
+  if (result.error) {
+    *error = std::move(*result.error);
+    return false;
   }
 
+  ruleset_checksums_ = std::move(result.ruleset_checksums);
+  if (!result.warnings.empty())
+    extension_->AddInstallWarnings(std::move(result.warnings));
+
   return true;
 }
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 74b018c..4ee3fc7 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -3351,11 +3351,6 @@
     "expiry_milestone": 86
   },
   {
-    "name": "prefetch-main-resource-network-isolation-key",
-    "owners": [ "dom", "yhirano" ],
-    "expiry_milestone": 85
-  },
-  {
     "name": "prefetch-notification-scheduling-integration",
     "owners": [ "hesen" ],
     "expiry_milestone": 88
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 9d562ac6..b77f789 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1629,13 +1629,6 @@
     "not send credentials for cross-origin requests, and do not pass through "
     "service workers.";
 
-const char kPrefetchMainResourceNetworkIsolationKeyName[] =
-    "Prefetch requests for cross-origin main resources are fetched with a "
-    "special NetworkIsolationKey";
-const char kPrefetchMainResourceNetworkIsolationKeyDescription[] =
-    "Prefetch requests for cross-origin main resources can be reused by next "
-    "top-level navigations when HTTP cache is double-keyed.";
-
 const char kPrinterStatusName[] = "Show printer Status";
 const char kPrinterStatusDescription[] =
     "Enables printer status icons and labels for saved and nearby printers";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index c0197c2..890b4dda 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -950,9 +950,6 @@
 extern const char kPrefetchPrivacyChangesName[];
 extern const char kPrefetchPrivacyChangesDescription[];
 
-extern const char kPrefetchMainResourceNetworkIsolationKeyName[];
-extern const char kPrefetchMainResourceNetworkIsolationKeyDescription[];
-
 extern const char kPrinterStatusName[];
 extern const char kPrinterStatusDescription[];
 
diff --git a/chrome/browser/media/feeds/media_feeds_store.mojom b/chrome/browser/media/feeds/media_feeds_store.mojom
index 9d24cfd..b861977 100644
--- a/chrome/browser/media/feeds/media_feeds_store.mojom
+++ b/chrome/browser/media/feeds/media_feeds_store.mojom
@@ -31,8 +31,8 @@
   // The number of times in a row the feed has failed to be fetched.
   int64 fetch_failed_count;
 
-  // The time the previously fetched feed should expire in the cache.
-  mojo_base.mojom.Time? cache_expiry_time;
+  // The time we previously fetched the feed that did not hit the cache.
+  mojo_base.mojom.Time? last_fetch_time_not_cache_hit;
 
   // The number of items in the last feed fetch.
   int64 last_fetch_item_count;
diff --git a/chrome/browser/media/history/media_history_feeds_table.cc b/chrome/browser/media/history/media_history_feeds_table.cc
index 49234c0..33fcf21a 100644
--- a/chrome/browser/media/history/media_history_feeds_table.cc
+++ b/chrome/browser/media/history/media_history_feeds_table.cc
@@ -38,29 +38,29 @@
   if (!CanAccessDatabase())
     return sql::INIT_FAILURE;
 
-  bool success =
-      DB()->Execute(base::StringPrintf("CREATE TABLE IF NOT EXISTS %s("
-                                       "id INTEGER PRIMARY KEY AUTOINCREMENT,"
-                                       "origin_id INTEGER NOT NULL UNIQUE,"
-                                       "url TEXT NOT NULL, "
-                                       "last_discovery_time_s INTEGER, "
-                                       "last_fetch_time_s INTEGER, "
-                                       "user_status INTEGER DEFAULT 0, "
-                                       "last_fetch_result INTEGER DEFAULT 0, "
-                                       "fetch_failed_count INTEGER, "
-                                       "cache_expiry_time_s INTEGER, "
-                                       "last_fetch_item_count INTEGER, "
-                                       "last_fetch_play_next_count INTEGER, "
-                                       "last_fetch_content_types INTEGER, "
-                                       "logo BLOB, "
-                                       "display_name TEXT, "
-                                       "CONSTRAINT fk_origin "
-                                       "FOREIGN KEY (origin_id) "
-                                       "REFERENCES origin(id) "
-                                       "ON DELETE CASCADE"
-                                       ")",
-                                       kTableName)
-                        .c_str());
+  bool success = DB()->Execute(
+      base::StringPrintf("CREATE TABLE IF NOT EXISTS %s("
+                         "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+                         "origin_id INTEGER NOT NULL UNIQUE,"
+                         "url TEXT NOT NULL, "
+                         "last_discovery_time_s INTEGER, "
+                         "last_fetch_time_s INTEGER, "
+                         "user_status INTEGER DEFAULT 0, "
+                         "last_fetch_result INTEGER DEFAULT 0, "
+                         "fetch_failed_count INTEGER, "
+                         "last_fetch_time_not_cache_hit_s INTEGER, "
+                         "last_fetch_item_count INTEGER, "
+                         "last_fetch_play_next_count INTEGER, "
+                         "last_fetch_content_types INTEGER, "
+                         "logo BLOB, "
+                         "display_name TEXT, "
+                         "CONSTRAINT fk_origin "
+                         "FOREIGN KEY (origin_id) "
+                         "REFERENCES origin(id) "
+                         "ON DELETE CASCADE"
+                         ")",
+                         kTableName)
+          .c_str());
 
   if (success) {
     success = DB()->Execute(
@@ -142,7 +142,7 @@
   sql::Statement statement(DB()->GetUniqueStatement(
       "SELECT id, url, last_discovery_time_s, last_fetch_time_s, "
       "user_status, last_fetch_result, fetch_failed_count, "
-      "cache_expiry_time_s, "
+      "last_fetch_time_not_cache_hit_s, "
       "last_fetch_item_count, last_fetch_play_next_count, "
       "last_fetch_content_types, "
       "logo, display_name FROM mediaFeed"));
@@ -195,8 +195,9 @@
     feed->fetch_failed_count = statement.ColumnInt64(6);
 
     if (statement.GetColumnType(7) == sql::ColumnType::kInteger) {
-      feed->cache_expiry_time = base::Time::FromDeltaSinceWindowsEpoch(
-          base::TimeDelta::FromSeconds(statement.ColumnInt64(7)));
+      feed->last_fetch_time_not_cache_hit =
+          base::Time::FromDeltaSinceWindowsEpoch(
+              base::TimeDelta::FromSeconds(statement.ColumnInt64(7)));
     }
 
     feed->last_fetch_item_count = statement.ColumnInt64(8);
@@ -215,7 +216,7 @@
 bool MediaHistoryFeedsTable::UpdateFeedFromFetch(
     const int64_t feed_id,
     const media_feeds::mojom::FetchResult result,
-    const base::Time& expiry_time,
+    const bool was_fetched_from_cache,
     const int item_count,
     const int item_play_next_count,
     const int item_content_types,
@@ -242,32 +243,48 @@
     }
   }
 
-  sql::Statement statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      "UPDATE mediaFeed SET last_fetch_time_s = ?, last_fetch_result = ?, "
-      "fetch_failed_count = ?, cache_expiry_time_s = ?, last_fetch_item_count "
-      "= ?, "
-      "last_fetch_play_next_count = ?, last_fetch_content_types = ?, "
-      "logo = ?, display_name = ?  WHERE id = ?"));
+  sql::Statement statement;
+  if (was_fetched_from_cache) {
+    statement.Assign(DB()->GetCachedStatement(
+        SQL_FROM_HERE,
+        "UPDATE mediaFeed SET last_fetch_time_s = ?, last_fetch_result = ?, "
+        "fetch_failed_count = ?, last_fetch_item_count = ?, "
+        "last_fetch_play_next_count = ?, last_fetch_content_types = ?, "
+        "logo = ?, display_name = ?  WHERE id = ?"));
+  } else {
+    statement.Assign(DB()->GetCachedStatement(
+        SQL_FROM_HERE,
+        "UPDATE mediaFeed SET last_fetch_time_s = ?, last_fetch_result = ?, "
+        "fetch_failed_count = ?, last_fetch_item_count = ?, "
+        "last_fetch_play_next_count = ?, last_fetch_content_types = ?, "
+        "logo = ?, display_name = ?, last_fetch_time_not_cache_hit_s = ? WHERE "
+        "id = ?"));
+  }
 
   statement.BindInt64(0,
                       base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds());
   statement.BindInt64(1, static_cast<int>(result));
   statement.BindInt64(2, fetch_failed_count);
-  statement.BindInt64(3, expiry_time.ToDeltaSinceWindowsEpoch().InSeconds());
-  statement.BindInt64(4, item_count);
-  statement.BindInt64(5, item_play_next_count);
-  statement.BindInt64(6, item_content_types);
+  statement.BindInt64(3, item_count);
+  statement.BindInt64(4, item_play_next_count);
+  statement.BindInt64(5, item_content_types);
 
   if (!logos.empty()) {
-    BindProto(statement, 7,
+    BindProto(statement, 6,
               media_feeds::MediaImagesToProto(logos, kMaxLogoCount));
   } else {
-    statement.BindNull(7);
+    statement.BindNull(6);
   }
 
-  statement.BindString(8, display_name);
-  statement.BindInt64(9, feed_id);
+  statement.BindString(7, display_name);
+
+  if (was_fetched_from_cache) {
+    statement.BindInt64(8, feed_id);
+  } else {
+    statement.BindInt64(
+        8, base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds());
+    statement.BindInt64(9, feed_id);
+  }
 
   return statement.Run() && DB()->GetLastChangeCount() == 1;
 }
diff --git a/chrome/browser/media/history/media_history_feeds_table.h b/chrome/browser/media/history/media_history_feeds_table.h
index 3bb23b6..c98b3f6 100644
--- a/chrome/browser/media/history/media_history_feeds_table.h
+++ b/chrome/browser/media/history/media_history_feeds_table.h
@@ -54,7 +54,7 @@
   // Updates the feed following a fetch.
   bool UpdateFeedFromFetch(const int64_t feed_id,
                            const media_feeds::mojom::FetchResult result,
-                           const base::Time& expiry_time,
+                           const bool was_fetched_from_cache,
                            const int item_count,
                            const int item_play_next_count,
                            const int item_content_types,
diff --git a/chrome/browser/media/history/media_history_keyed_service.cc b/chrome/browser/media/history/media_history_keyed_service.cc
index 6caa266a..41dae95 100644
--- a/chrome/browser/media/history/media_history_keyed_service.cc
+++ b/chrome/browser/media/history/media_history_keyed_service.cc
@@ -211,12 +211,13 @@
     const int64_t feed_id,
     std::vector<media_feeds::mojom::MediaFeedItemPtr> items,
     const media_feeds::mojom::FetchResult result,
-    const base::Time& expiry_time,
+    const bool was_fetched_from_cache,
     const std::vector<media_session::MediaImage>& logos,
     const std::string& display_name) {
   if (auto* store = store_->GetForWrite()) {
     store->StoreMediaFeedFetchResult(feed_id, std::move(items), result,
-                                     expiry_time, logos, display_name);
+                                     was_fetched_from_cache, logos,
+                                     display_name);
   }
 }
 
diff --git a/chrome/browser/media/history/media_history_keyed_service.h b/chrome/browser/media/history/media_history_keyed_service.h
index 81e525a9..64cbd41 100644
--- a/chrome/browser/media/history/media_history_keyed_service.h
+++ b/chrome/browser/media/history/media_history_keyed_service.h
@@ -94,12 +94,13 @@
 
   // Replaces the media items in |feed_id|. This will delete any old feed items
   // and store the new ones in |items|. This will also update the |result|,
-  // |expiry_time|, |logos| and |display_name| for the feed.
+  // |logos| and |display_name| for the feed. If the feed was fetched from the
+  // browser cache then |was_fetched_from_cache| should be true.
   void StoreMediaFeedFetchResult(
       const int64_t feed_id,
       std::vector<media_feeds::mojom::MediaFeedItemPtr> items,
       const media_feeds::mojom::FetchResult result,
-      const base::Time& expiry_time,
+      const bool was_fetched_from_cache,
       const std::vector<media_session::MediaImage>& logos,
       const std::string& display_name);
 
diff --git a/chrome/browser/media/history/media_history_keyed_service_unittest.cc b/chrome/browser/media/history/media_history_keyed_service_unittest.cc
index cb185e60..261f668 100644
--- a/chrome/browser/media/history/media_history_keyed_service_unittest.cc
+++ b/chrome/browser/media/history/media_history_keyed_service_unittest.cc
@@ -398,10 +398,12 @@
   // Store the feed data.
   service()->StoreMediaFeedFetchResult(
       1, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), std::vector<media_session::MediaImage>(), "Test");
+      /* was_fetched_from_cache= */ false,
+      std::vector<media_session::MediaImage>(), "Test");
   service()->StoreMediaFeedFetchResult(
       2, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), std::vector<media_session::MediaImage>(), "test");
+      /* was_fetched_from_cache= */ false,
+      std::vector<media_session::MediaImage>(), "test");
 
   // Wait until the feed data has finished saving.
   WaitForDB();
@@ -613,10 +615,12 @@
   // Store the feed data.
   service()->StoreMediaFeedFetchResult(
       1, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), std::vector<media_session::MediaImage>(), "Test");
+      /* was_fetched_from_cache= */ false,
+      std::vector<media_session::MediaImage>(), "Test");
   service()->StoreMediaFeedFetchResult(
       2, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), std::vector<media_session::MediaImage>(), "test");
+      /* was_fetched_from_cache= */ false,
+      std::vector<media_session::MediaImage>(), "test");
 
   // Wait until the feed data has finished saving.
   WaitForDB();
diff --git a/chrome/browser/media/history/media_history_store.cc b/chrome/browser/media/history/media_history_store.cc
index 8584c52..ed9e8829 100644
--- a/chrome/browser/media/history/media_history_store.cc
+++ b/chrome/browser/media/history/media_history_store.cc
@@ -100,7 +100,7 @@
       const int64_t feed_id,
       std::vector<media_feeds::mojom::MediaFeedItemPtr> items,
       const media_feeds::mojom::FetchResult result,
-      const base::Time& expiry_time,
+      const bool was_fetched_from_cache,
       const std::vector<media_session::MediaImage>& logos,
       const std::string& display_name);
 
@@ -630,7 +630,7 @@
     const int64_t feed_id,
     std::vector<media_feeds::mojom::MediaFeedItemPtr> items,
     const media_feeds::mojom::FetchResult result,
-    const base::Time& expiry_time,
+    const bool was_fetched_from_cache,
     const std::vector<media_session::MediaImage>& logos,
     const std::string& display_name) {
   DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
@@ -674,8 +674,8 @@
 
   // Update the metadata associated with this feed.
   if (!feeds_table_->UpdateFeedFromFetch(
-          feed_id, result, expiry_time, items.size(), item_play_next_count,
-          item_content_types, logos, display_name)) {
+          feed_id, result, was_fetched_from_cache, items.size(),
+          item_play_next_count, item_content_types, logos, display_name)) {
     DB()->RollbackTransaction();
     return;
   }
@@ -915,14 +915,14 @@
     const int64_t feed_id,
     std::vector<media_feeds::mojom::MediaFeedItemPtr> items,
     const media_feeds::mojom::FetchResult result,
-    const base::Time& expiry_time,
+    const bool was_fetched_from_cache,
     const std::vector<media_session::MediaImage>& logos,
     const std::string& display_name) {
   db_->db_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&MediaHistoryStoreInternal::StoreMediaFeedFetchResult, db_,
-                     feed_id, std::move(items), result, expiry_time, logos,
-                     display_name));
+                     feed_id, std::move(items), result, was_fetched_from_cache,
+                     logos, display_name));
 }
 
 void MediaHistoryStore::GetItemsForMediaFeedForDebug(
diff --git a/chrome/browser/media/history/media_history_store.h b/chrome/browser/media/history/media_history_store.h
index faef435..33b22285 100644
--- a/chrome/browser/media/history/media_history_store.h
+++ b/chrome/browser/media/history/media_history_store.h
@@ -148,7 +148,7 @@
       const int64_t feed_id,
       std::vector<media_feeds::mojom::MediaFeedItemPtr> items,
       const media_feeds::mojom::FetchResult result,
-      const base::Time& expiry_time,
+      const bool was_fetched_from_cache,
       const std::vector<media_session::MediaImage>& logos,
       const std::string& display_name);
 
diff --git a/chrome/browser/media/history/media_history_store_unittest.cc b/chrome/browser/media/history/media_history_store_unittest.cc
index b25afba..ea8da7a 100644
--- a/chrome/browser/media/history/media_history_store_unittest.cc
+++ b/chrome/browser/media/history/media_history_store_unittest.cc
@@ -825,7 +825,7 @@
       EXPECT_EQ(media_feeds::mojom::FetchResult::kNone,
                 feeds[0]->last_fetch_result);
       EXPECT_EQ(0, feeds[0]->fetch_failed_count);
-      EXPECT_FALSE(feeds[0]->cache_expiry_time.has_value());
+      EXPECT_FALSE(feeds[0]->last_fetch_time_not_cache_hit.has_value());
       EXPECT_EQ(0, feeds[0]->last_fetch_item_count);
       EXPECT_EQ(0, feeds[0]->last_fetch_play_next_count);
       EXPECT_EQ(0, feeds[0]->last_fetch_content_types);
@@ -875,42 +875,7 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), GetExpectedLogos(), kExpectedDisplayName);
-  WaitForDB();
-
-  {
-    // The media items should be stored and the feed should be updated.
-    auto feeds = GetMediaFeedsSync(service());
-    auto items = GetItemsForMediaFeedSync(service(), feed_id);
-
-    if (IsReadOnly()) {
-      EXPECT_TRUE(feeds.empty());
-      EXPECT_TRUE(items.empty());
-    } else {
-      EXPECT_EQ(feed_id, feeds[0]->id);
-      EXPECT_TRUE(feeds[0]->last_fetch_time.has_value());
-      EXPECT_EQ(media_feeds::mojom::FetchResult::kSuccess,
-                feeds[0]->last_fetch_result);
-      EXPECT_EQ(0, feeds[0]->fetch_failed_count);
-      EXPECT_TRUE(feeds[0]->cache_expiry_time.has_value());
-      EXPECT_EQ(kExpectedFetchItemCount, feeds[0]->last_fetch_item_count);
-      EXPECT_EQ(kExpectedFetchPlayNextCount,
-                feeds[0]->last_fetch_play_next_count);
-      EXPECT_EQ(kExpectedFetchContentTypes, feeds[0]->last_fetch_content_types);
-      EXPECT_EQ(GetExpectedLogos(), feeds[0]->logos);
-      EXPECT_EQ(kExpectedDisplayName, feeds[0]->display_name);
-
-      EXPECT_EQ(GetExpectedItems(), items);
-    }
-
-    // The OTR service should have the same data.
-    EXPECT_EQ(feeds, GetMediaFeedsSync(otr_service()));
-    EXPECT_EQ(items, GetItemsForMediaFeedSync(otr_service(), feed_id));
-  }
-
-  service()->StoreMediaFeedFetchResult(
-      feed_id, GetAltExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), std::vector<media_session::MediaImage>(),
+      /* was_fetched_from_cache= */ false, GetExpectedLogos(),
       kExpectedDisplayName);
   WaitForDB();
 
@@ -928,7 +893,45 @@
       EXPECT_EQ(media_feeds::mojom::FetchResult::kSuccess,
                 feeds[0]->last_fetch_result);
       EXPECT_EQ(0, feeds[0]->fetch_failed_count);
-      EXPECT_TRUE(feeds[0]->cache_expiry_time.has_value());
+      EXPECT_TRUE(feeds[0]->last_fetch_time_not_cache_hit.has_value());
+      EXPECT_EQ(kExpectedFetchItemCount, feeds[0]->last_fetch_item_count);
+      EXPECT_EQ(kExpectedFetchPlayNextCount,
+                feeds[0]->last_fetch_play_next_count);
+      EXPECT_EQ(kExpectedFetchContentTypes, feeds[0]->last_fetch_content_types);
+      EXPECT_EQ(GetExpectedLogos(), feeds[0]->logos);
+      EXPECT_EQ(kExpectedDisplayName, feeds[0]->display_name);
+
+      EXPECT_EQ(GetExpectedItems(), items);
+    }
+
+    // The OTR service should have the same data.
+    EXPECT_EQ(feeds, GetMediaFeedsSync(otr_service()));
+    EXPECT_EQ(items, GetItemsForMediaFeedSync(otr_service(), feed_id));
+  }
+
+  service()->StoreMediaFeedFetchResult(
+      feed_id, GetAltExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
+      /* was_fetched_from_cache= */ false,
+      std::vector<media_session::MediaImage>(), kExpectedDisplayName);
+  WaitForDB();
+
+  base::Optional<base::Time> last_fetch_time_not_cache_hit;
+
+  {
+    // The media items should be stored and the feed should be updated.
+    auto feeds = GetMediaFeedsSync(service());
+    auto items = GetItemsForMediaFeedSync(service(), feed_id);
+
+    if (IsReadOnly()) {
+      EXPECT_TRUE(feeds.empty());
+      EXPECT_TRUE(items.empty());
+    } else {
+      EXPECT_EQ(feed_id, feeds[0]->id);
+      EXPECT_TRUE(feeds[0]->last_fetch_time.has_value());
+      EXPECT_EQ(media_feeds::mojom::FetchResult::kSuccess,
+                feeds[0]->last_fetch_result);
+      EXPECT_EQ(0, feeds[0]->fetch_failed_count);
+      EXPECT_TRUE(feeds[0]->last_fetch_time_not_cache_hit.has_value());
       EXPECT_EQ(kExpectedAltFetchItemCount, feeds[0]->last_fetch_item_count);
       EXPECT_EQ(kExpectedAltFetchPlayNextCount,
                 feeds[0]->last_fetch_play_next_count);
@@ -938,6 +941,48 @@
       EXPECT_EQ(kExpectedDisplayName, feeds[0]->display_name);
 
       EXPECT_EQ(GetAltExpectedItems(), items);
+
+      last_fetch_time_not_cache_hit = feeds[0]->last_fetch_time_not_cache_hit;
+    }
+
+    // The OTR service should have the same data.
+    EXPECT_EQ(feeds, GetMediaFeedsSync(otr_service()));
+    EXPECT_EQ(items, GetItemsForMediaFeedSync(otr_service(), feed_id));
+  }
+
+  service()->StoreMediaFeedFetchResult(
+      feed_id, GetAltExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
+      /* was_fetched_from_cache= */ true,
+      std::vector<media_session::MediaImage>(), kExpectedDisplayName);
+  WaitForDB();
+
+  {
+    // The media items should be stored and the feed should be updated.
+    auto feeds = GetMediaFeedsSync(service());
+    auto items = GetItemsForMediaFeedSync(service(), feed_id);
+
+    if (IsReadOnly()) {
+      EXPECT_TRUE(feeds.empty());
+      EXPECT_TRUE(items.empty());
+    } else {
+      EXPECT_EQ(feed_id, feeds[0]->id);
+      EXPECT_TRUE(feeds[0]->last_fetch_time.has_value());
+      EXPECT_EQ(media_feeds::mojom::FetchResult::kSuccess,
+                feeds[0]->last_fetch_result);
+      EXPECT_EQ(0, feeds[0]->fetch_failed_count);
+      EXPECT_TRUE(feeds[0]->last_fetch_time_not_cache_hit.has_value());
+      EXPECT_EQ(kExpectedAltFetchItemCount, feeds[0]->last_fetch_item_count);
+      EXPECT_EQ(kExpectedAltFetchPlayNextCount,
+                feeds[0]->last_fetch_play_next_count);
+      EXPECT_EQ(kExpectedAltFetchContentTypes,
+                feeds[0]->last_fetch_content_types);
+      EXPECT_TRUE(feeds[0]->logos.empty());
+      EXPECT_EQ(kExpectedDisplayName, feeds[0]->display_name);
+
+      EXPECT_EQ(GetAltExpectedItems(), items);
+
+      EXPECT_EQ(last_fetch_time_not_cache_hit,
+                feeds[0]->last_fetch_time_not_cache_hit);
     }
 
     // The OTR service should have the same data.
@@ -957,8 +1002,8 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), std::vector<media_session::MediaImage>(),
-      std::string());
+      /* was_fetched_from_cache= */ false,
+      std::vector<media_session::MediaImage>(), std::string());
   WaitForDB();
 
   {
@@ -977,7 +1022,8 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, std::vector<media_feeds::mojom::MediaFeedItemPtr>(),
-      media_feeds::mojom::FetchResult::kSuccess, base::Time::Now(),
+      media_feeds::mojom::FetchResult::kSuccess,
+      /* was_fetched_from_cache= */ false,
       std::vector<media_session::MediaImage>(), std::string());
   WaitForDB();
 
@@ -1004,13 +1050,14 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id_a, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), std::vector<media_session::MediaImage>(),
-      std::string());
+      /* was_fetched_from_cache= */ false,
+      std::vector<media_session::MediaImage>(), std::string());
   WaitForDB();
 
   service()->StoreMediaFeedFetchResult(
       feed_id_b, GetAltExpectedItems(),
-      media_feeds::mojom::FetchResult::kFailedNetworkError, base::Time::Now(),
+      media_feeds::mojom::FetchResult::kFailedNetworkError,
+      /* was_fetched_from_cache= */ false,
       std::vector<media_session::MediaImage>(), std::string());
   WaitForDB();
 
@@ -1078,8 +1125,8 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), std::vector<media_session::MediaImage>(),
-      std::string());
+      /* was_fetched_from_cache= */ false,
+      std::vector<media_session::MediaImage>(), std::string());
   WaitForDB();
 
   {
@@ -1133,8 +1180,8 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), std::vector<media_session::MediaImage>(),
-      std::string());
+      /* was_fetched_from_cache= */ false,
+      std::vector<media_session::MediaImage>(), std::string());
   WaitForDB();
 
   {
@@ -1215,8 +1262,9 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, GetExpectedItems(),
-      media_feeds::mojom::FetchResult::kFailedNetworkError, base::Time::Now(),
-      GetExpectedLogos(), kExpectedDisplayName);
+      media_feeds::mojom::FetchResult::kFailedNetworkError,
+      /* was_fetched_from_cache= */ false, GetExpectedLogos(),
+      kExpectedDisplayName);
   WaitForDB();
 
   {
@@ -1238,8 +1286,9 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, GetExpectedItems(),
-      media_feeds::mojom::FetchResult::kFailedBackendError, base::Time::Now(),
-      GetExpectedLogos(), kExpectedDisplayName);
+      media_feeds::mojom::FetchResult::kFailedBackendError,
+      /* was_fetched_from_cache= */ false, GetExpectedLogos(),
+      kExpectedDisplayName);
   WaitForDB();
 
   {
@@ -1261,7 +1310,8 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), GetExpectedLogos(), kExpectedDisplayName);
+      /* was_fetched_from_cache= */ false, GetExpectedLogos(),
+      kExpectedDisplayName);
   WaitForDB();
 
   {
@@ -1331,8 +1381,8 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, GetExpectedItems(),
-      media_feeds::mojom::FetchResult::kFailedNetworkError, base::Time::Now(),
-      logos, kExpectedDisplayName);
+      media_feeds::mojom::FetchResult::kFailedNetworkError,
+      /* was_fetched_from_cache= */ false, logos, kExpectedDisplayName);
   WaitForDB();
 
   {
@@ -1406,7 +1456,8 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, std::move(items), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), GetExpectedLogos(), kExpectedDisplayName);
+      /* was_fetched_from_cache= */ false, GetExpectedLogos(),
+      kExpectedDisplayName);
   WaitForDB();
 
   {
@@ -1443,7 +1494,8 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id, std::move(items), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), GetExpectedLogos(), kExpectedDisplayName);
+      /* was_fetched_from_cache= */ false, GetExpectedLogos(),
+      kExpectedDisplayName);
   WaitForDB();
 
   {
@@ -1475,13 +1527,14 @@
 
   service()->StoreMediaFeedFetchResult(
       feed_id_a, GetExpectedItems(), media_feeds::mojom::FetchResult::kSuccess,
-      base::Time::Now(), std::vector<media_session::MediaImage>(),
-      std::string());
+      /* was_fetched_from_cache= */ false,
+      std::vector<media_session::MediaImage>(), std::string());
   WaitForDB();
 
   service()->StoreMediaFeedFetchResult(
       feed_id_b, GetAltExpectedItems(),
-      media_feeds::mojom::FetchResult::kSuccess, base::Time::Now(),
+      media_feeds::mojom::FetchResult::kSuccess,
+      /* was_fetched_from_cache= */ false,
       std::vector<media_session::MediaImage>(), std::string());
   WaitForDB();
 
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 021467d3..62004e48 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/json/json_reader.h"
 #include "base/optional.h"
 #include "chrome/browser/media/router/data_decoder_util.h"
@@ -109,12 +110,14 @@
   } else {
     const MediaRoute::Id& existing_route_id =
         it->second->route().media_route_id();
-    TerminateSession(
-        existing_route_id,
-        base::BindOnce(
-            &CastActivityManager::LaunchSessionAfterTerminatingExisting,
-            weak_ptr_factory_.GetWeakPtr(), existing_route_id,
-            std::move(params)));
+    // We cannot launch the new session in the TerminateSession() callback
+    // because if we create a session there, then it may get deleted when
+    // OnSessionRemoved() is called to notify that the previous session was
+    // removed on the receiver.
+    TerminateSession(existing_route_id, base::DoNothing());
+    // The new session will be launched when OnSessionRemoved() is called for
+    // the old session.
+    pending_launch_ = std::move(params);
   }
 }
 
@@ -162,24 +165,6 @@
            /* error_text */ base::nullopt, RouteRequestResult::ResultCode::OK);
 }
 
-void CastActivityManager::LaunchSessionAfterTerminatingExisting(
-    const MediaRoute::Id& existing_route_id,
-    DoLaunchSessionParams params,
-    const base::Optional<std::string>& error_string,
-    RouteRequestResult::ResultCode result) {
-  // NOTE(mfoltz): I don't recall if an explicit STOP request is required by
-  // Cast V2 before launching a new session.  I think in the Javascript MRP
-  // session termination is a fire and forget operation.  In which case we could
-  // rely on RECEIVER_STATUS to clean up the state from the just-removed
-  // session, versus having to stop then wait for a response.
-  DLOG_IF(ERROR, error_string)
-      << "Failed to terminate existing session before launching new "
-      << "session! New session may not operate correctly. Error: "
-      << *error_string;
-  activities_.erase(existing_route_id);
-  DoLaunchSession(std::move(params));
-}
-
 CastActivityRecord* CastActivityManager::FindActivityForSessionJoin(
     const CastMediaSource& cast_source,
     const std::string& presentation_id) {
@@ -514,11 +499,15 @@
 }
 
 void CastActivityManager::OnSessionRemoved(const MediaSinkInternal& sink) {
-  auto it = FindActivityBySink(sink);
-  if (it != activities_.end()) {
-    RemoveActivity(it, PresentationConnectionState::TERMINATED,
+  auto activity_it = FindActivityBySink(sink);
+  if (activity_it != activities_.end()) {
+    RemoveActivity(activity_it, PresentationConnectionState::TERMINATED,
                    PresentationConnectionCloseReason::CLOSED);
   }
+  if (pending_launch_ && pending_launch_->sink.id() == sink.id()) {
+    DoLaunchSession(std::move(*pending_launch_));
+    pending_launch_.reset();
+  }
 }
 
 void CastActivityManager::OnMediaStatusUpdated(const MediaSinkInternal& sink,
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 dac700d..d9f2b27 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager.h
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.h
@@ -19,6 +19,7 @@
 #include "chrome/browser/media/router/providers/cast/cast_internal_message_util.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_sink.h"
 #include "chrome/common/media_router/mojom/media_router.mojom.h"
 #include "chrome/common/media_router/providers/cast/cast_media_source.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -159,9 +160,11 @@
         const url::Origin& origin,
         int tab_id,
         mojom::MediaRouteProvider::CreateRouteCallback callback);
+    DoLaunchSessionParams(const DoLaunchSessionParams& other) = delete;
     DoLaunchSessionParams(DoLaunchSessionParams&& other);
     ~DoLaunchSessionParams();
-    DoLaunchSessionParams& operator=(DoLaunchSessionParams&&) = delete;
+    DoLaunchSessionParams& operator=(DoLaunchSessionParams&) = delete;
+    DoLaunchSessionParams& operator=(DoLaunchSessionParams&&) = default;
 
     // The route for which a session is being launched.
     MediaRoute route;
@@ -183,11 +186,6 @@
   };
 
   void DoLaunchSession(DoLaunchSessionParams params);
-  void LaunchSessionAfterTerminatingExisting(
-      const MediaRoute::Id& existing_route_id,
-      DoLaunchSessionParams params,
-      const base::Optional<std::string>& error_string,
-      RouteRequestResult::ResultCode result);
 
   void RemoveActivityByRouteId(const std::string& route_id);
 
@@ -268,6 +266,12 @@
   // there is a CastActivityRecord.
   CastActivityMap cast_activities_;
 
+  // Information for a session that will be launched once |this| is notified
+  // that the existing session on the receiver has been removed. We only store
+  // one pending launch at a time so that we don't accumulate orphaned pending
+  // launches over time.
+  base::Optional<DoLaunchSessionParams> pending_launch_;
+
   // The following raw pointer fields are assumed to outlive |this|.
   MediaSinkServiceBase* const media_sink_service_;
   CastSessionTracker* const session_tracker_;
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc
index 7361d44..03b541b 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager_unittest.cc
@@ -114,8 +114,9 @@
         router_remote_.get(), "theHashToken");
 
     ON_CALL(message_handler_, StopSession)
-        .WillByDefault(WithArg<3>(
-            [this](auto callback) { result_callback_ = std::move(callback); }));
+        .WillByDefault(WithArg<3>([this](auto callback) {
+          stop_session_callback_ = std::move(callback);
+        }));
 
     RunUntilIdle();
 
@@ -241,7 +242,7 @@
     }
     manager_->TerminateSession(route_->media_route_id(),
                                MakeTerminateRouteCallback(expect_success));
-    std::move(result_callback_)
+    std::move(stop_session_callback_)
         .Run(expect_success ? cast_channel::Result::kOk
                             : cast_channel::Result::kFailed);
   }
@@ -323,7 +324,7 @@
   const url::Origin origin_ = url::Origin::Create(GURL(kOrigin));
   const MediaSource::Id route_query_ = "theRouteQuery";
   base::Optional<MediaRoute> updated_route_;
-  cast_channel::ResultCallback result_callback_;
+  cast_channel::ResultCallback stop_session_callback_;
 };
 
 TEST_F(CastActivityManagerTest, LaunchCastAppSession) {
@@ -385,9 +386,13 @@
       base::BindOnce(&CastActivityManagerTest::ExpectLaunchSessionSuccess,
                      base::Unretained(this)));
 
+  std::move(stop_session_callback_).Run(cast_channel::Result::kOk);
+
+  // LaunchSession() should not be called until we notify |maanger_| that the
+  // previous session was removed.
   EXPECT_CALL(message_handler_,
               LaunchSession(kChannelId, "BBBBBBBB", kDefaultLaunchTimeout, _));
-  std::move(result_callback_).Run(cast_channel::Result::kOk);
+  manager_->OnSessionRemoved(sink_);
 }
 
 TEST_F(CastActivityManagerTest, AddRemoveNonLocalActivity) {
@@ -422,6 +427,7 @@
   manager_->OnSessionAddedOrUpdated(sink_, *session);
 }
 
+// TODO(takumif): Add a test case to terminate a session and launch another.
 TEST_F(CastActivityManagerTest, TerminateSession) {
   LaunchCastAppSession();
   TerminateSession(true);
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
index 3187bd1..f6b182b 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "base/sequence_checker.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
@@ -131,18 +132,25 @@
 class TestObserver : public NavigationPredictorKeyedService::Observer {
  public:
   TestObserver() {}
-  ~TestObserver() override {}
+  ~TestObserver() override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  }
 
   base::Optional<NavigationPredictorKeyedService::Prediction> last_prediction()
       const {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return last_prediction_;
   }
 
-  size_t count_predictions() const { return count_predictions_; }
+  size_t count_predictions() const {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    return count_predictions_;
+  }
 
   // Waits until the count if received notifications is at least
   // |expected_notifications_count|.
   void WaitUntilNotificationsCountReached(size_t expected_notifications_count) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     // Ensure that |wait_loop_| is null implying there is no ongoing wait.
     ASSERT_FALSE(!!wait_loop_);
 
@@ -158,6 +166,7 @@
   void OnPredictionUpdated(
       const base::Optional<NavigationPredictorKeyedService::Prediction>
           prediction) override {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     ++count_predictions_;
     last_prediction_ = prediction;
     if (wait_loop_ && count_predictions_ >= expected_notifications_count_) {
@@ -176,6 +185,8 @@
   std::unique_ptr<base::RunLoop> wait_loop_;
   base::Optional<size_t> expected_notifications_count_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(TestObserver);
 };
 
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.cc b/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.cc
index 3f6dc6e7..4c79c0c 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_keyed_service.cc
@@ -37,11 +37,57 @@
 }
 
 NavigationPredictorKeyedService::Prediction::Prediction(
-    const NavigationPredictorKeyedService::Prediction& other) = default;
+    const NavigationPredictorKeyedService::Prediction& other)
+    : web_contents_(other.web_contents_),
+      prediction_source_(other.prediction_source_) {
+  // Use non-default copy constructor operator that does deep-copy.
+  if (other.source_document_url_)
+    source_document_url_ = other.source_document_url_;
+
+  if (other.external_app_packages_name_) {
+    external_app_packages_name_ = std::vector<std::string>();
+    external_app_packages_name_->reserve(
+        other.external_app_packages_name_->size());
+    for (const auto& entry : other.external_app_packages_name_.value())
+      external_app_packages_name_->push_back(entry);
+  }
+
+  sorted_predicted_urls_.reserve(other.sorted_predicted_urls_.size());
+  for (const auto& entry : other.sorted_predicted_urls_)
+    sorted_predicted_urls_.push_back(entry);
+}
 
 NavigationPredictorKeyedService::Prediction&
 NavigationPredictorKeyedService::Prediction::operator=(
-    const NavigationPredictorKeyedService::Prediction& other) = default;
+    const NavigationPredictorKeyedService::Prediction& other) {
+  // Use non-default assignment operator that does deep-copy.
+  web_contents_ = other.web_contents_;
+
+  source_document_url_.reset();
+  if (other.source_document_url_)
+    source_document_url_ = other.source_document_url_;
+
+  if (external_app_packages_name_)
+    external_app_packages_name_.reset();
+
+  if (other.external_app_packages_name_) {
+    external_app_packages_name_ = std::vector<std::string>();
+    external_app_packages_name_->reserve(
+        other.external_app_packages_name_->size());
+    for (const auto& entry : other.external_app_packages_name_.value())
+      external_app_packages_name_->push_back(entry);
+  } else {
+    external_app_packages_name_.reset();
+  }
+  prediction_source_ = other.prediction_source_;
+
+  sorted_predicted_urls_.clear();
+  sorted_predicted_urls_.reserve(other.sorted_predicted_urls_.size());
+  for (const auto& entry : other.sorted_predicted_urls_)
+    sorted_predicted_urls_.push_back(entry);
+
+  return *this;
+}
 
 NavigationPredictorKeyedService::Prediction::~Prediction() = default;
 
diff --git a/chrome/browser/predictors/loading_predictor_tab_helper.cc b/chrome/browser/predictors/loading_predictor_tab_helper.cc
index f5238262..ff88778 100644
--- a/chrome/browser/predictors/loading_predictor_tab_helper.cc
+++ b/chrome/browser/predictors/loading_predictor_tab_helper.cc
@@ -124,9 +124,6 @@
   if (!IsHandledNavigation(navigation_handle))
     return;
 
-  // Clear out prediction from previous navigation.
-  last_optimization_guide_prediction_ = base::nullopt;
-
   auto navigation_id = NavigationID(
       web_contents(),
       ukm::ConvertToSourceId(navigation_handle->GetNavigationId(),
@@ -260,6 +257,9 @@
 
   predictor_->loading_data_collector()->RecordMainFrameLoadComplete(
       navigation_id, last_optimization_guide_prediction_);
+
+  // Clear out Optimization Guide Prediction, as it is no longer needed.
+  last_optimization_guide_prediction_ = base::nullopt;
 }
 
 void LoadingPredictorTabHelper::OnOptimizationGuideDecision(
@@ -302,7 +302,12 @@
         OptimizationHintsReceiveStatus::kBeforeNavigationFinish);
   }
 
-  DCHECK(last_optimization_guide_prediction_);
+  if (!last_optimization_guide_prediction_) {
+    // Data for the navigation has already been recorded, do not proceed any
+    // further, even for counterfactual logging.
+    return;
+  }
+
   last_optimization_guide_prediction_->decision = decision;
 
   if (decision != optimization_guide::OptimizationGuideDecision::kTrue)
diff --git a/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc b/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc
index 5b08b0a..93a5df5 100644
--- a/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc
+++ b/chrome/browser/predictors/loading_predictor_tab_helper_unittest.cc
@@ -552,6 +552,59 @@
 }
 
 // Tests that document on load completed is recorded with correct navigation
+// id and optimization guide prediction and does not crash if callback comes
+// after everything has been recorded.
+TEST_F(
+    LoadingPredictorTabHelperOptimizationGuideDeciderTest,
+    DocumentOnLoadCompletedOptimizationGuidePredictionComesAfterDocumentOnLoad) {
+  base::HistogramTester histogram_tester;
+
+  optimization_guide::OptimizationMetadata optimization_metadata;
+  optimization_guide::proto::LoadingPredictorMetadata lp_metadata;
+  lp_metadata.add_subresources()->set_url("http://test.org/resource1");
+  lp_metadata.add_subresources()->set_url("http://other.org/resource2");
+  lp_metadata.add_subresources()->set_url("http://other.org/resource3");
+  optimization_metadata.set_loading_predictor_metadata(lp_metadata);
+  optimization_guide::OptimizationGuideDecisionCallback callback;
+  EXPECT_CALL(
+      *mock_optimization_guide_keyed_service_,
+      CanApplyOptimizationAsync(_, optimization_guide::proto::LOADING_PREDICTOR,
+                                base::test::IsNotNullCallback()))
+      .WillOnce(WithArg<2>(
+          Invoke([&](optimization_guide::OptimizationGuideDecisionCallback
+                         got_callback) -> void {
+            callback = std::move(got_callback);
+          })));
+  NavigateAndCommitInMainFrameAndVerifyMetrics("http://test.org");
+  auto navigation_id =
+      CreateNavigationID(GetTabID(), "http://test.org",
+                         web_contents()->GetLastCommittedSourceId());
+
+  // Adding subframe navigation to ensure that the committed main frame url will
+  // be used.
+  auto* subframe =
+      content::RenderFrameHostTester::For(main_rfh())->AppendChild("subframe");
+  NavigateAndCommitInFrame("http://sub.test.org", subframe);
+
+  base::Optional<OptimizationGuidePrediction> prediction =
+      OptimizationGuidePrediction();
+  prediction->decision =
+      optimization_guide::OptimizationGuideDecision::kUnknown;
+  EXPECT_CALL(*mock_collector_,
+              RecordMainFrameLoadComplete(navigation_id, prediction));
+  tab_helper_->DocumentOnLoadCompletedInMainFrame();
+
+  // Invoke callback after document completed in main frame..
+  std::move(callback).Run(optimization_guide::OptimizationGuideDecision::kTrue,
+                          optimization_metadata);
+
+  // Optimization guide predictions came after commit.
+  histogram_tester.ExpectUniqueSample(
+      "LoadingPredictor.OptimizationHintsReceiveStatus",
+      OptimizationHintsReceiveStatus::kAfterNavigationFinish, 1);
+}
+
+// Tests that document on load completed is recorded with correct navigation
 // id and optimization guide prediction with no prediction..
 TEST_F(LoadingPredictorTabHelperOptimizationGuideDeciderTest,
        DocumentOnLoadCompletedOptimizationGuidePredictionArrivedNoPrediction) {
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn
index df3e3c5d5..96160c38 100644
--- a/chrome/browser/resources/chromeos/login/BUILD.gn
+++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -230,7 +230,10 @@
 }
 
 js_library("oobe_dialog") {
-  deps = [ "//ui/webui/resources/cr_elements:cr_scrollable_behavior" ]
+  deps = [
+    "//ui/webui/resources/cr_elements:cr_scrollable_behavior",
+    "//ui/webui/resources/cr_elements/cr_lazy_render:cr_lazy_render",
+  ]
 }
 
 js_library("oobe_enable_kiosk") {
diff --git a/chrome/browser/resources/chromeos/login/arc_terms_of_service.html b/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
index 4418bce..da1b818 100644
--- a/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
+++ b/chrome/browser/resources/chromeos/login/arc_terms_of_service.html
@@ -11,9 +11,11 @@
     <link rel="stylesheet" href="oobe_dialog_host.css">
     <link rel="stylesheet" href="arc_terms_of_service.css">
     <link rel="stylesheet" href="oobe_flex_layout.css">
+    <!-- As this dialog have pre-loading logic that require access to elements,
+         dialog is marked as no-lazy. -->
     <oobe-dialog id="arcTosDialog" has-buttons class="arc-tos-loading"
         title-key="arcTermsOfServiceScreenHeading"
-        subtitle-key="arcTermsOfServiceScreenDescription">
+        subtitle-key="arcTermsOfServiceScreenDescription" no-lazy>
       <iron-icon src="chrome://oobe/playstore.svg" slot="oobe-icon">
       </iron-icon>
       <div id="arcTosContainer" slot="footer" class="flex layout vertical">
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog.html b/chrome/browser/resources/chromeos/login/oobe_dialog.html
index e0e5112..1514940 100644
--- a/chrome/browser/resources/chromeos/login/oobe_dialog.html
+++ b/chrome/browser/resources/chromeos/login/oobe_dialog.html
@@ -6,6 +6,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_scrollable_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html">
 
 <!--
   Simple OOBE dialog which should be used for OOBE UI elements.
@@ -75,38 +76,42 @@
     <link rel="stylesheet" href="oobe_dialog.css">
     <link rel="stylesheet" href="oobe_flex_layout.css">
     <style include="cr-shared-style"></style>
-    <div id="top-scroll-container" class="layout vertical flex" scrollable>
-      <div id="header-container" hidden="[[noHeader]]">
-        <div id="oobe-icon-div" class="slot-container">
-          <slot name="oobe-icon"></slot>
+    <cr-lazy-render id="lazy">
+      <template>
+        <div id="top-scroll-container" class="layout vertical flex" scrollable>
+          <div id="header-container" hidden="[[noHeader]]">
+            <div id="oobe-icon-div" class="slot-container">
+              <slot name="oobe-icon"></slot>
+            </div>
+            <div id="oobe-title" class="slot-container layout vertical
+                end-justified">
+              <slot name="title">
+                <h1 class="fallback">[[i18nDynamic(locale, titleKey)]]</h1>
+              </slot>
+            </div>
+            <div id="oobe-subtitle" class="slot-container layout vertical">
+              <slot name="subtitle">
+                <div class="fallback">[[i18nDynamic(locale, subtitleKey)]]</div>
+              </slot>
+            </div>
+            <div id="oobe-progress" class="slot-container layout vertical">
+              <slot name="progress"></slot>
+            </div>
+          </div>
+          <div id="footer-container" noFooterPadding$="[[noFooterPadding]]"
+              footerShrinkable$="[[footerShrinkable]]"
+              class="slot-container flex-grow layout vertical">
+            <slot name="footer"></slot>
+          </div>
         </div>
-        <div id="oobe-title" class="slot-container layout vertical
-            end-justified">
-          <slot name="title">
-            <h1 class="fallback">[[i18nDynamic(locale, titleKey)]]</h1>
-          </slot>
-        </div>
-        <div id="oobe-subtitle" class="slot-container layout vertical">
-          <slot name="subtitle">
-            <div class="fallback">[[i18nDynamic(locale, subtitleKey)]]</div>
-          </slot>
-        </div>
-        <div id="oobe-progress" class="slot-container layout vertical">
-          <slot name="progress"></slot>
-        </div>
-      </div>
-      <div id="footer-container" noFooterPadding$="[[noFooterPadding]]"
-          footerShrinkable$="[[footerShrinkable]]"
-          class="slot-container flex-grow layout vertical">
-        <slot name="footer"></slot>
-      </div>
-    </div>
-    <template is="dom-if" if="[[hasButtons]]">
-      <div id="oobe-bottom" hideShadow$="[[hideShadow]]"
-          class="slot-container layout horizontal center">
-        <slot name="bottom-buttons"></slot>
-      </div>
+        <template is="dom-if" if="[[hasButtons]]">
+          <div id="oobe-bottom" hideShadow$="[[hideShadow]]"
+              class="slot-container layout horizontal center">
+            <slot name="bottom-buttons"></slot>
+          </div>
+        </template>
+      </template>
     </template>
-  </template>
+  </cr-lazy-render>
 </dom-module>
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog.js b/chrome/browser/resources/chromeos/login/oobe_dialog.js
index 6373b423..0bc8dcc 100644
--- a/chrome/browser/resources/chromeos/login/oobe_dialog.js
+++ b/chrome/browser/resources/chromeos/login/oobe_dialog.js
@@ -80,6 +80,15 @@
       type: String,
     },
 
+    /**
+     * If set, prevents lazy instantiation of the dialog.
+     */
+    noLazy: {
+      type: Boolean,
+      value: false,
+      observer: 'onNoLazyChanged_',
+    }
+
   },
 
   focus() {
@@ -93,6 +102,7 @@
   },
 
   onBeforeShow() {
+    this.$$('#lazy').get();
     var isOobe = window.hasOwnProperty('Oobe') &&
         window.hasOwnProperty('DISPLAY_TYPE') && Oobe.getInstance() &&
         Oobe.getInstance().displayType == DISPLAY_TYPE.OOBE;
@@ -142,4 +152,10 @@
     if (this.fullScreenDialog)
       document.documentElement.setAttribute('full-screen-dialog', true);
   },
+
+  /** @private */
+  onNoLazyChanged_() {
+    if (this.noLazy)
+      this.$$('#lazy').get();
+  }
 });
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.html b/chrome/browser/resources/chromeos/login/oobe_eula.html
index 7c34384..c91edbb3c 100644
--- a/chrome/browser/resources/chromeos/login/oobe_eula.html
+++ b/chrome/browser/resources/chromeos/login/oobe_eula.html
@@ -21,10 +21,12 @@
           icon1x="oobe-32:googleg" icon2x="oobe-64:googleg">
       </hd-iron-icon>
     </oobe-dialog>
+    <!-- As this dialog have pre-loading logic that require access to elements,
+         dialog is marked as no-lazy. -->
     <oobe-dialog id="eulaDialog" hidden="[[eulaLoadingScreenShown]]"
         role="dialog" title-key="oobeEulaSectionTitle"
         aria-label$="[[i18nDynamic(locale, 'oobeEulaSectionTitle')]]"
-        aria-describedby="crosEulaFrame" has-buttons>
+        aria-describedby="crosEulaFrame" has-buttons no-lazy>
       <hd-iron-icon slot="oobe-icon"
           icon1x="oobe-32:googleg" icon2x="oobe-64:googleg">
       </hd-iron-icon>
diff --git a/chrome/browser/resources/chromeos/login/oobe_terms_of_service.html b/chrome/browser/resources/chromeos/login/oobe_terms_of_service.html
index edf72c75..854a6c7c 100644
--- a/chrome/browser/resources/chromeos/login/oobe_terms_of_service.html
+++ b/chrome/browser/resources/chromeos/login/oobe_terms_of_service.html
@@ -30,9 +30,11 @@
     </oobe-dialog>
 
     <!-- NORMAL DIALOG -->
+    <!-- As this dialog have pre-loading logic that require access to elements,
+         dialog is marked as no-lazy. -->
     <oobe-dialog id="termsOfServiceDialog" role="dialog"
         aria-labelledby="title"
-        hidden="[[isInErrorState_(uiState)]]" has-buttons>
+        hidden="[[isInErrorState_(uiState)]]" has-buttons no-lazy>
       <hd-iron-icon slot="oobe-icon" id="termsOfServiceGoogleIcon"
           icon1x="oobe-32:googleg" icon2x="oobe-64:googleg">
       </hd-iron-icon>
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.html b/chrome/browser/resources/chromeos/login/screen_gaia_signin.html
index f6689370..3a85df7 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.html
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.html
@@ -11,9 +11,11 @@
     <link rel="stylesheet" href="oobe_flex_layout.css">
     <link rel="stylesheet" href="oobe_popup_overlay.css">
     <link rel="stylesheet" href="screen_gaia_signin.css">
+    <!-- As this dialog have pre-loading logic that require access to elements,
+         dialog is marked as no-lazy. -->
     <oobe-dialog id="signin-frame-dialog" class="gaia-dialog" role="dialog"
         has-buttons="[[!isSamlSsoVisible_]]"
-        no-header no-footer-padding
+        no-header no-footer-padding no-lazy
         hidden="[[!isStep_(step_, 'online-gaia', 'gaia-loading')]]">
       <div slot="footer" class="flex layout vertical">
         <div id="signin-frame-container" transparent$="[[isLoadingUiShown_]]"
diff --git a/chrome/browser/resources/chromeos/login/security_token_pin.js b/chrome/browser/resources/chromeos/login/security_token_pin.js
index cc7981a..c3f145ad 100644
--- a/chrome/browser/resources/chromeos/login/security_token_pin.js
+++ b/chrome/browser/resources/chromeos/login/security_token_pin.js
@@ -101,6 +101,15 @@
     this.$.pinKeyboard.focusInputSynchronously();
   },
 
+  /** @override */
+  onBeforeShow() {
+    this.behaviors.forEach((behavior) => {
+      if (behavior.onBeforeShow)
+        behavior.onBeforeShow.call(this);
+    });
+    this.$$('#dialog').onBeforeShow();
+  },
+
   /**
    * Returns the i18n string ID for the current error label.
    * @param {OobeTypes.SecurityTokenPinDialogParameters} parameters
diff --git a/chrome/browser/resources/media/media_feeds.html b/chrome/browser/resources/media/media_feeds.html
index b7e3edf..3fedcd7 100644
--- a/chrome/browser/resources/media/media_feeds.html
+++ b/chrome/browser/resources/media/media_feeds.html
@@ -110,8 +110,8 @@
         <th sort-key="fetchFailedCount">
           Fetch Failed Count
         </th>
-        <th sort-key="cacheExpiryTime">
-          Cache Expiry Time
+        <th sort-key="lastFetchTimeNotCacheHit">
+          Last Fetch Time (not cache hit)
         </th>
         <th sort-key="lastFetchItemCount">
           Last Fetch Item Count
diff --git a/chrome/browser/resources/media/media_feeds.js b/chrome/browser/resources/media/media_feeds.js
index 9f0e173..b398331 100644
--- a/chrome/browser/resources/media/media_feeds.js
+++ b/chrome/browser/resources/media/media_feeds.js
@@ -62,7 +62,7 @@
       td.textContent = data.url;
     } else if (
         key === 'lastDiscoveryTime' || key === 'lastFetchTime' ||
-        key === 'cacheExpiryTime' || key === 'datePublished') {
+        key === 'lastFetchTimeNotCacheHit' || key === 'datePublished') {
       // Format a mojo time.
       td.textContent =
           convertMojoTimeToJS(/** @type {mojoBase.mojom.Time} */ (data))
@@ -277,7 +277,7 @@
       return val1 > val2 ? 1 : -1;
     } else if (
         sortKey === 'lastDiscoveryTime' || sortKey === 'lastFetchTime' ||
-        sortKey === 'cacheExpiryTime') {
+        sortKey === 'lastFetchTimeNotCacheHit') {
       return val1.internalValue > val2.internalValue ? 1 : -1;
     }
 
diff --git a/chrome/browser/resources/new_tab_page/app.html b/chrome/browser/resources/new_tab_page/app.html
index c1335375..f155163 100644
--- a/chrome/browser/resources/new_tab_page/app.html
+++ b/chrome/browser/resources/new_tab_page/app.html
@@ -183,7 +183,7 @@
     <dom-if if="[[showCustomizeDialog_]]" restamp>
       <template>
         <ntp-customize-dialog on-close="onCustomizeDialogClose_"
-            theme="[[theme_]]">
+            theme="[[theme_]]" background-selection="{{backgroundSelection_}}">
         </ntp-customize-dialog>
       </template>
     </dom-if>
@@ -205,17 +205,17 @@
       </cr-button>
     </div>
     <a id="backgroundImageAttribution"
-        href="[[theme_.backgroundImageAttributionUrl.url]]"
-        hidden="[[!theme_.backgroundImageAttribution1]]">
+        href="[[backgroundImageAttributionUrl_]]"
+        hidden="[[!backgroundImageAttribution1_]]">
       <div id="backgroundImageAttribution1Container">
         <div id="linkIcon"></div>
         <div id="backgroundImageAttribution1">
-          [[theme_.backgroundImageAttribution1]]
+          [[backgroundImageAttribution1_]]
         </div>
       </div>
       <div id="backgroundImageAttribution2"
-          hidden="[[!theme_.backgroundImageAttribution2]]">
-        [[theme_.backgroundImageAttribution2]]
+          hidden="[[!backgroundImageAttribution2_]]">
+        [[backgroundImageAttribution2_]]
       </div>
     </a>
   </div>
diff --git a/chrome/browser/resources/new_tab_page/app.js b/chrome/browser/resources/new_tab_page/app.js
index 89ad0ed..8070019a 100644
--- a/chrome/browser/resources/new_tab_page/app.js
+++ b/chrome/browser/resources/new_tab_page/app.js
@@ -17,6 +17,7 @@
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {BrowserProxy} from './browser_proxy.js';
+import {BackgroundSelection, BackgroundSelectionType} from './customize_dialog.js';
 import {skColorToRgb} from './utils.js';
 
 class AppElement extends PolymerElement {
@@ -53,14 +54,41 @@
 
       /** @private */
       showBackgroundImage_: {
-        computed: 'computeShowBackgroundImage_(theme_)',
+        computed: 'computeShowBackgroundImage_(theme_, backgroundSelection_)',
         reflectToAttribute: true,
         type: Boolean,
       },
 
+      /** @private {!BackgroundSelection} */
+      backgroundSelection_: {
+        type: Object,
+        value: () => ({type: BackgroundSelectionType.NO_SELECTION}),
+      },
+
+      /** @private */
+      backgroundImageAttribution1_: {
+        type: String,
+        computed: `computeBackgroundImageAttribution1_(theme_,
+            backgroundSelection_)`,
+      },
+
+      /** @private */
+      backgroundImageAttribution2_: {
+        type: String,
+        computed: `computeBackgroundImageAttribution2_(theme_,
+            backgroundSelection_)`,
+      },
+
+      /** @private */
+      backgroundImageAttributionUrl_: {
+        type: String,
+        computed: `computeBackgroundImageAttributionUrl_(theme_,
+            backgroundSelection_)`,
+      },
+
       /** @private */
       backgroundImagePath_: {
-        computed: 'computeBackgroundImagePath_(theme_)',
+        computed: 'computeBackgroundImagePath_(theme_, backgroundSelection_)',
         type: String,
       },
 
@@ -118,6 +146,59 @@
     this.eventTracker_.removeAll();
   }
 
+  /**
+   * @return {string}
+   * @private
+   */
+  computeBackgroundImageAttribution1_() {
+    switch (this.backgroundSelection_.type) {
+      case BackgroundSelectionType.NO_SELECTION:
+        return this.theme_ && this.theme_.backgroundImageAttribution1 || '';
+      case BackgroundSelectionType.IMAGE:
+        return this.backgroundSelection_.image.attribution1;
+      case BackgroundSelectionType.NO_BACKGROUND:
+      case BackgroundSelectionType.DAILY_REFRESH:
+      default:
+        return '';
+    }
+  }
+
+  /**
+   * @return {string}
+   * @private
+   */
+  computeBackgroundImageAttribution2_() {
+    switch (this.backgroundSelection_.type) {
+      case BackgroundSelectionType.NO_SELECTION:
+        return this.theme_ && this.theme_.backgroundImageAttribution2 || '';
+      case BackgroundSelectionType.IMAGE:
+        return this.backgroundSelection_.image.attribution2;
+      case BackgroundSelectionType.NO_BACKGROUND:
+      case BackgroundSelectionType.DAILY_REFRESH:
+      default:
+        return '';
+    }
+  }
+
+  /**
+   * @return {string}
+   * @private
+   */
+  computeBackgroundImageAttributionUrl_() {
+    switch (this.backgroundSelection_.type) {
+      case BackgroundSelectionType.NO_SELECTION:
+        return this.theme_ && this.theme_.backgroundImageAttributionUrl ?
+            this.theme_.backgroundImageAttributionUrl.url :
+            '';
+      case BackgroundSelectionType.IMAGE:
+        return this.backgroundSelection_.image.attributionUrl.url;
+      case BackgroundSelectionType.NO_BACKGROUND:
+      case BackgroundSelectionType.DAILY_REFRESH:
+      default:
+        return '';
+    }
+  }
+
   /** @private */
   onVoiceSearchClick_() {
     this.showVoiceSearchOverlay_ = true;
@@ -152,7 +233,16 @@
    * @private
    */
   computeShowBackgroundImage_() {
-    return !!this.theme_ && !!this.theme_.backgroundImageUrl;
+    switch (this.backgroundSelection_.type) {
+      case BackgroundSelectionType.NO_SELECTION:
+        return !!this.theme_ && !!this.theme_.backgroundImageUrl;
+      case BackgroundSelectionType.IMAGE:
+        return true;
+      case BackgroundSelectionType.NO_BACKGROUND:
+      case BackgroundSelectionType.DAILY_REFRESH:
+      default:
+        return false;
+    }
   }
 
   /**
@@ -160,10 +250,19 @@
    * @private
    */
   computeBackgroundImagePath_() {
-    if (!this.theme_ || !this.theme_.backgroundImageUrl) {
-      return '';
+    switch (this.backgroundSelection_.type) {
+      case BackgroundSelectionType.NO_SELECTION:
+        return this.theme_ && this.theme_.backgroundImageUrl ?
+            `background_image?${this.theme_.backgroundImageUrl.url}` :
+            '';
+      case BackgroundSelectionType.IMAGE:
+        return `background_image?${
+            this.backgroundSelection_.image.imageUrl.url}`;
+      case BackgroundSelectionType.NO_BACKGROUND:
+      case BackgroundSelectionType.DAILY_REFRESH:
+      default:
+        return '';
     }
-    return `background_image?${this.theme_.backgroundImageUrl.url}`;
   }
 
   /**
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.html b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.html
index d5ee6804..98cfad6c 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.html
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.html
@@ -3,6 +3,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="os_languages_page.html">
+<link rel="import" href="smart_inputs_page.html">
 <link rel="import" href="../../i18n_setup.html">
 <link rel="import" href="../../languages_page/languages.html">
 <link rel="import" href="manage_input_methods_page.html">
@@ -34,6 +35,15 @@
             on-click="onLanguagesTap_"
             role-description="$i18n{subpageArrowRoleDescription}">
         </cr-link-row>
+        <template is="dom-if" if="[[smartInputsEnabled_]]">
+          <cr-link-row
+              class="hr"
+              id="smartInputsSubpageTrigger"
+              label="$i18n{smartInputsTitle}"
+              on-click="onSmartInputsClick_"
+              role-description="$i18n{subpageArrowRoleDescription}">
+          </cr-link-row>
+        </template>
       </div>
 
       <!-- "Language and input" sub-page. -->
@@ -50,6 +60,16 @@
         </settings-subpage>
       </template>
 
+      <!-- "Smart inputs" sub-page. -->
+      <template is="dom-if" route-path="/osLanguages/smartInputs">
+        <settings-subpage
+            associated-control="[[$$('#smartInputsSubpageTrigger')]]"
+            page-title="$i18n{smartInputsTitle}">
+          <os-settings-smart-inputs-page prefs="{{prefs}}">
+          </os-settings-smart-inputs-page>
+        </settings-subpage>
+      </template>
+
       <!-- "Manage input methods" sub-sub-page. -->
       <template is="dom-if" route-path="/osLanguages/inputMethods">
         <!-- TODO(crbug.com/950007): Associate control with the sub-subpage
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.js b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.js
index e9d6153..d3dbee6 100644
--- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.js
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.js
@@ -32,8 +32,24 @@
               settings.routes.OS_LANGUAGES_DETAILS.path,
               '#languagesSubpageTrigger');
         }
+        if (settings.routes.OS_LANGUAGES_SMART_INPUTS) {
+          map.set(
+              settings.routes.OS_LANGUAGES_SMART_INPUTS.path,
+              '#smartInputsSubpageTrigger');
+        }
         return map;
       },
+    },
+
+    /**
+     * This is enabled when any of the smart inputs features is allowed.
+     * @private
+     * */
+    smartInputsEnabled_: {
+      type: Boolean,
+      value() {
+        return loadTimeData.getBoolean('allowAssistivePersonalInfo');
+      },
     }
   },
 
@@ -44,6 +60,12 @@
         settings.routes.OS_LANGUAGES_DETAILS);
   },
 
+  /** @private */
+  onSmartInputsClick_() {
+    settings.Router.getInstance().navigateTo(
+        settings.routes.OS_LANGUAGES_SMART_INPUTS);
+  },
+
   /**
    * @param {string} uiLanguage Current UI language fully specified, e.g.
    *     "English (United States)".
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.html b/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.html
new file mode 100644
index 0000000..5f00da4c
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.html
@@ -0,0 +1,43 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="../../controls/settings_toggle_button.html">
+<link rel="import" href="../../i18n_setup.html">
+<link rel="import" href="../../prefs/prefs_behavior.html">
+<link rel="import" href="../../settings_shared_css.html">
+
+<dom-module id="os-settings-smart-inputs-page">
+  <template>
+    <style include="settings-shared">
+      h2 {
+        padding-inline-start: var(--cr-section-padding);
+      }
+    </style>
+
+    <div route-path="default">
+      <template is="dom-if" if="[[allowAssistivePersonalInfo_]]">
+        <div id="assistPersonalInfo">
+          <h2 aria-describedby="personalInfoSuggestionDescription">
+            $i18n{personalInfoSuggestionTitle}
+          </h2>
+          <span class="settings-box first" aria-hidden="true"
+              id="personalInfoSuggestionDescription">
+            $i18n{personalInfoSuggestionDescription}
+          </span>
+          <div class="list-frame vertical-list">
+            <settings-toggle-button class="list-item first"
+                pref="{{prefs.assistive_feature_enabled.personal_info_suggester}}"
+                label="$i18n{showPersonalInfoSuggestion}">
+            </settings-toggle-button>
+            <cr-link-row class="hr list-item"
+                label="$i18n{managePersonalInfo}"
+                on-click="onManagePersonalInfoClick_" external>
+            </cr-link-row>
+          </div>
+        </div>
+      </template>
+    </div>
+  </template>
+  <script src="smart_inputs_page.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.js
new file mode 100644
index 0000000..2f72502
--- /dev/null
+++ b/chrome/browser/resources/settings/chromeos/os_languages_page/smart_inputs_page.js
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview 'os-settings-smart-inputs-page' is the settings sub-page
+ * to provide users with assistive or expressive input options.
+ */
+
+Polymer({
+  is: 'os-settings-smart-inputs-page',
+
+  behaviors: [
+    I18nBehavior,
+    PrefsBehavior,
+  ],
+
+  properties: {
+    /** Preferences state. */
+    prefs: {
+      type: Object,
+      notify: true,
+    },
+
+    /** @private */
+    allowAssistivePersonalInfo_: {
+      type: Boolean,
+      value() {
+        return loadTimeData.getBoolean('allowAssistivePersonalInfo');
+      },
+    }
+  },
+
+  /**
+   * Opens Chrome browser's autofill manage addresses setting page.
+   * @private
+   */
+  onManagePersonalInfoClick_() {
+    window.open('chrome://settings/addresses');
+  },
+});
diff --git a/chrome/browser/resources/settings/chromeos/os_route.js b/chrome/browser/resources/settings/chromeos/os_route.js
index ebe9d68..738a87a 100644
--- a/chrome/browser/resources/settings/chromeos/os_route.js
+++ b/chrome/browser/resources/settings/chromeos/os_route.js
@@ -104,6 +104,8 @@
     r.OS_LANGUAGES_DETAILS = r.OS_LANGUAGES.createChild('/osLanguages/details');
     r.OS_LANGUAGES_INPUT_METHODS =
         r.OS_LANGUAGES.createChild('/osLanguages/inputMethods');
+    r.OS_LANGUAGES_SMART_INPUTS =
+        r.OS_LANGUAGES.createChild('/osLanguages/smartInputs');
 
     r.OS_PRINTING = r.ADVANCED.createSection('/osPrinting', 'osPrinting');
 
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_routes.js b/chrome/browser/resources/settings/chromeos/os_settings_routes.js
index 936db70c0..3ace0bb 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_routes.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings_routes.js
@@ -53,6 +53,7 @@
  *   OS_LANGUAGES: !settings.Route,
  *   OS_LANGUAGES_DETAILS: !settings.Route,
  *   OS_LANGUAGES_INPUT_METHODS: !settings.Route,
+ *   OS_LANGUAGES_SMART_INPUTS: !settings.Route,
  *   OS_PRINTING: !settings.Route,
  *   OS_PRIVACY: !settings.Route,
  *   OS_RESET: !settings.Route,
@@ -76,4 +77,4 @@
  *   SYNC_ADVANCED: !settings.Route,
  * }}
  */
-/* #export */ let OsSettingsRoutes;
\ No newline at end of file
+/* #export */ let OsSettingsRoutes;
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd
index 07fe9067..839f5c6 100644
--- a/chrome/browser/resources/settings/os_settings_resources.grd
+++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -621,6 +621,12 @@
       <structure name="IDR_OS_SETTINGS_LANGUAGES_MANAGE_INPUT_METHODS_PAGE_JS"
                  file="chromeos/os_languages_page/manage_input_methods_page.js"
                  type="chrome_html" />
+      <structure name="IDR_OS_SETTINGS_LANGUAGES_SMART_INPUTS_PAGE_HTML"
+                 file="chromeos/os_languages_page/smart_inputs_page.html"
+                 type="chrome_html" />
+      <structure name="IDR_OS_SETTINGS_LANGUAGES_SMART_INPUTS_PAGE_JS"
+                 file="chromeos/os_languages_page/smart_inputs_page.js"
+                 type="chrome_html" />
       <structure name="IDR_OS_SETTINGS_OS_SEARCH_RESULT_ROW_JS"
                  file="chromeos/os_settings_search_box/os_search_result_row.js"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/settings/privacy_page/BUILD.gn b/chrome/browser/resources/settings/privacy_page/BUILD.gn
index 3c1f649..25d75501 100644
--- a/chrome/browser/resources/settings/privacy_page/BUILD.gn
+++ b/chrome/browser/resources/settings/privacy_page/BUILD.gn
@@ -563,7 +563,7 @@
                    "chrome/browser/resources/settings/metrics_browser_proxy.html|PrivacyElementInteractions,MetricsBrowserProxyImpl",
                    "chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.html|PrivacyPageBrowserProxy,PrivacyPageBrowserProxyImpl",
                    "chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.html|SiteSettingsPrefsBrowserProxyImpl",
-                   "chrome/browser/resources/settings/site_settings/constants.html|ContentSettingsTypes,CookieControlsMode,ChooserType",
+                   "chrome/browser/resources/settings/site_settings/constants.html|ContentSettingsTypes,ChooserType",
                    "chrome/browser/resources/settings/people_page/sync_browser_proxy.html|SyncBrowserProxyImpl,SyncStatus",
                    "chrome/browser/resources/settings/hats_browser_proxy.html|HatsBrowserProxyImpl",
                    "chrome/browser/resources/settings/page_visibility.html|PrivacyPageVisibility",
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 956a14e..cde7a30 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -273,13 +273,9 @@
               sub-option-mode="cookies-session-only">
           </category-default-setting>
           <settings-toggle-button
-              id="blockThirdPartyCookies"
               pref="{{prefs.profile.block_third_party_cookies}}"
               label="$i18n{thirdPartyCookie}"
-              sub-label="$i18n{thirdPartyCookieSublabel}"
-              on-settings-boolean-control-change=
-                  "onBlockThirdPartyCookiesToggleChange_"
-              no-set-pref>
+              sub-label="$i18n{thirdPartyCookieSublabel}">
           </settings-toggle-button>
           <cr-link-row id="site-data-trigger" class="hr"
               on-click="onSiteDataTap_" label="$i18n{siteSettingsCookieLink}">
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js
index 316757c0..9e03e975 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -416,20 +416,6 @@
     },
 
     /**
-     * Updates both required block third party cookie preferences.
-     * @param {!Event} event
-     * @private
-     */
-    onBlockThirdPartyCookiesToggleChange_(event) {
-      const target = /** @type {!SettingsToggleButtonElement} */ (event.target);
-      this.setPrefValue('profile.block_third_party_cookies', target.checked);
-      this.setPrefValue(
-          'profile.cookie_controls_mode',
-          target.checked ? settings.CookieControlsMode.ENABLED :
-                           settings.CookieControlsMode.DISABLED);
-    },
-
-    /**
      * Records changes made to the "can a website check if you have saved
      * payment methods" setting for logging, the logic of actually changing the
      * setting is taken care of by the webUI pref.
diff --git a/chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.cc b/chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.cc
index c6e9b80..77fd7c24 100644
--- a/chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.cc
+++ b/chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.cc
@@ -12,13 +12,12 @@
 #include "base/syslog_logging.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/browser/spellchecker/spellcheck_service.h"
 #include "chrome/common/pref_names.h"
 #include "components/policy/core/browser/policy_error_map.h"
 #include "components/policy/policy_constants.h"
 #include "components/prefs/pref_value_map.h"
 #include "components/spellcheck/browser/pref_names.h"
-#include "components/spellcheck/common/spellcheck_features.h"
+#include "components/spellcheck/common/spellcheck_common.h"
 #include "components/strings/grit/components_strings.h"
 
 SpellcheckLanguageBlacklistPolicyHandler::
@@ -114,11 +113,9 @@
   // Separate the valid languages from the unknown / unsupported languages and
   // the languages that also appear in the SpellcheckLanguage policy.
   for (const base::Value& language : value->GetList()) {
-    std::string candidate_language =
-        base::TrimWhitespaceASCII(language.GetString(), base::TRIM_ALL)
-            .as_string();
     std::string current_language =
-        SpellcheckService::GetSupportedAcceptLanguageCode(candidate_language);
+        spellcheck::GetCorrespondingSpellCheckLanguage(
+            base::TrimWhitespaceASCII(language.GetString(), base::TRIM_ALL));
 
     if (current_language.empty()) {
       unknown->emplace_back(language.GetString());
diff --git a/chrome/browser/spellchecker/spellcheck_language_policy_handler.cc b/chrome/browser/spellchecker/spellcheck_language_policy_handler.cc
index 7724da7d..b5407f5 100644
--- a/chrome/browser/spellchecker/spellcheck_language_policy_handler.cc
+++ b/chrome/browser/spellchecker/spellcheck_language_policy_handler.cc
@@ -11,13 +11,12 @@
 #include "base/syslog_logging.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/browser/spellchecker/spellcheck_service.h"
 #include "chrome/common/pref_names.h"
 #include "components/policy/core/browser/policy_error_map.h"
 #include "components/policy/policy_constants.h"
 #include "components/prefs/pref_value_map.h"
 #include "components/spellcheck/browser/pref_names.h"
-#include "components/spellcheck/common/spellcheck_features.h"
+#include "components/spellcheck/common/spellcheck_common.h"
 #include "components/strings/grit/components_strings.h"
 
 SpellcheckLanguagePolicyHandler::SpellcheckLanguagePolicyHandler()
@@ -87,11 +86,9 @@
 
   // Separate the valid languages from the unknown / unsupported languages.
   for (const base::Value& language : value->GetList()) {
-    std::string candidate_language =
-        base::TrimWhitespaceASCII(language.GetString(), base::TRIM_ALL)
-            .as_string();
     std::string current_language =
-        SpellcheckService::GetSupportedAcceptLanguageCode(candidate_language);
+        spellcheck::GetCorrespondingSpellCheckLanguage(
+            base::TrimWhitespaceASCII(language.GetString(), base::TRIM_ALL));
 
     if (current_language.empty()) {
       unknown->emplace_back(language.GetString());
diff --git a/chrome/browser/spellchecker/spellcheck_language_policy_handlers_unittest.cc b/chrome/browser/spellchecker/spellcheck_language_policy_handlers_unittest.cc
deleted file mode 100644
index 5427e8df..0000000
--- a/chrome/browser/spellchecker/spellcheck_language_policy_handlers_unittest.cc
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Chromium style is to have one unit test per one header file. However, the
-// applied blocked spellcheck language policy depends on the applied forced
-// language policy. If a language is both blocked and forced, forced wins. It is
-// only practical to test this interaction in a single unit test covering both
-// header files.
-#include "chrome/browser/spellchecker/spellcheck_language_blacklist_policy_handler.h"
-#include "chrome/browser/spellchecker/spellcheck_language_policy_handler.h"
-
-#include <ostream>
-#include <string>
-#include <vector>
-
-#include "base/strings/string_util.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/values.h"
-#include "chrome/common/pref_names.h"
-#include "components/policy/core/common/policy_map.h"
-#include "components/policy/policy_constants.h"
-#include "components/prefs/pref_value_map.h"
-#include "components/spellcheck/browser/pref_names.h"
-#include "components/spellcheck/common/spellcheck_features.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace policy {
-
-struct TestCase {
-  TestCase(const std::vector<std::string>& blocked_languages,
-           const std::vector<std::string>& forced_languages,
-           const std::vector<std::string>& expected_blocked_languages,
-           const std::vector<std::string>& expected_forced_languages,
-           bool spellcheck_enabled,
-           bool windows_spellchecker_enabled)
-      : blocked_languages(blocked_languages),
-        forced_languages(forced_languages),
-        expected_blocked_languages(expected_blocked_languages),
-        expected_forced_languages(expected_forced_languages),
-        spellcheck_enabled(spellcheck_enabled),
-        windows_spellchecker_enabled(windows_spellchecker_enabled) {}
-
-  std::vector<std::string> blocked_languages;
-  std::vector<std::string> forced_languages;
-  std::vector<std::string> expected_blocked_languages;
-  std::vector<std::string> expected_forced_languages;
-  bool spellcheck_enabled;
-  bool windows_spellchecker_enabled;
-};
-
-std::ostream& operator<<(std::ostream& out, const TestCase& test_case) {
-  out << "blocked_languages=["
-      << base::JoinString(test_case.blocked_languages, ",")
-      << "], forced_languages=["
-      << base::JoinString(test_case.forced_languages, ",")
-      << "], expected_blocked_languages=["
-      << base::JoinString(test_case.expected_blocked_languages, ",")
-      << "], expected_forced_languages=["
-      << base::JoinString(test_case.expected_forced_languages, ",")
-      << "], spellcheck_enabled=" << test_case.spellcheck_enabled
-      << "], windows_spellchecker_enabled="
-      << test_case.windows_spellchecker_enabled;
-  return out;
-}
-
-class SpellcheckLanguagePolicyHandlersTest
-    : public testing::TestWithParam<TestCase> {
- public:
-  SpellcheckLanguagePolicyHandlersTest() = default;
-  ~SpellcheckLanguagePolicyHandlersTest() override = default;
-
-  void CheckPrefs(const PrefValueMap& prefs,
-                  const std::string& key,
-                  const std::vector<std::string>& expected) {
-    // Retrieve the spellcheck enabled pref (if it exists).
-    const base::Value* spellcheck_enabled_pref = nullptr;
-    const bool is_spellcheck_enabled_pref_set = prefs.GetValue(
-        spellcheck::prefs::kSpellCheckEnable, &spellcheck_enabled_pref);
-
-    const base::Value* languages_list = nullptr;
-    if (GetParam().spellcheck_enabled) {
-      EXPECT_TRUE(is_spellcheck_enabled_pref_set);
-      EXPECT_TRUE(spellcheck_enabled_pref->is_bool());
-      EXPECT_TRUE(spellcheck_enabled_pref->GetBool());
-
-      EXPECT_TRUE(prefs.GetValue(key, &languages_list));
-      EXPECT_TRUE(languages_list->is_list());
-      EXPECT_EQ(expected.size(), languages_list->GetList().size());
-
-      for (const auto& language : languages_list->GetList()) {
-        EXPECT_TRUE(language.is_string());
-        EXPECT_TRUE(std::find(expected.begin(), expected.end(),
-                              language.GetString()) != expected.end());
-      }
-    } else {
-      EXPECT_FALSE(is_spellcheck_enabled_pref_set);
-      // No language list should be added to prefs if spellchecking disabled.
-      EXPECT_FALSE(prefs.GetValue(key, &languages_list));
-    }
-  }
-};
-
-TEST_P(SpellcheckLanguagePolicyHandlersTest, ApplyPolicySettings) {
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
-  base::test::ScopedFeatureList feature_list;
-  if (GetParam().windows_spellchecker_enabled) {
-    // Force hybrid spellchecking to be enabled.
-    feature_list.InitWithFeatures(
-        /*enabled_features=*/{spellcheck::kWinUseBrowserSpellChecker,
-                              spellcheck::kWinUseHybridSpellChecker},
-        /*disabled_features=*/{});
-  } else {
-    // Hunspell-only spellcheck languages will be used.
-    feature_list.InitAndDisableFeature(spellcheck::kWinUseBrowserSpellChecker);
-  }
-#endif  // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
-
-  PrefValueMap prefs;
-  policy::PolicyMap policy;
-
-  base::Value blocked_languages_list(base::Value::Type::LIST);
-  for (const auto& blocked_language : GetParam().blocked_languages) {
-    blocked_languages_list.Append(std::move(blocked_language));
-  }
-
-  base::Value forced_languages_list(base::Value::Type::LIST);
-  for (const auto& forced_language : GetParam().forced_languages) {
-    forced_languages_list.Append(std::move(forced_language));
-  }
-
-  policy.Set(policy::key::kSpellcheckLanguageBlacklist,
-             policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
-             policy::POLICY_SOURCE_ENTERPRISE_DEFAULT,
-             base::Value::ToUniquePtrValue(std::move(blocked_languages_list)),
-             nullptr);
-
-  policy.Set(
-      policy::key::kSpellcheckLanguage, policy::POLICY_LEVEL_MANDATORY,
-      policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_ENTERPRISE_DEFAULT,
-      base::Value::ToUniquePtrValue(std::move(forced_languages_list)), nullptr);
-
-  policy.Set(
-      policy::key::kSpellcheckEnabled, policy::POLICY_LEVEL_MANDATORY,
-      policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_ENTERPRISE_DEFAULT,
-      std::make_unique<base::Value>(GetParam().spellcheck_enabled), nullptr);
-
-  // Apply policy to the forced languages handler.
-  SpellcheckLanguagePolicyHandler forced_languages_handler;
-  forced_languages_handler.ApplyPolicySettings(policy, &prefs);
-
-  // Apply policy to the blocked languages handler.
-  SpellcheckLanguageBlacklistPolicyHandler blocked_languages_handler;
-  blocked_languages_handler.ApplyPolicySettings(policy, &prefs);
-
-  // Check if forced languages preferences are as expected.
-  CheckPrefs(prefs, spellcheck::prefs::kSpellCheckForcedDictionaries,
-             GetParam().expected_forced_languages);
-
-  // Check if blocked languages preferences are as expected.
-  CheckPrefs(prefs, spellcheck::prefs::kSpellCheckBlacklistedDictionaries,
-             GetParam().expected_blocked_languages);
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    TestCases,
-    SpellcheckLanguagePolicyHandlersTest,
-    testing::Values(
-#if BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
-        // Test cases for Windows spellchecker (policy languages not restricted
-        // to Hunspell).
-        TestCase({"ar-SA", "es-MX", "fi", "fr",
-                  "not-a-language"} /* blocked languages */,
-                 {"fi", "fr", "not-another-language"} /* forced languages */,
-                 {"ar", "es-MX"} /* expected blocked languages */,
-                 {"fi", "fr"} /* expected forced languages */,
-                 true /* spellcheck enabled */,
-                 true /* windows spellchecker enabled */),
-        TestCase({"ar-SA", "es-MX", "fi", "fr "} /* blocked languages */,
-                 {"fi", "fr"} /* forced languages */,
-                 {""} /* expected blocked languages */,
-                 {""} /* expected forced languages */,
-                 false /* spellcheck enabled */,
-                 true /* windows spellchecker enabled */),
-#endif  // BUILDFLAG(USE_WIN_HYBRID_SPELLCHECKER)
-        // Test cases for Hunspell only spellchecker. ar-SA and fi are
-        // non-Hunspell languages so are ignored for policy enforcement. If they
-        // ever obtain Hunspell support, the first test case below will fail.
-        TestCase({"ar-SA", "es-MX", "fi", "fr",
-                  "not-a-language"} /* blocked languages */,
-                 {"fi", "fr", "not-another-language"} /* forced languages */,
-                 {"es-MX"} /* expected blocked languages */,
-                 {"fr"} /* expected forced languages */,
-                 true /* spellcheck enabled */,
-                 false /* windows spellchecker enabled */),
-        TestCase({"ar-SA", "es-MX", "fi", "fr",
-                  "not-a-language"} /* blocked languages */,
-                 {"fi", "fr", "not-another-language"} /* forced languages */,
-                 {""} /* expected blocked languages */,
-                 {""} /* expected forced languages */,
-                 false /* spellcheck enabled */,
-                 false /* windows spellchecker enabled */)));
-
-}  // namespace policy
diff --git a/chrome/browser/spellchecker/spellcheck_service.cc b/chrome/browser/spellchecker/spellcheck_service.cc
index 4aea771d..7d3ddb7 100644
--- a/chrome/browser/spellchecker/spellcheck_service.cc
+++ b/chrome/browser/spellchecker/spellcheck_service.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/spellchecker/spellcheck_service.h"
 
 #include <algorithm>
-#include <iterator>
 #include <set>
 #include <utility>
 
@@ -39,7 +38,6 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
 #include "base/task/post_task.h"
@@ -202,84 +200,6 @@
   return true;
 }
 
-// static
-std::string SpellcheckService::GetSupportedAcceptLanguageCode(
-    const std::string& supported_language_full_tag) {
-  // Default to accept language in hardcoded list of Hunspell dictionaries
-  // (kSupportedSpellCheckerLanguages).
-  std::string supported_accept_language =
-      spellcheck::GetCorrespondingSpellCheckLanguage(
-          supported_language_full_tag);
-
-#if defined(OS_WIN)
-  if (!spellcheck::UseWinHybridSpellChecker())
-    return supported_accept_language;
-
-  // Collect the hardcoded list of accept-languages supported by the browser,
-  // that is, languages that can be added as preferred languages in the
-  // languages settings page.
-  std::vector<std::string> accept_languages;
-  l10n_util::GetAcceptLanguages(&accept_languages);
-
-  // First try exact match. Per BCP47, tags are in ASCII and should be treated
-  // as case-insensitive (although there are conventions for the capitalization
-  // of subtags).
-  auto iter =
-      std::find_if(accept_languages.begin(), accept_languages.end(),
-                   [supported_language_full_tag](const auto& accept_language) {
-                     return base::EqualsCaseInsensitiveASCII(
-                         supported_language_full_tag, accept_language);
-                   });
-  if (iter != accept_languages.end())
-    return *iter;
-
-  // Then try matching just the language and (optional) script subtags, but
-  // not the region subtag. For example, Edge supports sr-Cyrl-RS as an accept
-  // language, but not sr-Cyrl-CS. Matching language + script subtags assures
-  // we get the correct script for spellchecking, and not use sr-Latn-RS if
-  // language packs for both scripts are installed on the system.
-  if (!base::Contains(supported_language_full_tag, "-"))
-    return "";
-
-  iter =
-      std::find_if(accept_languages.begin(), accept_languages.end(),
-                   [supported_language_full_tag](const auto& accept_language) {
-                     return base::EqualsCaseInsensitiveASCII(
-                         SpellcheckService::GetLanguageAndScriptTag(
-                             supported_language_full_tag,
-                             /* include_script_tag */ true),
-                         SpellcheckService::GetLanguageAndScriptTag(
-                             accept_language,
-                             /* include_script_tag */ true));
-                   });
-
-  if (iter != accept_languages.end())
-    return *iter;
-
-  // Then try just matching the leading language subtag. E.g. Edge supports
-  // kok as an accept language, but if the Konkani language pack is
-  // installed the Windows spellcheck API reports kok-Deva-IN for the
-  // dictionary name.
-  iter =
-      std::find_if(accept_languages.begin(), accept_languages.end(),
-                   [supported_language_full_tag](const auto& accept_language) {
-                     return base::EqualsCaseInsensitiveASCII(
-                         SpellcheckService::GetLanguageAndScriptTag(
-                             supported_language_full_tag,
-                             /* include_script_tag */ false),
-                         SpellcheckService::GetLanguageAndScriptTag(
-                             accept_language,
-                             /* include_script_tag */ false));
-                   });
-
-  if (iter != accept_languages.end())
-    return *iter;
-
-#endif  // defined(OS_WIN)
-
-  return supported_accept_language;
-}
-
 void SpellcheckService::StartRecordingMetrics(bool spellcheck_enabled) {
   metrics_ = std::make_unique<SpellCheckHostMetrics>();
   metrics_->RecordEnabledStats(spellcheck_enabled);
@@ -441,33 +361,6 @@
 }
 
 // static
-std::string SpellcheckService::GetLanguageAndScriptTag(
-    const std::string& full_tag,
-    bool include_script_tag) {
-  std::string language_and_script_tag;
-
-  std::vector<std::string> subtags = base::SplitString(
-      full_tag, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  // Language subtag is required, all others optional.
-  DCHECK_GE(subtags.size(), 1ULL);
-  std::vector<std::string> subtag_tokens_to_pass;
-  subtag_tokens_to_pass.push_back(subtags.front());
-  subtags.erase(subtags.begin());
-
-  // The optional script subtag always follows the language subtag, and is 4
-  // characters in length.
-  if (include_script_tag) {
-    if (!subtags.empty() && subtags.front().length() == 4) {
-      subtag_tokens_to_pass.push_back(subtags.front());
-    }
-  }
-
-  language_and_script_tag = base::JoinString(subtag_tokens_to_pass, "-");
-
-  return language_and_script_tag;
-}
-
-// static
 void SpellcheckService::AttachStatusEvent(base::WaitableEvent* status_event) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
diff --git a/chrome/browser/spellchecker/spellcheck_service.h b/chrome/browser/spellchecker/spellcheck_service.h
index 97df1313..803c7da 100644
--- a/chrome/browser/spellchecker/spellcheck_service.h
+++ b/chrome/browser/spellchecker/spellcheck_service.h
@@ -94,13 +94,6 @@
   // when we do not set an event to |status_event_|.
   static bool SignalStatusEvent(EventType type);
 
-  // Get the best match of a supported accept language code for the provided
-  // language tag. Returns an empty string if no match is found. Method cannot
-  // be defined in spellcheck_common.h as it depends on l10n_util, and code
-  // under components cannot depend on ui/base.
-  static std::string GetSupportedAcceptLanguageCode(
-      const std::string& supported_language_full_tag);
-
   // Instantiates SpellCheckHostMetrics object and makes it ready for recording
   // metrics. This should be called only if the metrics recording is active.
   void StartRecordingMetrics(bool spellcheck_enabled);
@@ -168,11 +161,6 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(SpellcheckServiceBrowserTest, DeleteCorruptedBDICT);
 
-  // Parses a full BCP47 language tag to return just the language subtag,
-  // optionally with a hyphen and script subtag appended.
-  static std::string GetLanguageAndScriptTag(const std::string& full_tag,
-                                             bool include_script_tag);
-
   // Attaches an event so browser tests can listen the status events.
   static void AttachStatusEvent(base::WaitableEvent* status_event);
 
diff --git a/chrome/browser/thumbnail/generator/BUILD.gn b/chrome/browser/thumbnail/generator/BUILD.gn
index d49ac83..a4dd63a 100644
--- a/chrome/browser/thumbnail/generator/BUILD.gn
+++ b/chrome/browser/thumbnail/generator/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//media/media_options.gni")
+
 if (is_android) {
   import("//build/config/android/config.gni")
   import("//build/config/android/rules.gni")
@@ -42,6 +44,18 @@
       "android/thumbnail_media_parser.h",
     ]
 
+    if (media_use_ffmpeg) {
+      sources += [
+        "android/thumbnail_media_parser_impl.cc",
+        "android/thumbnail_media_parser_impl.h",
+      ]
+    } else {
+      sources += [
+        "android/noop_thumbnail_media_parser.cc",
+        "android/noop_thumbnail_media_parser.h",
+      ]
+    }
+
     deps += [
       ":jni_headers",
       "//third_party/android_opengl/etc1",
diff --git a/chrome/browser/thumbnail/generator/android/noop_thumbnail_media_parser.cc b/chrome/browser/thumbnail/generator/android/noop_thumbnail_media_parser.cc
new file mode 100644
index 0000000..81ad60a8
--- /dev/null
+++ b/chrome/browser/thumbnail/generator/android/noop_thumbnail_media_parser.cc
@@ -0,0 +1,13 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/thumbnail/generator/android/noop_thumbnail_media_parser.h"
+
+#include "third_party/skia/include/core/SkBitmap.h"
+
+void NoopThumbnailMediaParser::Start(ParseCompleteCB parse_complete_cb) {
+  DCHECK(parse_complete_cb);
+  std::move(parse_complete_cb)
+      .Run(false /*success*/, chrome::mojom::MediaMetadata::New(), SkBitmap());
+}
diff --git a/chrome/browser/thumbnail/generator/android/noop_thumbnail_media_parser.h b/chrome/browser/thumbnail/generator/android/noop_thumbnail_media_parser.h
new file mode 100644
index 0000000..69f291d
--- /dev/null
+++ b/chrome/browser/thumbnail/generator/android/noop_thumbnail_media_parser.h
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_NOOP_THUMBNAIL_MEDIA_PARSER_H_
+#define CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_NOOP_THUMBNAIL_MEDIA_PARSER_H_
+
+#include "chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h"
+
+// Empty implementation used when ENABLE_FFMPEG build flag is false.
+class NoopThumbnailMediaParser : public ThumbnailMediaParser {
+ public:
+  NoopThumbnailMediaParser() = default;
+  NoopThumbnailMediaParser(const NoopThumbnailMediaParser&) = delete;
+  NoopThumbnailMediaParser& operator=(const NoopThumbnailMediaParser&) = delete;
+  ~NoopThumbnailMediaParser() override = default;
+
+ private:
+  // ThumbnailMediaParser implementation.
+  void Start(ParseCompleteCB parse_complete_cb) override;
+};
+
+#endif  // CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_NOOP_THUMBNAIL_MEDIA_PARSER_H_
diff --git a/chrome/browser/thumbnail/generator/android/thumbnail_generator.cc b/chrome/browser/thumbnail/generator/android/thumbnail_generator.cc
index e9e9959..496b66c 100644
--- a/chrome/browser/thumbnail/generator/android/thumbnail_generator.cc
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_generator.cc
@@ -106,7 +106,7 @@
   // Retrieve video thumbnail.
   if (base::StartsWith(mime_type, "video/",
                        base::CompareCase::INSENSITIVE_ASCII)) {
-    auto parser = std::make_unique<ThumbnailMediaParser>(mime_type, file_path);
+    auto parser = ThumbnailMediaParser::Create(mime_type, file_path);
     parser->Start(base::BindOnce(&ThumbnailGenerator::OnVideoThumbnailRetrieved,
                                  weak_factory_.GetWeakPtr(),
                                  std::move(java_callback), icon_size,
diff --git a/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.cc b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.cc
index 4dec88f..1066924 100644
--- a/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.cc
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.cc
@@ -1,309 +1,23 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h"
 
-#include "base/bind.h"
-#include "base/files/file.h"
-#include "base/files/file_util.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/task/post_task.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
-#include "base/task_runner_util.h"
-#include "cc/paint/skia_paint_canvas.h"
-#include "chrome/browser/thumbnail/generator/android/local_media_data_source_factory.h"
-#include "content/public/browser/android/gpu_video_accelerator_factories_provider.h"
-#include "content/public/browser/media_service.h"
-#include "media/base/overlay_info.h"
-#include "media/base/video_thumbnail_decoder.h"
-#include "media/mojo/clients/mojo_video_decoder.h"
-#include "media/mojo/mojom/media_service.mojom.h"
-#include "media/mojo/services/media_interface_provider.h"
-#include "media/renderers/paint_canvas_video_renderer.h"
-#include "media/video/gpu_video_accelerator_factories.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
-#include "third_party/skia/include/core/SkBitmap.h"
+#include "media/media_buildflags.h"
 
-namespace {
+#if BUILDFLAG(ENABLE_FFMPEG)
+#include "chrome/browser/thumbnail/generator/android/thumbnail_media_parser_impl.h"
+#else
+#include "chrome/browser/thumbnail/generator/android/noop_thumbnail_media_parser.h"
+#endif
 
-// The maximum duration to parse media file.
-const base::TimeDelta kTimeOut = base::TimeDelta::FromSeconds(8);
-
-// Returns if the mime type is video or audio.
-bool IsSupportedMediaMimeType(const std::string& mime_type) {
-  return base::StartsWith(mime_type, "audio/",
-                          base::CompareCase::INSENSITIVE_ASCII) ||
-         base::StartsWith(mime_type, "video/",
-                          base::CompareCase::INSENSITIVE_ASCII);
-}
-
-void OnRequestOverlayInfo(bool decoder_requires_restart_for_overlay,
-                          media::ProvideOverlayInfoCB overlay_info_cb) {
-  // No android overlay associated with video thumbnail.
-  if (overlay_info_cb)
-    std::move(overlay_info_cb).Run(media::OverlayInfo());
-}
-
-int64_t GetFileSize(const base::FilePath& file_path) {
-  int64_t size = 0;
-  if (!base::GetFileSize(file_path, &size))
-    return -1;
-  return size;
-}
-
-}  // namespace
-
-ThumbnailMediaParser::ThumbnailMediaParser(const std::string& mime_type,
-                                           const base::FilePath& file_path)
-    : mime_type_(mime_type),
-      file_path_(file_path),
-      file_task_runner_(
-          base::ThreadPool::CreateSingleThreadTaskRunner({base::MayBlock()})),
-      decode_done_(false) {}
-
-ThumbnailMediaParser::~ThumbnailMediaParser() = default;
-
-void ThumbnailMediaParser::Start(ParseCompleteCB parse_complete_cb) {
-  RecordMediaParserEvent(MediaParserEvent::kInitialize);
-  parse_complete_cb_ = std::move(parse_complete_cb);
-  timer_.Start(
-      FROM_HERE, kTimeOut,
-      base::BindOnce(&ThumbnailMediaParser::OnError, weak_factory_.GetWeakPtr(),
-                     MediaParserEvent::kTimeout));
-
-  // Only process media mime types.
-  if (!IsSupportedMediaMimeType(mime_type_)) {
-    OnError(MediaParserEvent::kUnsupportedMimeType);
-    return;
-  }
-
-  // Get the size of the file if needed.
-  base::PostTaskAndReplyWithResult(
-      file_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&GetFileSize, file_path_),
-      base::BindOnce(&ThumbnailMediaParser::OnReadFileSize,
-                     weak_factory_.GetWeakPtr()));
-}
-
-void ThumbnailMediaParser::OnReadFileSize(int64_t file_size) {
-  if (file_size < 0) {
-    OnError(MediaParserEvent::kReadFileError);
-    return;
-  }
-
-  size_ = file_size;
-  RetrieveMediaParser();
-}
-
-void ThumbnailMediaParser::OnMediaParserCreated() {
-  auto media_source_factory = std::make_unique<LocalMediaDataSourceFactory>(
-      file_path_, file_task_runner_);
-  mojo::PendingRemote<chrome::mojom::MediaDataSource> source;
-  media_data_source_ = media_source_factory->CreateMediaDataSource(
-      source.InitWithNewPipeAndPassReceiver(),
-      base::BindRepeating(&ThumbnailMediaParser::OnMediaDataReady,
-                          weak_factory_.GetWeakPtr()));
-
-  RecordMediaMetadataEvent(MediaMetadataEvent::kMetadataStart);
-  media_parser()->ParseMediaMetadata(
-      mime_type_, size_, false /* get_attached_images */, std::move(source),
-      base::BindOnce(&ThumbnailMediaParser::OnMediaMetadataParsed,
-                     weak_factory_.GetWeakPtr()));
-}
-
-void ThumbnailMediaParser::OnConnectionError() {
-  OnError(MediaParserEvent::kUtilityConnectionError);
-}
-
-void ThumbnailMediaParser::OnMediaMetadataParsed(
-    bool parse_success,
-    chrome::mojom::MediaMetadataPtr metadata,
-    const std::vector<metadata::AttachedImage>& attached_images) {
-  if (!parse_success) {
-    RecordMediaMetadataEvent(MediaMetadataEvent::kMetadataFailed);
-    OnError(MediaParserEvent::kMetadataFailed);
-    return;
-  }
-  metadata_ = std::move(metadata);
-  DCHECK(metadata_);
-  RecordMediaMetadataEvent(MediaMetadataEvent::kMetadataComplete);
-
-  // For audio file, we only need metadata and poster.
-  if (base::StartsWith(mime_type_, "audio/",
-                       base::CompareCase::INSENSITIVE_ASCII)) {
-    NotifyComplete(SkBitmap());
-    return;
-  }
-
-  DCHECK(base::StartsWith(mime_type_, "video/",
-                          base::CompareCase::INSENSITIVE_ASCII));
-
-  // Start to retrieve video thumbnail.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ThumbnailMediaParser::RetrieveEncodedVideoFrame,
-                     weak_factory_.GetWeakPtr()));
-}
-
-void ThumbnailMediaParser::RetrieveEncodedVideoFrame() {
-  RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoThumbnailStart);
-  media_data_source_.reset();
-
-  auto media_source_factory = std::make_unique<LocalMediaDataSourceFactory>(
-      file_path_, file_task_runner_);
-  mojo::PendingRemote<chrome::mojom::MediaDataSource> source;
-  media_data_source_ = media_source_factory->CreateMediaDataSource(
-      source.InitWithNewPipeAndPassReceiver(),
-      base::BindRepeating(&ThumbnailMediaParser::OnMediaDataReady,
-                          weak_factory_.GetWeakPtr()));
-
-  media_parser()->ExtractVideoFrame(
-      mime_type_, base::saturated_cast<uint32_t>(size_), std::move(source),
-      base::BindOnce(&ThumbnailMediaParser::OnVideoFrameRetrieved,
-                     weak_factory_.GetWeakPtr()));
-}
-
-void ThumbnailMediaParser::OnVideoFrameRetrieved(
-    bool success,
-    chrome::mojom::VideoFrameDataPtr video_frame_data,
-    const base::Optional<media::VideoDecoderConfig>& config) {
-  if (!success) {
-    RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoFrameExtractionFailed);
-    OnError(MediaParserEvent::kVideoThumbnailFailed);
-    return;
-  }
-
-  video_frame_data_ = std::move(video_frame_data);
-  DCHECK(config.has_value());
-  config_ = config.value();
-
-  // For vp8, vp9 codec, we directly do software decoding in utility process.
-  // Render now.
-  if (video_frame_data_->which() ==
-      chrome::mojom::VideoFrameData::Tag::DECODED_FRAME) {
-    decode_done_ = true;
-    RenderVideoFrame(std::move(video_frame_data_->get_decoded_frame()));
-    return;
-  }
-
-  // For other codec, the encoded frame is retrieved in utility process, send
-  // the data to GPU process to do hardware decoding.
-  if (video_frame_data_->get_encoded_data().empty()) {
-    RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoFrameExtractionFailed);
-    OnError(MediaParserEvent::kVideoThumbnailFailed);
-    return;
-  }
-
-  // Starts to decode with MojoVideoDecoder.
-  content::CreateGpuVideoAcceleratorFactories(base::BindRepeating(
-      &ThumbnailMediaParser::OnGpuVideoAcceleratorFactoriesReady,
-      weak_factory_.GetWeakPtr()));
-}
-
-void ThumbnailMediaParser::OnGpuVideoAcceleratorFactoriesReady(
-    std::unique_ptr<media::GpuVideoAcceleratorFactories> factories) {
-  gpu_factories_ = std::move(factories);
-  DecodeVideoFrame();
-}
-
-void ThumbnailMediaParser::DecodeVideoFrame() {
-  mojo::PendingRemote<media::mojom::VideoDecoder> video_decoder_remote;
-  GetMediaInterfaceFactory()->CreateVideoDecoder(
-      video_decoder_remote.InitWithNewPipeAndPassReceiver());
-
-  // Build and config the decoder.
-  DCHECK(gpu_factories_);
-  auto mojo_decoder = std::make_unique<media::MojoVideoDecoder>(
-      base::ThreadTaskRunnerHandle::Get(), gpu_factories_.get(), this,
-      std::move(video_decoder_remote),
-      media::VideoDecoderImplementation::kDefault,
-      base::BindRepeating(&OnRequestOverlayInfo), gfx::ColorSpace());
-
-  decoder_ = std::make_unique<media::VideoThumbnailDecoder>(
-      std::move(mojo_decoder), config_,
-      std::move(video_frame_data_->get_encoded_data()));
-
-  decoder_->Start(base::BindOnce(&ThumbnailMediaParser::OnVideoFrameDecoded,
-                                 weak_factory_.GetWeakPtr()));
-  video_frame_data_.reset();
-}
-
-void ThumbnailMediaParser::OnVideoFrameDecoded(
-    scoped_refptr<media::VideoFrame> frame) {
-  if (!frame) {
-    RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoDecodeFailed);
-    OnError(MediaParserEvent::kVideoThumbnailFailed);
-    return;
-  }
-
-  DCHECK(frame->HasTextures());
-  decode_done_ = true;
-
-  RenderVideoFrame(std::move(frame));
-}
-
-void ThumbnailMediaParser::RenderVideoFrame(
-    scoped_refptr<media::VideoFrame> video_frame) {
-  auto* context_provider =
-      gpu_factories_ ? gpu_factories_->GetMediaContextProvider() : nullptr;
-
-  media::PaintCanvasVideoRenderer renderer;
-  SkBitmap bitmap;
-  bitmap.allocN32Pixels(video_frame->visible_rect().width(),
-                        video_frame->visible_rect().height());
-
-  // Draw the video frame to |bitmap|.
-  cc::SkiaPaintCanvas canvas(bitmap);
-  renderer.Copy(video_frame, &canvas, context_provider);
-
-  RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoThumbnailComplete);
-  NotifyComplete(std::move(bitmap));
-}
-
-media::mojom::InterfaceFactory*
-ThumbnailMediaParser::GetMediaInterfaceFactory() {
-  if (!media_interface_factory_) {
-    mojo::PendingRemote<service_manager::mojom::InterfaceProvider> interfaces;
-    media_interface_provider_ = std::make_unique<media::MediaInterfaceProvider>(
-        interfaces.InitWithNewPipeAndPassReceiver());
-    content::GetMediaService().CreateInterfaceFactory(
-        media_interface_factory_.BindNewPipeAndPassReceiver(),
-        std::move(interfaces));
-    media_interface_factory_.set_disconnect_handler(
-        base::BindOnce(&ThumbnailMediaParser::OnDecoderConnectionError,
-                       base::Unretained(this)));
-  }
-
-  return media_interface_factory_.get();
-}
-
-void ThumbnailMediaParser::OnDecoderConnectionError() {
-  OnError(MediaParserEvent::kGpuConnectionError);
-}
-
-void ThumbnailMediaParser::OnMediaDataReady(
-    chrome::mojom::MediaDataSource::ReadCallback callback,
-    std::unique_ptr<std::string> data) {
-  // TODO(xingliu): Change media_parser.mojom to move the data instead of copy.
-  if (media_parser())
-    std::move(callback).Run(std::vector<uint8_t>(data->begin(), data->end()));
-}
-
-void ThumbnailMediaParser::NotifyComplete(SkBitmap bitmap) {
-  DCHECK(metadata_);
-  DCHECK(parse_complete_cb_);
-  RecordMediaParserEvent(MediaParserEvent::kSuccess);
-  std::move(parse_complete_cb_)
-      .Run(true, std::move(metadata_), std::move(bitmap));
-}
-
-void ThumbnailMediaParser::OnError(MediaParserEvent event) {
-  DCHECK(parse_complete_cb_);
-  RecordMediaParserEvent(MediaParserEvent::kFailure);
-  RecordMediaParserEvent(event);
-  std::move(parse_complete_cb_)
-      .Run(false, chrome::mojom::MediaMetadata::New(), SkBitmap());
+std::unique_ptr<ThumbnailMediaParser> ThumbnailMediaParser::Create(
+    const std::string& mime_type,
+    const base::FilePath& file_path) {
+#if BUILDFLAG(ENABLE_FFMPEG)
+  return std::make_unique<ThumbnailMediaParserImpl>(mime_type, file_path);
+#else
+  return std::make_unique<NoopThumbnailMediaParser>();
+#endif
 }
diff --git a/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h
index 6d5a3283..655f5f66 100644
--- a/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,132 +7,39 @@
 
 #include <memory>
 #include <string>
-#include <vector>
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
-#include "base/sequenced_task_runner.h"
-#include "base/timer/timer.h"
-#include "chrome/browser/thumbnail/generator/android/stats.h"
-#include "chrome/common/media_galleries/metadata_types.h"
 #include "chrome/services/media_gallery_util/public/cpp/media_parser_provider.h"
 #include "chrome/services/media_gallery_util/public/mojom/media_parser.mojom-forward.h"
-#include "media/base/media_log.h"
-#include "media/mojo/mojom/interface_factory.mojom.h"
-#include "mojo/public/cpp/bindings/remote.h"
-
-namespace media {
-class GpuVideoAcceleratorFactories;
-class MediaInterfaceProvider;
-class MojoVideoDecoder;
-class VideoDecoderConfig;
-class VideoThumbnailDecoder;
-}  // namespace media
 
 class SkBitmap;
 
 // Parse local media files, including media metadata and thumbnails.
 // Metadata is always parsed in utility process for both audio and video files.
-//
-// For video file, the thumbnail will be the a video key frame. The frame
-// extraction always happens in utility process. The decoding may happen in
-// utility or GPU process based on video codec.
-class ThumbnailMediaParser : public MediaParserProvider,
-                             public media::MediaLog {
+class ThumbnailMediaParser {
  public:
   using ParseCompleteCB =
       base::OnceCallback<void(bool success,
                               chrome::mojom::MediaMetadataPtr media_metadata,
                               SkBitmap bitmap)>;
 
-  ThumbnailMediaParser(const std::string& mime_type,
-                       const base::FilePath& file_path);
-  ~ThumbnailMediaParser() override;
+  // Creates the parser, may return an empty implementation when ffmpeg is
+  // disabled.
+  static std::unique_ptr<ThumbnailMediaParser> Create(
+      const std::string& mime_type,
+      const base::FilePath& file_path);
+
+  ThumbnailMediaParser() = default;
+  ThumbnailMediaParser(const ThumbnailMediaParser&) = delete;
+  ThumbnailMediaParser& operator=(const ThumbnailMediaParser&) = delete;
+  virtual ~ThumbnailMediaParser() = default;
 
   // Parse media metadata and thumbnail in a local file. All file IO will run on
   // |file_task_runner|. The metadata is parsed in an utility process safely.
   // The thumbnail is retrieved from GPU process or utility process based on
   // different codec.
-  void Start(ParseCompleteCB parse_complete_cb);
-
- private:
-  void OnReadFileSize(int64_t file_size);
-
-  // MediaParserProvider implementation:
-  void OnMediaParserCreated() override;
-  void OnConnectionError() override;
-
-  // Called after media metadata are parsed.
-  void OnMediaMetadataParsed(
-      bool parse_success,
-      chrome::mojom::MediaMetadataPtr metadata,
-      const std::vector<metadata::AttachedImage>& attached_images);
-
-  // Retrieves an encoded video frame.
-  void RetrieveEncodedVideoFrame();
-  void OnVideoFrameRetrieved(
-      bool success,
-      chrome::mojom::VideoFrameDataPtr video_frame_data,
-      const base::Optional<media::VideoDecoderConfig>& config);
-
-  // Decodes the video frame.
-  void OnGpuVideoAcceleratorFactoriesReady(
-      std::unique_ptr<media::GpuVideoAcceleratorFactories>);
-  void DecodeVideoFrame();
-  void OnVideoFrameDecoded(scoped_refptr<media::VideoFrame> decoded_frame);
-
-  // Renders the video frame to bitmap.
-  void RenderVideoFrame(scoped_refptr<media::VideoFrame> video_frame);
-
-  media::mojom::InterfaceFactory* GetMediaInterfaceFactory();
-  void OnDecoderConnectionError();
-
-  // Overlays media data source read operation. Gradually read data from media
-  // file.
-  void OnMediaDataReady(chrome::mojom::MediaDataSource::ReadCallback callback,
-                        std::unique_ptr<std::string> data);
-
-  void NotifyComplete(SkBitmap bitmap);
-  void OnError(MediaParserEvent event);
-
-  int64_t size_;
-  std::string mime_type_;
-  base::FilePath file_path_;
-
-  ParseCompleteCB parse_complete_cb_;
-  chrome::mojom::MediaMetadataPtr metadata_;
-
-  // Used to read media files chunks to feed to IPC channel.
-  std::unique_ptr<chrome::mojom::MediaDataSource> media_data_source_;
-
-  // The task runner to do blocking disk IO.
-  scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
-
-  // A timer to prevent unresponsive Android decoder during video file parsing,
-  // and the parser will fail gracefully after timeout.
-  base::OneShotTimer timer_;
-
-  // Cached video frame data, which contains either encoded frame or decoded
-  // video frame. Encoded frame is extracted with ffmpeg, the data can be large
-  // for high resolution video.
-  chrome::mojom::VideoFrameDataPtr video_frame_data_;
-
-  // Objects used to decode the video into media::VideoFrame with
-  // MojoVideoDecoder.
-  media::VideoDecoderConfig config_;
-  std::unique_ptr<media::VideoThumbnailDecoder> decoder_;
-  mojo::Remote<media::mojom::InterfaceFactory> media_interface_factory_;
-  std::unique_ptr<media::MediaInterfaceProvider> media_interface_provider_;
-  std::unique_ptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
-  bool decode_done_;
-
-  base::WeakPtrFactory<ThumbnailMediaParser> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(ThumbnailMediaParser);
+  virtual void Start(ParseCompleteCB parse_complete_cb) = 0;
 };
 
 #endif  // CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_MEDIA_PARSER_H_
diff --git a/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.cc b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.cc
index f0176e6..40fca7b7 100644
--- a/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.cc
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.cc
@@ -64,7 +64,7 @@
     const std::string& mime_type,
     const base::FilePath& file_path,
     ThumbnailMediaParser::ParseCompleteCB parse_complete_cb)
-    : parser_(std::make_unique<ThumbnailMediaParser>(mime_type, file_path)),
+    : parser_(ThumbnailMediaParser::Create(mime_type, file_path)),
       parse_complete_cb_(std::move(parse_complete_cb)) {}
 
 ThumbnailMediaParserBridge::~ThumbnailMediaParserBridge() = default;
diff --git a/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_impl.cc b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_impl.cc
new file mode 100644
index 0000000..3c79ee2
--- /dev/null
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_impl.cc
@@ -0,0 +1,310 @@
+// 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/thumbnail/generator/android/thumbnail_media_parser_impl.h"
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/task_runner_util.h"
+#include "cc/paint/skia_paint_canvas.h"
+#include "chrome/browser/thumbnail/generator/android/local_media_data_source_factory.h"
+#include "content/public/browser/android/gpu_video_accelerator_factories_provider.h"
+#include "content/public/browser/media_service.h"
+#include "media/base/overlay_info.h"
+#include "media/base/video_thumbnail_decoder.h"
+#include "media/mojo/clients/mojo_video_decoder.h"
+#include "media/mojo/mojom/media_service.mojom.h"
+#include "media/mojo/services/media_interface_provider.h"
+#include "media/renderers/paint_canvas_video_renderer.h"
+#include "media/video/gpu_video_accelerator_factories.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace {
+
+// The maximum duration to parse media file.
+const base::TimeDelta kTimeOut = base::TimeDelta::FromSeconds(8);
+
+// Returns if the mime type is video or audio.
+bool IsSupportedMediaMimeType(const std::string& mime_type) {
+  return base::StartsWith(mime_type, "audio/",
+                          base::CompareCase::INSENSITIVE_ASCII) ||
+         base::StartsWith(mime_type, "video/",
+                          base::CompareCase::INSENSITIVE_ASCII);
+}
+
+void OnRequestOverlayInfo(bool decoder_requires_restart_for_overlay,
+                          media::ProvideOverlayInfoCB overlay_info_cb) {
+  // No android overlay associated with video thumbnail.
+  if (overlay_info_cb)
+    std::move(overlay_info_cb).Run(media::OverlayInfo());
+}
+
+int64_t GetFileSize(const base::FilePath& file_path) {
+  int64_t size = 0;
+  if (!base::GetFileSize(file_path, &size))
+    return -1;
+  return size;
+}
+
+}  // namespace
+
+ThumbnailMediaParserImpl::ThumbnailMediaParserImpl(
+    const std::string& mime_type,
+    const base::FilePath& file_path)
+    : mime_type_(mime_type),
+      file_path_(file_path),
+      file_task_runner_(
+          base::ThreadPool::CreateSingleThreadTaskRunner({base::MayBlock()})),
+      decode_done_(false) {}
+
+ThumbnailMediaParserImpl::~ThumbnailMediaParserImpl() = default;
+
+void ThumbnailMediaParserImpl::Start(ParseCompleteCB parse_complete_cb) {
+  RecordMediaParserEvent(MediaParserEvent::kInitialize);
+  parse_complete_cb_ = std::move(parse_complete_cb);
+  timer_.Start(
+      FROM_HERE, kTimeOut,
+      base::BindOnce(&ThumbnailMediaParserImpl::OnError,
+                     weak_factory_.GetWeakPtr(), MediaParserEvent::kTimeout));
+
+  // Only process media mime types.
+  if (!IsSupportedMediaMimeType(mime_type_)) {
+    OnError(MediaParserEvent::kUnsupportedMimeType);
+    return;
+  }
+
+  // Get the size of the file if needed.
+  base::PostTaskAndReplyWithResult(
+      file_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&GetFileSize, file_path_),
+      base::BindOnce(&ThumbnailMediaParserImpl::OnReadFileSize,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void ThumbnailMediaParserImpl::OnReadFileSize(int64_t file_size) {
+  if (file_size < 0) {
+    OnError(MediaParserEvent::kReadFileError);
+    return;
+  }
+
+  size_ = file_size;
+  RetrieveMediaParser();
+}
+
+void ThumbnailMediaParserImpl::OnMediaParserCreated() {
+  auto media_source_factory = std::make_unique<LocalMediaDataSourceFactory>(
+      file_path_, file_task_runner_);
+  mojo::PendingRemote<chrome::mojom::MediaDataSource> source;
+  media_data_source_ = media_source_factory->CreateMediaDataSource(
+      source.InitWithNewPipeAndPassReceiver(),
+      base::BindRepeating(&ThumbnailMediaParserImpl::OnMediaDataReady,
+                          weak_factory_.GetWeakPtr()));
+
+  RecordMediaMetadataEvent(MediaMetadataEvent::kMetadataStart);
+  media_parser()->ParseMediaMetadata(
+      mime_type_, size_, false /* get_attached_images */, std::move(source),
+      base::BindOnce(&ThumbnailMediaParserImpl::OnMediaMetadataParsed,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void ThumbnailMediaParserImpl::OnConnectionError() {
+  OnError(MediaParserEvent::kUtilityConnectionError);
+}
+
+void ThumbnailMediaParserImpl::OnMediaMetadataParsed(
+    bool parse_success,
+    chrome::mojom::MediaMetadataPtr metadata,
+    const std::vector<metadata::AttachedImage>& attached_images) {
+  if (!parse_success) {
+    RecordMediaMetadataEvent(MediaMetadataEvent::kMetadataFailed);
+    OnError(MediaParserEvent::kMetadataFailed);
+    return;
+  }
+  metadata_ = std::move(metadata);
+  DCHECK(metadata_);
+  RecordMediaMetadataEvent(MediaMetadataEvent::kMetadataComplete);
+
+  // For audio file, we only need metadata and poster.
+  if (base::StartsWith(mime_type_, "audio/",
+                       base::CompareCase::INSENSITIVE_ASCII)) {
+    NotifyComplete(SkBitmap());
+    return;
+  }
+
+  DCHECK(base::StartsWith(mime_type_, "video/",
+                          base::CompareCase::INSENSITIVE_ASCII));
+
+  // Start to retrieve video thumbnail.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ThumbnailMediaParserImpl::RetrieveEncodedVideoFrame,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void ThumbnailMediaParserImpl::RetrieveEncodedVideoFrame() {
+  RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoThumbnailStart);
+  media_data_source_.reset();
+
+  auto media_source_factory = std::make_unique<LocalMediaDataSourceFactory>(
+      file_path_, file_task_runner_);
+  mojo::PendingRemote<chrome::mojom::MediaDataSource> source;
+  media_data_source_ = media_source_factory->CreateMediaDataSource(
+      source.InitWithNewPipeAndPassReceiver(),
+      base::BindRepeating(&ThumbnailMediaParserImpl::OnMediaDataReady,
+                          weak_factory_.GetWeakPtr()));
+
+  media_parser()->ExtractVideoFrame(
+      mime_type_, base::saturated_cast<uint32_t>(size_), std::move(source),
+      base::BindOnce(&ThumbnailMediaParserImpl::OnVideoFrameRetrieved,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void ThumbnailMediaParserImpl::OnVideoFrameRetrieved(
+    bool success,
+    chrome::mojom::VideoFrameDataPtr video_frame_data,
+    const base::Optional<media::VideoDecoderConfig>& config) {
+  if (!success) {
+    RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoFrameExtractionFailed);
+    OnError(MediaParserEvent::kVideoThumbnailFailed);
+    return;
+  }
+
+  video_frame_data_ = std::move(video_frame_data);
+  DCHECK(config.has_value());
+  config_ = config.value();
+
+  // For vp8, vp9 codec, we directly do software decoding in utility process.
+  // Render now.
+  if (video_frame_data_->which() ==
+      chrome::mojom::VideoFrameData::Tag::DECODED_FRAME) {
+    decode_done_ = true;
+    RenderVideoFrame(std::move(video_frame_data_->get_decoded_frame()));
+    return;
+  }
+
+  // For other codec, the encoded frame is retrieved in utility process, send
+  // the data to GPU process to do hardware decoding.
+  if (video_frame_data_->get_encoded_data().empty()) {
+    RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoFrameExtractionFailed);
+    OnError(MediaParserEvent::kVideoThumbnailFailed);
+    return;
+  }
+
+  // Starts to decode with MojoVideoDecoder.
+  content::CreateGpuVideoAcceleratorFactories(base::BindRepeating(
+      &ThumbnailMediaParserImpl::OnGpuVideoAcceleratorFactoriesReady,
+      weak_factory_.GetWeakPtr()));
+}
+
+void ThumbnailMediaParserImpl::OnGpuVideoAcceleratorFactoriesReady(
+    std::unique_ptr<media::GpuVideoAcceleratorFactories> factories) {
+  gpu_factories_ = std::move(factories);
+  DecodeVideoFrame();
+}
+
+void ThumbnailMediaParserImpl::DecodeVideoFrame() {
+  mojo::PendingRemote<media::mojom::VideoDecoder> video_decoder_remote;
+  GetMediaInterfaceFactory()->CreateVideoDecoder(
+      video_decoder_remote.InitWithNewPipeAndPassReceiver());
+
+  // Build and config the decoder.
+  DCHECK(gpu_factories_);
+  auto mojo_decoder = std::make_unique<media::MojoVideoDecoder>(
+      base::ThreadTaskRunnerHandle::Get(), gpu_factories_.get(), this,
+      std::move(video_decoder_remote),
+      media::VideoDecoderImplementation::kDefault,
+      base::BindRepeating(&OnRequestOverlayInfo), gfx::ColorSpace());
+
+  decoder_ = std::make_unique<media::VideoThumbnailDecoder>(
+      std::move(mojo_decoder), config_,
+      std::move(video_frame_data_->get_encoded_data()));
+
+  decoder_->Start(base::BindOnce(&ThumbnailMediaParserImpl::OnVideoFrameDecoded,
+                                 weak_factory_.GetWeakPtr()));
+  video_frame_data_.reset();
+}
+
+void ThumbnailMediaParserImpl::OnVideoFrameDecoded(
+    scoped_refptr<media::VideoFrame> frame) {
+  if (!frame) {
+    RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoDecodeFailed);
+    OnError(MediaParserEvent::kVideoThumbnailFailed);
+    return;
+  }
+
+  DCHECK(frame->HasTextures());
+  decode_done_ = true;
+
+  RenderVideoFrame(std::move(frame));
+}
+
+void ThumbnailMediaParserImpl::RenderVideoFrame(
+    scoped_refptr<media::VideoFrame> video_frame) {
+  auto* context_provider =
+      gpu_factories_ ? gpu_factories_->GetMediaContextProvider() : nullptr;
+
+  media::PaintCanvasVideoRenderer renderer;
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(video_frame->visible_rect().width(),
+                        video_frame->visible_rect().height());
+
+  // Draw the video frame to |bitmap|.
+  cc::SkiaPaintCanvas canvas(bitmap);
+  renderer.Copy(video_frame, &canvas, context_provider);
+
+  RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoThumbnailComplete);
+  NotifyComplete(std::move(bitmap));
+}
+
+media::mojom::InterfaceFactory*
+ThumbnailMediaParserImpl::GetMediaInterfaceFactory() {
+  if (!media_interface_factory_) {
+    mojo::PendingRemote<service_manager::mojom::InterfaceProvider> interfaces;
+    media_interface_provider_ = std::make_unique<media::MediaInterfaceProvider>(
+        interfaces.InitWithNewPipeAndPassReceiver());
+    content::GetMediaService().CreateInterfaceFactory(
+        media_interface_factory_.BindNewPipeAndPassReceiver(),
+        std::move(interfaces));
+    media_interface_factory_.set_disconnect_handler(
+        base::BindOnce(&ThumbnailMediaParserImpl::OnDecoderConnectionError,
+                       base::Unretained(this)));
+  }
+
+  return media_interface_factory_.get();
+}
+
+void ThumbnailMediaParserImpl::OnDecoderConnectionError() {
+  OnError(MediaParserEvent::kGpuConnectionError);
+}
+
+void ThumbnailMediaParserImpl::OnMediaDataReady(
+    chrome::mojom::MediaDataSource::ReadCallback callback,
+    std::unique_ptr<std::string> data) {
+  // TODO(xingliu): Change media_parser.mojom to move the data instead of copy.
+  if (media_parser())
+    std::move(callback).Run(std::vector<uint8_t>(data->begin(), data->end()));
+}
+
+void ThumbnailMediaParserImpl::NotifyComplete(SkBitmap bitmap) {
+  DCHECK(metadata_);
+  DCHECK(parse_complete_cb_);
+  RecordMediaParserEvent(MediaParserEvent::kSuccess);
+  std::move(parse_complete_cb_)
+      .Run(true, std::move(metadata_), std::move(bitmap));
+}
+
+void ThumbnailMediaParserImpl::OnError(MediaParserEvent event) {
+  DCHECK(parse_complete_cb_);
+  RecordMediaParserEvent(MediaParserEvent::kFailure);
+  RecordMediaParserEvent(event);
+  std::move(parse_complete_cb_)
+      .Run(false, chrome::mojom::MediaMetadata::New(), SkBitmap());
+}
diff --git a/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_impl.h b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_impl.h
new file mode 100644
index 0000000..1278081
--- /dev/null
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_impl.h
@@ -0,0 +1,127 @@
+// 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_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_MEDIA_PARSER_IMPL_H_
+#define CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_MEDIA_PARSER_IMPL_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/sequenced_task_runner.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/thumbnail/generator/android/stats.h"
+#include "chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h"
+#include "chrome/common/media_galleries/metadata_types.h"
+#include "media/base/media_log.h"
+#include "media/mojo/mojom/interface_factory.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace media {
+class GpuVideoAcceleratorFactories;
+class MediaInterfaceProvider;
+class MojoVideoDecoder;
+class VideoDecoderConfig;
+class VideoThumbnailDecoder;
+}  // namespace media
+
+class SkBitmap;
+
+// Parse media file in remote process using ffmpeg to extract video frame.
+// The decoding may happen in utility or GPU process based on video codec.
+// For video file, the thumbnail will be the a video key frame.
+class ThumbnailMediaParserImpl : public ThumbnailMediaParser,
+                                 public MediaParserProvider,
+                                 public media::MediaLog {
+ public:
+  ThumbnailMediaParserImpl(const std::string& mime_type,
+                           const base::FilePath& file_path);
+  ~ThumbnailMediaParserImpl() override;
+
+  // ThumbnailMediaParser implementation.
+  void Start(ParseCompleteCB parse_complete_cb) override;
+
+ private:
+  void OnReadFileSize(int64_t file_size);
+
+  // MediaParserProvider implementation:
+  void OnMediaParserCreated() override;
+  void OnConnectionError() override;
+
+  // Called after media metadata are parsed.
+  void OnMediaMetadataParsed(
+      bool parse_success,
+      chrome::mojom::MediaMetadataPtr metadata,
+      const std::vector<metadata::AttachedImage>& attached_images);
+
+  // Retrieves an encoded video frame.
+  void RetrieveEncodedVideoFrame();
+  void OnVideoFrameRetrieved(
+      bool success,
+      chrome::mojom::VideoFrameDataPtr video_frame_data,
+      const base::Optional<media::VideoDecoderConfig>& config);
+
+  // Decodes the video frame.
+  void OnGpuVideoAcceleratorFactoriesReady(
+      std::unique_ptr<media::GpuVideoAcceleratorFactories>);
+  void DecodeVideoFrame();
+  void OnVideoFrameDecoded(scoped_refptr<media::VideoFrame> decoded_frame);
+
+  // Renders the video frame to bitmap.
+  void RenderVideoFrame(scoped_refptr<media::VideoFrame> video_frame);
+
+  media::mojom::InterfaceFactory* GetMediaInterfaceFactory();
+  void OnDecoderConnectionError();
+
+  // Overlays media data source read operation. Gradually read data from media
+  // file.
+  void OnMediaDataReady(chrome::mojom::MediaDataSource::ReadCallback callback,
+                        std::unique_ptr<std::string> data);
+
+  void NotifyComplete(SkBitmap bitmap);
+  void OnError(MediaParserEvent event);
+
+  int64_t size_;
+  std::string mime_type_;
+  base::FilePath file_path_;
+
+  ParseCompleteCB parse_complete_cb_;
+  chrome::mojom::MediaMetadataPtr metadata_;
+
+  // Used to read media files chunks to feed to IPC channel.
+  std::unique_ptr<chrome::mojom::MediaDataSource> media_data_source_;
+
+  // The task runner to do blocking disk IO.
+  scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
+
+  // A timer to prevent unresponsive Android decoder during video file parsing,
+  // and the parser will fail gracefully after timeout.
+  base::OneShotTimer timer_;
+
+  // Cached video frame data, which contains either encoded frame or decoded
+  // video frame. Encoded frame is extracted with ffmpeg, the data can be large
+  // for high resolution video.
+  chrome::mojom::VideoFrameDataPtr video_frame_data_;
+
+  // Objects used to decode the video into media::VideoFrame with
+  // MojoVideoDecoder.
+  media::VideoDecoderConfig config_;
+  std::unique_ptr<media::VideoThumbnailDecoder> decoder_;
+  mojo::Remote<media::mojom::InterfaceFactory> media_interface_factory_;
+  std::unique_ptr<media::MediaInterfaceProvider> media_interface_provider_;
+  std::unique_ptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
+  bool decode_done_;
+
+  base::WeakPtrFactory<ThumbnailMediaParserImpl> weak_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(ThumbnailMediaParserImpl);
+};
+
+#endif  // CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_MEDIA_PARSER_IMPL_H_
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 29d4bca..0c9ca74 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -423,6 +423,7 @@
     "//chrome/services/qrcode_generator/public/cpp",
     "//chrome/services/qrcode_generator/public/mojom",
     "//components/about_ui",
+    "//components/client_hints/browser",
     "//components/account_id",
     "//components/autofill/content/browser:risk_proto",
     "//components/autofill/core/browser",
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 0d934715..387cab8 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
@@ -310,6 +310,10 @@
         result.score = search_ranker_score_map[result.result->id()];
       }
     } else if (model == Model::APPS) {
+      // Do not rerank apps for a query-based search.
+      if (!last_query_.empty())
+        continue;
+
       if (using_aggregated_app_inference_) {
         const std::string id = NormalizeAppId(result.result->id());
 
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc
index 848e0a69..8e0af58 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -110,6 +110,8 @@
      {ChromePage::OSLANGUAGESDETAILS, chrome::kOsLanguagesDetailsSubPage},
      {ChromePage::OSLANGUAGESINPUTMETHODS,
       chrome::kOsLanguagesInputMethodsSubPage},
+     {ChromePage::OSLANGUAGESSMARTINPUTS,
+      chrome::kOsLanguagesSmartInputsSubPage},
      {ChromePage::LOCKSCREEN, chrome::kLockScreenSubPage},
      {ChromePage::MAIN, ""},
      {ChromePage::MANAGEACCESSIBILITY, chrome::kManageAccessibilitySubPage},
diff --git a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
index a25289c..d61763ee 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
@@ -274,6 +274,8 @@
                      base_url.Resolve(chrome::kOsLanguagesDetailsSubPage));
   TestOpenChromePage(ChromePage::OSLANGUAGESINPUTMETHODS,
                      base_url.Resolve(chrome::kOsLanguagesInputMethodsSubPage));
+  TestOpenChromePage(ChromePage::OSLANGUAGESSMARTINPUTS,
+                     base_url.Resolve(chrome::kOsLanguagesSmartInputsSubPage));
   TestOpenChromePage(ChromePage::LOCKSCREEN,
                      base_url.Resolve(chrome::kLockScreenSubPage));
   TestOpenChromePage(ChromePage::MANAGEACCESSIBILITY,
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc
index a71c8e9..90b2ba9 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_app_window_browsertest.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/web_applications/test/web_app_test.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/common/web_application_info.h"
 #include "chrome/services/app_service/public/cpp/instance.h"
 #include "chrome/services/app_service/public/cpp/instance_registry.h"
 #include "components/arc/arc_service_manager.h"
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
index 17b11ab1f..62e1535 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
@@ -36,6 +36,7 @@
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/views/crostini/crostini_app_restart_view.h"
 #include "chrome/browser/ui/webui/settings/chromeos/app_management/app_management_uma.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/app_registry_controller.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/chrome_features.h"
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc
index 20506d3..2a23a770 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc
@@ -21,6 +21,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/vector2d.h"
 
@@ -45,6 +46,9 @@
         std::make_unique<TestAutofillExternalDelegate>(
             driver->autofill_manager(), driver,
             /*call_parent_methods=*/true);
+
+    disable_animation_ = std::make_unique<ui::ScopedAnimationDurationScaleMode>(
+        ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
   }
 
   // Normally the WebContents will automatically delete the delegate, but here
@@ -56,6 +60,7 @@
 
  protected:
   std::unique_ptr<TestAutofillExternalDelegate> autofill_external_delegate_;
+  std::unique_ptr<ui::ScopedAnimationDurationScaleMode> disable_animation_;
 };
 
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 68ff8a30..cc8ffd09 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -16,8 +16,9 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/buildflags.h"
 #include "chrome/browser/captive_portal/captive_portal_service_factory.h"
-#include "chrome/browser/client_hints/client_hints.h"
+#include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/complex_tasks/task_tab_helper.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/content_settings/mixed_content_settings_tab_helper.h"
 #include "chrome/browser/content_settings/sound_content_setting_observer.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
@@ -94,6 +95,7 @@
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/captive_portal/core/buildflags.h"
+#include "components/client_hints/browser/client_hints.h"
 #include "components/dom_distiller/core/dom_distiller_features.h"
 #include "components/download/content/factory/navigation_monitor_factory.h"
 #include "components/download/content/public/download_navigation_observer.h"
@@ -238,7 +240,10 @@
     ChromeSubresourceFilterClient::CreateForWebContents(web_contents);
   }
   ChromeTranslateClient::CreateForWebContents(web_contents);
-  client_hints::ClientHints::CreateForWebContents(web_contents);
+  client_hints::ClientHints::CreateForWebContents(
+      web_contents, g_browser_process->network_quality_tracker(),
+      HostContentSettingsMapFactory::GetForProfile(profile),
+      GetUserAgentMetadata());
   ConnectionHelpTabHelper::CreateForWebContents(web_contents);
   CoreTabHelper::CreateForWebContents(web_contents);
   DataReductionProxyTabHelper::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 06d8bd8d..98c9887 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -93,7 +93,7 @@
 // Makes chrome://settings serve the Polymer 3 version of that page.
 // https://crbug.com/1026426.
 const base::Feature kSettingsPolymer3{"SettingsPolymer3",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
+                                      base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables friendly settings for the |chrome://settings/syncSetup| page.
 // https://crbug.com/1035421.
diff --git a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc
index 2f510de..7eadb00 100644
--- a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view_browsertest.cc
@@ -19,8 +19,10 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/common/web_application_info.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/arc/arc_util.h"
diff --git a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
index d7b37f2..a2563805 100644
--- a/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/card_unmask_prompt_views.cc
@@ -215,7 +215,6 @@
 
   auto new_card_link = std::make_unique<views::Link>(
       l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_UNMASK_NEW_CARD_LINK));
-  new_card_link->SetUnderline(false);
   new_card_link->set_callback(base::BindRepeating(
       &CardUnmaskPromptViews::LinkClicked, base::Unretained(this)));
   new_card_link_ = input_row_->AddChildView(std::move(new_card_link));
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
index 15308db..fec6f51f 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
@@ -265,7 +265,6 @@
         l10n_util::GetStringUTF16(IDS_EXTENSION_INSTALLED_MANAGE_SHORTCUTS)));
     manage_shortcut->set_callback(base::BindRepeating(
         &ExtensionInstalledBubbleView::LinkClicked, base::Unretained(this)));
-    manage_shortcut->SetUnderline(false);
   }
 
   if (model_->show_how_to_manage()) {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 2c36ef0..862cef5 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -118,6 +118,24 @@
     // TODO(orinj): Use the real translated string table values here instead.
     tab_switch_button_ =
         CreatePillButton(button_row_, this, "Switch to this tab");
+
+    const auto make_predicate = [=](auto state) {
+      return [=](View* view) {
+        return view->GetVisible() &&
+               popup_contents_view_->model()->selection() ==
+                   OmniboxPopupModel::Selection(model_index_, state);
+      };
+    };
+    keyword_button_focus_ring_ = views::FocusRing::Install(keyword_button_);
+    keyword_button_focus_ring_->SetHasFocusPredicate(
+        make_predicate(OmniboxPopupModel::FOCUSED_BUTTON_KEYWORD));
+    pedal_button_focus_ring_ = views::FocusRing::Install(pedal_button_);
+    pedal_button_focus_ring_->SetHasFocusPredicate(
+        make_predicate(OmniboxPopupModel::FOCUSED_BUTTON_PEDAL));
+    tab_switch_button_focus_ring_ =
+        views::FocusRing::Install(tab_switch_button_);
+    tab_switch_button_focus_ring_->SetHasFocusPredicate(
+        make_predicate(OmniboxPopupModel::FOCUSED_BUTTON_TAB_SWITCH));
   }
 
   keyword_view_ = AddChildView(std::make_unique<OmniboxMatchCellView>(this));
@@ -232,6 +250,12 @@
     keyword_view_->description()->ApplyTextColor(
         OmniboxPart::RESULTS_TEXT_DIMMED);
   }
+
+  if (OmniboxFieldTrial::IsSuggestionButtonRowEnabled()) {
+    keyword_button_focus_ring_->SchedulePaint();
+    pedal_button_focus_ring_->SchedulePaint();
+    tab_switch_button_focus_ring_->SchedulePaint();
+  }
 }
 
 void OmniboxResultView::OnSelectionStateChanged() {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.h b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
index 6e174fd4..eea4b35 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
@@ -169,6 +169,9 @@
   views::MdTextButton* keyword_button_ = nullptr;
   views::MdTextButton* pedal_button_ = nullptr;
   views::MdTextButton* tab_switch_button_ = nullptr;
+  std::unique_ptr<views::FocusRing> keyword_button_focus_ring_;
+  std::unique_ptr<views::FocusRing> pedal_button_focus_ring_;
+  std::unique_ptr<views::FocusRing> tab_switch_button_focus_ring_;
 
   // The "X" button at the end of the match cell, used to remove suggestions.
   views::ImageButton* remove_suggestion_button_;
diff --git a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
index f4d68ce3..7357fb1 100644
--- a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
+++ b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
@@ -153,7 +153,6 @@
         view->GetWidget()->Minimize();
       },
       base::Unretained(this)));
-  hide_link->SetUnderline(false);
   hide_link_ = AddChildView(std::move(hide_link));
 
   // The client rect for NotificationBarClientView uses the bounds for the
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
index c075fc24..b51890ed 100644
--- a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
+++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/web_app_launch_manager.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/file_handler_manager.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
diff --git a/chrome/browser/ui/web_applications/web_app_badging_browsertest.cc b/chrome/browser/ui/web_applications/web_app_badging_browsertest.cc
index c82b1dec..9027b8cb 100644
--- a/chrome/browser/ui/web_applications/web_app_badging_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_badging_browsertest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
+#include "chrome/common/web_application_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 
diff --git a/chrome/browser/ui/web_applications/web_app_browsertest.cc b/chrome/browser/ui/web_applications/web_app_browsertest.cc
index 910491c..b171334 100644
--- a/chrome/browser/ui/web_applications/web_app_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_browsertest.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h"
 #include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/ui/web_applications/web_app_menu_model.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/app_registry_controller.h"
 #include "chrome/browser/web_applications/components/external_install_options.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
diff --git a/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc b/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc
index 24d01c0..4ea8a6ba 100644
--- a/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_controller_browsertest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/extensions/browsertest_util.h"
 #include "chrome/browser/predictors/loading_predictor_config.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/app_shortcut_manager.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
diff --git a/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc b/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc
index 9a701954..282eb43 100644
--- a/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/app_service/browser_app_launcher.h"
 #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/file_handler_manager.h"
 #include "chrome/browser/web_applications/components/web_app_prefs_utils.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 69ee8265..68f1887a 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/login_screen.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -1388,20 +1387,6 @@
     gaia_silent_load_ = false;
   }
 
-  // Views-based login may reach here while pre-loading the Gaia screen, so
-  // update the wallpaper in |LoginDisplayHostMojo::UpdateGaiaDialogVisibility|
-  // instead, which controls the actual visibility of the Gaia screen.
-  if (!ash::features::IsViewsLoginEnabled()) {
-    // Note that LoadAuthExtension clears |populated_email_|.
-    if (populated_email_.empty()) {
-      LoginDisplayHost::default_host()->LoadSigninWallpaper();
-    } else {
-      LoginDisplayHost::default_host()->LoadWallpaper(
-          user_manager::known_user::GetAccountId(
-              populated_email_, std::string() /* id */, AccountType::UNKNOWN));
-    }
-  }
-
   input_method::InputMethodManager* imm =
       input_method::InputMethodManager::Get();
 
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 7ccd1bb5..e324f5f 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -10,8 +10,6 @@
 #include <string>
 #include <utility>
 
-#include "ash/public/cpp/ash_features.h"
-#include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/network_config_service.h"
 #include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
 #include "base/bind.h"
@@ -601,10 +599,6 @@
   localized_strings->SetString("highlightStrength",
                                keyboard_driven_oobe ? "strong" : "normal");
 
-  localized_strings->SetString(
-      "showViewsLock", ash::switches::IsUsingViewsLock() ? "on" : "off");
-  localized_strings->SetString(
-      "showViewsLogin", ash::features::IsViewsLoginEnabled() ? "on" : "off");
   localized_strings->SetBoolean(
       "changePictureVideoModeEnabled",
       base::FeatureList::IsEnabled(features::kChangePictureVideoMode));
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc
index edaf7b31..91ec1d9 100644
--- a/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_localized_strings_provider.cc
@@ -384,6 +384,28 @@
   ::settings::AddCaptionSubpageStrings(html_source);
 }
 
+void AddSmartInputsStrings(content::WebUIDataSource* html_source) {
+  static constexpr webui::LocalizedString kLocalizedStrings[] = {
+      {"smartInputsTitle", IDS_SETTINGS_SMART_INPUTS_TITLE},
+      {"personalInfoSuggestionTitle",
+       IDS_SETTINGS_SMART_INPUTS_PERSONAL_INFO_TITLE},
+      {"personalInfoSuggestionDescription",
+       IDS_SETTINGS_SMART_INPUTS_PERSONAL_INFO_DESCRIPTION},
+      {"showPersonalInfoSuggestion",
+       IDS_SETTINGS_SMART_INPUTS_SHOW_PERSONAL_INFO},
+      {"managePersonalInfo", IDS_SETTINGS_SMART_INPUTS_MANAGE_PERSONAL_INFO},
+  };
+  AddLocalizedStringsBulk(html_source, kLocalizedStrings);
+
+  // Assistive personal info is allowed when the feature flag is enabled and the
+  // user is not in guest mode.
+  html_source->AddBoolean(
+      "allowAssistivePersonalInfo",
+      base::FeatureList::IsEnabled(features::kAssistPersonalInfo) &&
+          !(user_manager::UserManager::Get()->IsLoggedInAsGuest() ||
+            user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()));
+}
+
 void AddLanguagesStrings(content::WebUIDataSource* html_source) {
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
       {"orderLanguagesInstructions",
@@ -417,6 +439,7 @@
       {"moveUp", IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_MOVE_UP},
   };
   AddLocalizedStringsBulk(html_source, kLocalizedStrings);
+  AddSmartInputsStrings(html_source);
 
   html_source->AddString(
       "languagesLearnMoreURL",
diff --git a/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc b/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
index 2261c0cd..c3337bd 100644
--- a/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
+++ b/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/installable/installable_manager.h"
 #include "chrome/browser/installable/installable_metrics.h"
 #include "chrome/common/chrome_render_frame.mojom-test-utils.h"
+#include "chrome/common/web_application_info.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/navigation_entry.h"
diff --git a/chrome/browser/web_applications/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/system_web_app_manager_browsertest.cc
index 6ff16f0..4afa69c3b 100644
--- a/chrome/browser/web_applications/system_web_app_manager_browsertest.cc
+++ b/chrome/browser/web_applications/system_web_app_manager_browsertest.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/native_file_system/native_file_system_permission_request_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/test/test_system_web_app_installation.h"
diff --git a/chrome/browser/web_applications/test/test_system_web_app_installation.cc b/chrome/browser/web_applications/test/test_system_web_app_installation.cc
index c528176..7be3310 100644
--- a/chrome/browser/web_applications/test/test_system_web_app_installation.cc
+++ b/chrome/browser/web_applications/test/test_system_web_app_installation.cc
@@ -9,6 +9,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/test/test_system_web_app_installation.h"
 #include "chrome/browser/web_applications/test/test_system_web_app_url_data_source.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc
index 55404515..44beb947 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -15,6 +15,7 @@
 #include "base/values.h"
 #include "chrome/browser/installable/installable_metrics.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_icon_generator.h"
 #include "chrome/browser/web_applications/components/web_app_prefs_utils.h"
diff --git a/chrome/browser/web_applications/web_app_install_manager_unittest.cc b/chrome/browser/web_applications/web_app_install_manager_unittest.cc
index 9052eb7..5b77f60 100644
--- a/chrome/browser/web_applications/web_app_install_manager_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_manager_unittest.cc
@@ -34,6 +34,7 @@
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_icon_manager.h"
 #include "chrome/browser/web_applications/web_app_install_finalizer.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/test/base/testing_profile.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom-shared.h"
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc
index 0cb08280..006fb22 100644
--- a/chrome/browser/web_applications/web_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -42,6 +42,7 @@
 #include "chrome/browser/web_applications/web_app_install_manager.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
+#include "chrome/common/web_application_info.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index f07964e9..8fb01356 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -109,8 +109,6 @@
     "chrome_result_codes.h",
     "chrome_ui_features_prefs.cc",
     "chrome_ui_features_prefs.h",
-    "client_hints/client_hints.cc",
-    "client_hints/client_hints.h",
     "common_message_generator.cc",
     "common_message_generator.h",
     "component_flash_hint_file_linux.cc",
@@ -199,6 +197,7 @@
     "//chrome/installer/util:with_no_strings",
     "//components/cast_certificate",
     "//components/cdm/common",
+    "//components/client_hints/common",
     "//components/cloud_devices/common",
     "//components/component_updater",
     "//components/content_settings/core/common",
diff --git a/chrome/common/client_hints/OWNERS b/chrome/common/client_hints/OWNERS
deleted file mode 100644
index 22542699..0000000
--- a/chrome/common/client_hints/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-yoavweiss@chromium.org
-tbansal@chromium.org
-ryansturm@chromium.org
-
-# For IPC security review
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-# COMPONENT: Blink>Loader
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 38047d2..d49b3f8 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -421,6 +421,7 @@
 const char kOsLanguagesSubPage[] = "osLanguages";
 const char kOsLanguagesDetailsSubPage[] = "osLanguages/details";
 const char kOsLanguagesInputMethodsSubPage[] = "osLanguages/inputMethods";
+const char kOsLanguagesSmartInputsSubPage[] = "osLanguages/smartInputs";
 const char kLockScreenSubPage[] = "lockScreen";
 const char kManageAccessibilitySubPage[] = "manageAccessibility";
 const char kManageAccessibilityTtsSubPage[] = "manageAccessibility/tts";
@@ -492,6 +493,7 @@
       kOsLanguagesSubPage,
       kOsLanguagesDetailsSubPage,
       kOsLanguagesInputMethodsSubPage,
+      kOsLanguagesSmartInputsSubPage,
       kOsPeopleSubPage,
       kOsPrintingSubPage,
       kOsPrivacySubPage,
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index ee510e7..ac0cff8 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -389,6 +389,7 @@
 extern const char kOsLanguagesSubPage[];
 extern const char kOsLanguagesDetailsSubPage[];
 extern const char kOsLanguagesInputMethodsSubPage[];
+extern const char kOsLanguagesSmartInputsSubPage[];
 extern const char kOsPeopleSubPage[];
 extern const char kOsPrintingSubPage[];
 extern const char kOsPrivacySubPage[];
diff --git a/chrome/credential_provider/gaiacp/associated_user_validator.h b/chrome/credential_provider/gaiacp/associated_user_validator.h
index a75c746..d289e14 100644
--- a/chrome/credential_provider/gaiacp/associated_user_validator.h
+++ b/chrome/credential_provider/gaiacp/associated_user_validator.h
@@ -124,9 +124,6 @@
       CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,
       const std::vector<base::string16>& reauth_sids);
 
-  // Returns true if any associated user is enforced to reauth via google.
-  bool IsAuthEnforcedOnAssociatedUsers();
-
   // Restores the access for a user that was denied access (if applicable).
   // Returns S_OK on success, failure otherwise.
   HRESULT RestoreUserAccess(const base::string16& sid);
diff --git a/chrome/credential_provider/gaiacp/gaia_resources.grd b/chrome/credential_provider/gaiacp/gaia_resources.grd
index e9efdb08..19d0c1ca 100644
--- a/chrome/credential_provider/gaiacp/gaia_resources.grd
+++ b/chrome/credential_provider/gaiacp/gaia_resources.grd
@@ -180,7 +180,7 @@
         Only the user who locked this device can sign in
       </message>
       <message name="IDS_ADD_USER_DISALLOWED" desc="">
-        Failed to add a new user. This computer only allows one user to be created using a work account.
+        Another work account is already associated with this device. Sign in with your Windows account.
       </message>
       <message name="IDS_FORGOT_PASSWORD_LINK" desc="">
         Forgot Windows Password
diff --git a/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_ADD_USER_DISALLOWED.png.sha1 b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_ADD_USER_DISALLOWED.png.sha1
index 9c6eefde..16f93b9 100644
--- a/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_ADD_USER_DISALLOWED.png.sha1
+++ b/chrome/credential_provider/gaiacp/gaia_resources_grd/IDS_ADD_USER_DISALLOWED.png.sha1
@@ -1 +1 @@
-c7251ee2efad628f4dd7bd2d2bb88021217b99ca
\ No newline at end of file
+b5c424ab9800fcc350a917ad8e05d85120e903ca
\ No newline at end of file
diff --git a/chrome/renderer/DEPS b/chrome/renderer/DEPS
index 0d8d9651..9c6fc5d 100644
--- a/chrome/renderer/DEPS
+++ b/chrome/renderer/DEPS
@@ -4,6 +4,7 @@
   "+components/autofill/content/renderer",
   "+components/autofill/core/common",
   "+components/cdm/renderer",
+  "+components/client_hints/common",
   "+components/content_capture/common",
   "+components/content_capture/renderer",
   "+components/content_settings/core/common",
diff --git a/chrome/renderer/content_settings_agent_impl.cc b/chrome/renderer/content_settings_agent_impl.cc
index 2aa7543..ae4cf6d 100644
--- a/chrome/renderer/content_settings_agent_impl.cc
+++ b/chrome/renderer/content_settings_agent_impl.cc
@@ -12,9 +12,9 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/common/chrome_features.h"
-#include "chrome/common/client_hints/client_hints.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/ssl_insecure_content.h"
+#include "components/client_hints/common/client_hints.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings.mojom.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 5b73185a..28b8ba1e 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2304,6 +2304,7 @@
         "../browser/chromeos/login/wizard_controller_browsertest.cc",
         "../browser/chromeos/net/network_portal_detector_impl_browsertest.cc",
         "../browser/chromeos/network_change_manager_client_browsertest.cc",
+        "../browser/chromeos/platform_keys/platform_keys_service_browsertest.cc",
         "../browser/chromeos/plugin_vm/plugin_vm_test_helper.cc",
         "../browser/chromeos/policy/affiliation_test_helper.cc",
         "../browser/chromeos/policy/affiliation_test_helper.h",
@@ -4473,7 +4474,6 @@
     sources += [
       "../browser/spellchecker/spell_check_host_chrome_impl_mac_unittest.cc",
       "../browser/spellchecker/spellcheck_custom_dictionary_unittest.cc",
-      "../browser/spellchecker/spellcheck_language_policy_handlers_unittest.cc",
       "../browser/spellchecker/spellcheck_service_unittest.cc",
       "../tools/convert_dict/convert_dict_unittest.cc",
     ]
diff --git a/chrome/test/data/webrtc/peerconnection_getstats.js b/chrome/test/data/webrtc/peerconnection_getstats.js
index 568dfb2f..77aedd2 100644
--- a/chrome/test/data/webrtc/peerconnection_getstats.js
+++ b/chrome/test/data/webrtc/peerconnection_getstats.js
@@ -204,6 +204,12 @@
   pliCount: 'number',
   sliCount: 'number',
   encoderImplementation: 'string',
+  rid: 'string',
+  frameWidth: 'number',
+  frameHeight: 'number',
+  framesPerSecond: 'number',
+  framesSent: 'number',
+  hugeFramesSent: 'number',
 });
 addRTCStatsToWhitelist(
     Presence.MANDATORY, 'outbound-rtp', kRTCOutboundRtpStreamStats);
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index cd02eb3..120c486f 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -101,7 +101,6 @@
     "settings/a11y/basic_a11y_test.js",
     "settings/a11y/edit_dictionary_a11y_test.js",
     "settings/a11y/passwords_a11y_test.js",
-    "settings/advanced_page_browsertest.js",
     "settings/cr_settings_browsertest.js",
     "settings/cr_settings_v3_browsertest.js",
     "settings/help_page_browsertest.js",
@@ -215,6 +214,7 @@
     "$root_gen_dir/chrome/test/data/webui/mock_timer.m.js",
     "$root_gen_dir/chrome/test/data/webui/resources/list_property_update_behavior_tests.m.js",
     "$root_gen_dir/chrome/test/data/webui/settings/about_page_tests.m.js",
+    "$root_gen_dir/chrome/test/data/webui/settings/advanced_page_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/settings/all_sites_tests.m.js",
     "$root_gen_dir/chrome/test/data/webui/settings/appearance_page_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/settings/appearance_fonts_page_test.m.js",
@@ -272,6 +272,7 @@
     "$root_gen_dir/chrome/test/data/webui/settings/secure_dns_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/settings/settings_main_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/settings/settings_menu_test.m.js",
+    "$root_gen_dir/chrome/test/data/webui/settings/settings_page_test_util.m.js",
     "$root_gen_dir/chrome/test/data/webui/settings/settings_slider_tests.m.js",
     "$root_gen_dir/chrome/test/data/webui/settings/settings_subpage_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/settings/settings_textarea_tests.m.js",
diff --git a/chrome/test/data/webui/chromeos/print_management/print_management_test.js b/chrome/test/data/webui/chromeos/print_management/print_management_test.js
index 130d75a9..1d1b6b0b 100644
--- a/chrome/test/data/webui/chromeos/print_management/print_management_test.js
+++ b/chrome/test/data/webui/chromeos/print_management/print_management_test.js
@@ -7,6 +7,7 @@
 import 'chrome://print-management/print_management.js';
 
 import {setMetadataProviderForTesting} from 'chrome://print-management/mojo_interface_provider.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 const CompletionStatus = {
   FAILED: 0,
@@ -60,6 +61,35 @@
   return jobEntry;
 }
 
+/**
+ * @param{!Array<!chromeos.printing.printingManager.mojom.PrintJobInfo>}
+ *     expected
+ * @param{!Array<!HTMLElement>} actual
+ */
+function verifyPrintJobs(expected, actual) {
+  assertEquals(expected.length, actual.length);
+  for (let i = 0; i < expected.length; i++) {
+    const actualJobInfo = actual[i].jobEntry;
+    assertEquals(expected[i].id, actualJobInfo.id);
+    assertEquals(expected[i].title, actualJobInfo.title);
+    assertEquals(expected[i].completionStatus, actualJobInfo.completionStatus);
+    assertEquals(expected[i].creationTime, actualJobInfo.creationTime);
+    assertEquals(expected[i].printerName, actualJobInfo.printerName);
+    assertEquals(expected[i].creationTime, actualJobInfo.creationTime);
+  }
+}
+
+/**
+ * @param {!HTMLElement} page
+ * @return {!Array<!HTMLElement>}
+ */
+function getPrintJobEntries(page) {
+  flush();
+  const entryList = page.$$('#entryList');
+  return Array.from(
+      entryList.querySelectorAll('print-job-entry:not([hidden])'));
+}
+
 class FakePrintingMetadataProvider {
   constructor() {
     /** @private {!Map<string, !PromiseResolver>} */
@@ -107,6 +137,14 @@
   }
 
   /**
+   * @param {?Array<!chromeos.printing.printingManager.mojom.PrintJobInfo>}
+   *     printJobs
+   */
+  setPrintJobs(printJobs) {
+    this.printJobs_ = printJobs;
+  }
+
+  /**
    * @param {chromeos.printing.printingManager.mojom.PrintJobInfo} job
    */
   addPrintJob(job) {
@@ -145,8 +183,6 @@
 
   setup(function() {
     PolymerTest.clearBody();
-    page = document.createElement('print-management');
-    document.body.appendChild(page);
   });
 
   teardown(function() {
@@ -154,10 +190,38 @@
     page = null;
   });
 
-  test('MainPageLoaded', () => {
-    // TODO(jimmyxgong): Remove this stub test once the app has more
-    // capabilities to test.
-    assertEquals('Print Management', page.$$('#header').textContent);
+  /**
+   * @param {?Array<!chromeos.printing.printingManager.mojom.PrintJobInfo>}
+   *     printJobs
+   */
+  function initializePrintManagementApp(printJobs) {
+    mojoApi_.setPrintJobs(printJobs);
+    page = document.createElement('print-management');
+    document.body.appendChild(page);
+    flush();
+  }
+
+  test('PrintHistoryListIsSortedReverseChronologically', () => {
+    const expectedArr = [
+      createJobEntry(
+          'newest', 'titleA', CompletionStatus.PRINTED,
+          new Date(Date.UTC(2020, 3, 1, 1, 1, 1)), 'nameA'),
+      createJobEntry(
+          'middle', 'titleA', CompletionStatus.PRINTED,
+          new Date(Date.UTC(2020, 2, 1, 1, 1, 1)), 'nameB'),
+      createJobEntry(
+          'oldest', 'titleC', CompletionStatus.PRINTED,
+          new Date(Date.UTC(2020, 1, 1, 1, 1, 1)), 'nameC')
+    ];
+
+    // Initialize with a reversed array of |expectedArr|, since we expect the
+    // app to sort the list when it first loads. Since reverse() mutates the
+    // original array, use a copy array to prevent mutating |expectedArr|.
+    initializePrintManagementApp(expectedArr.slice().reverse());
+
+    mojoApi_.whenCalled('getPrintJobs').then(() => {
+      verifyPrintJobs(expectedArr, getPrintJobEntries(page));
+    });
   });
 });
 
@@ -234,4 +298,4 @@
     updateAndVerifyCompletionStatus(
         jobEntryTestElement, CompletionStatus.CANCELED, 'Canceled');
   });
-});
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/cr_components/cr_components_browsertest.js b/chrome/test/data/webui/cr_components/cr_components_browsertest.js
index f0c046c..e5b4dd7 100644
--- a/chrome/test/data/webui/cr_components/cr_components_browsertest.js
+++ b/chrome/test/data/webui/cr_components/cr_components_browsertest.js
@@ -7,6 +7,8 @@
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
 
+GEN('#include "chrome/browser/ui/ui_features.h"');
+
 /**
  * Test fixture for shared Polymer components.
  * @constructor
@@ -119,6 +121,9 @@
   browsePreload: 'chrome://settings/privacy_page/privacy_page.html',
 
   /** @override */
+  featureList: {disabled: ['features::kSettingsPolymer3']},
+
+  /** @override */
   extraLibraries: CrComponentsBrowserTest.prototype.extraLibraries.concat([
     '../test_util.js',
     '../test_browser_proxy.js',
diff --git a/chrome/test/data/webui/media/media_feeds_webui_browsertest.js b/chrome/test/data/webui/media/media_feeds_webui_browsertest.js
index 01425a8f..7e82e218 100644
--- a/chrome/test/data/webui/media/media_feeds_webui_browsertest.js
+++ b/chrome/test/data/webui/media/media_feeds_webui_browsertest.js
@@ -111,8 +111,7 @@
     GEN('logos.push_back(logo2);');
     GEN('service->StoreMediaFeedFetchResult(');
     GEN('  1, std::move(items), media_feeds::mojom::FetchResult::kSuccess,');
-    GEN('  base::Time::FromDeltaSinceWindowsEpoch(');
-    GEN('  base::TimeDelta::FromMinutes(40)), logos, "Test Feed");');
+    GEN('  false, logos, "Test Feed");');
     GEN('base::RunLoop run_loop;');
     GEN('service->PostTaskToDBForTest(run_loop.QuitClosure());');
     GEN('run_loop.Run();');
@@ -137,7 +136,7 @@
         [
           'ID', 'Url', 'Display Name', 'Last Discovery Time', 'Last Fetch Time',
           'User Status', 'Last Fetch Result', 'Fetch Failed Count',
-          'Cache Expiry Time', 'Last Fetch Item Count',
+          'Last Fetch Time (not cache hit)', 'Last Fetch Item Count',
           'Last Fetch Play Next Count', 'Last Fetch Content Types', 'Logos',
           'Actions'
         ],
diff --git a/chrome/test/data/webui/new_tab_page/app_test.js b/chrome/test/data/webui/new_tab_page/app_test.js
index b3800edc..e25f6295 100644
--- a/chrome/test/data/webui/new_tab_page/app_test.js
+++ b/chrome/test/data/webui/new_tab_page/app_test.js
@@ -5,6 +5,7 @@
 import 'chrome://new-tab-page/app.js';
 
 import {BrowserProxy} from 'chrome://new-tab-page/browser_proxy.js';
+import {BackgroundSelectionType} from 'chrome://new-tab-page/customize_dialog.js';
 import {assertNotStyle, assertStyle, createTestProxy} from 'chrome://test/new_tab_page/test_support.js';
 import {flushTasks} from 'chrome://test/test_util.m.js';
 
@@ -181,4 +182,44 @@
     assertTrue(app.$.logo.singleColored);
     assertStyle(app.$.logo, '--ntp-logo-color', 'rgb(255, 0, 0)');
   });
+
+  test('preview background image', async () => {
+    const theme = createTheme();
+    theme.backgroundImageUrl = {url: 'https://example.com/image.png'};
+    theme.backgroundImageAttribution1 = 'foo';
+    theme.backgroundImageAttribution2 = 'bar';
+    theme.backgroundImageAttributionUrl = {url: 'https://info.com'};
+    testProxy.callbackRouterRemote.setTheme(theme);
+    await testProxy.callbackRouterRemote.$.flushForTesting();
+    assertEquals(
+        'background_image?https://example.com/image.png',
+        app.$.backgroundImage.path);
+    assertEquals('https://info.com/', app.$.backgroundImageAttribution.href);
+    assertEquals('foo', app.$.backgroundImageAttribution1.innerText);
+    assertEquals('bar', app.$.backgroundImageAttribution2.innerText);
+    app.$.customizeButton.click();
+    await flushTasks();
+    const dialog = app.shadowRoot.querySelector('ntp-customize-dialog');
+    dialog.backgroundSelection = {
+      type: BackgroundSelectionType.IMAGE,
+      image: {
+        attribution1: '1',
+        attribution2: '2',
+        attributionUrl: {url: 'https://example.com'},
+        imageUrl: {url: 'https://example.com/other.png'},
+      },
+    };
+    assertEquals(
+        'background_image?https://example.com/other.png',
+        app.$.backgroundImage.path);
+    assertEquals('https://example.com/', app.$.backgroundImageAttribution.href);
+    assertEquals('1', app.$.backgroundImageAttribution1.innerText);
+    assertEquals('2', app.$.backgroundImageAttribution2.innerText);
+    assertFalse(app.$.backgroundImageAttribution2.hidden);
+
+    dialog.backgroundSelection = {type: BackgroundSelectionType.NO_SELECTION};
+    assertEquals(
+        'background_image?https://example.com/image.png',
+        app.$.backgroundImage.path);
+  });
 });
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index a55da60..70f986f 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -9,6 +9,7 @@
 js_modulizer("modulize") {
   input_files = [
     "about_page_tests.js",
+    "advanced_page_test.js",
     "all_sites_tests.js",
     "appearance_fonts_page_test.js",
     "appearance_page_test.js",
@@ -69,6 +70,7 @@
     "settings_animated_pages_test.js",
     "settings_main_test.js",
     "settings_menu_test.js",
+    "settings_page_test_util.js",
     "settings_slider_tests.js",
     "settings_subpage_test.js",
     "settings_textarea_tests.js",
@@ -156,6 +158,8 @@
                          "settings.setSearchManagerForTesting|setSearchManagerForTesting",
                          "settings.TestLanguagesBrowserProxy|TestLanguagesBrowserProxy",
                          "settings.TestLifetimeBrowserProxy|TestLifetimeBrowserProxy",
+                         "settings_page_test_util.getPage|getPage",
+                         "settings_page_test_util.getSection|getSection",
                          "settings_search.createSampleSearchEngine|createSampleSearchEngine",
                          "settings_search.TestSearchEnginesBrowserProxy|TestSearchEnginesBrowserProxy",
                          "sync_test_util.getSyncAllPrefs|getSyncAllPrefs",
diff --git a/chrome/test/data/webui/settings/a11y/settings_accessibility_test.js b/chrome/test/data/webui/settings/a11y/settings_accessibility_test.js
index f14d3986..0dfc6b32 100644
--- a/chrome/test/data/webui/settings/a11y/settings_accessibility_test.js
+++ b/chrome/test/data/webui/settings/a11y/settings_accessibility_test.js
@@ -10,6 +10,8 @@
   '//chrome/test/data/webui/polymer_browser_test_base.js',
 ]);
 
+GEN('#include "chrome/browser/ui/ui_features.h"');
+
 /**
  * Test fixture for Accessibility of Chrome Settings.
  * @constructor
@@ -81,6 +83,9 @@
     '../ensure_lazy_loaded.js',
   ],
 
+  /** @override */
+  featureList: {disabled: ['features::kSettingsPolymer3']},
+
   setUp: function() {
     PolymerTest.prototype.setUp.call(this);
     settings.ensureLazyLoaded();
diff --git a/chrome/test/data/webui/settings/advanced_page_browsertest.js b/chrome/test/data/webui/settings/advanced_page_browsertest.js
deleted file mode 100644
index 3f11977..0000000
--- a/chrome/test/data/webui/settings/advanced_page_browsertest.js
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/** @fileoverview Suite of tests for the Settings advanced page. */
-
-// Polymer BrowserTest fixture.
-GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
-
-/**
- * @constructor
- * @extends {PolymerTest}
- */
-function SettingsAdvancedPageBrowserTest() {}
-
-SettingsAdvancedPageBrowserTest.prototype = {
-  __proto__: PolymerTest.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://settings/',
-
-  /** @override */
-  extraLibraries: [
-    ...PolymerTest.prototype.extraLibraries,
-    'settings_page_test_util.js',
-  ],
-
-  /** @override */
-  setUp: function() {
-    PolymerTest.prototype.setUp.call(this);
-    suiteSetup(function() {
-      return CrSettingsPrefs.initialized;
-    });
-
-    suiteSetup(() => {
-      return settings_page_test_util.getPage('basic').then(basicPage => {
-        this.basicPage = basicPage;
-      });
-    });
-  },
-
-  /**
-   * Verifies the section has a visible #main element and that any possible
-   * sub-pages are hidden.
-   * @param {!Node} The DOM node for the section.
-   */
-  verifySubpagesHidden: function(section) {
-    // Check if there are sub-pages to verify.
-    const pages = section.firstElementChild.shadowRoot.querySelector(
-        'settings-animated-pages');
-    if (!pages) {
-      return;
-    }
-
-    const children = pages.getContentChildren();
-    const stampedChildren = children.filter(function(element) {
-      return element.tagName != 'TEMPLATE';
-    });
-
-    // The section's main child should be stamped and visible.
-    const main = stampedChildren.filter(function(element) {
-      return element.getAttribute('route-path') == 'default';
-    });
-    assertEquals(
-        main.length, 1,
-        'default card not found for section ' + section.section);
-    assertGT(main[0].offsetHeight, 0);
-
-    // Any other stamped subpages should not be visible.
-    const subpages = stampedChildren.filter(function(element) {
-      return element.getAttribute('route-path') != 'default';
-    });
-    for (const subpage of subpages) {
-      assertEquals(
-          subpage.offsetHeight, 0,
-          'Expected subpage #' + subpage.id + ' in ' + section.section +
-              ' not to be visible.');
-    }
-  }
-};
-
-// Times out on debug builders because the Settings page can take several
-// seconds to load in a Release build and several times that in a Debug build.
-// See https://crbug.com/558434.
-GEN('#if !defined(NDEBUG)');
-GEN('#define MAYBE_Load DISABLED_Load');
-GEN('#else');
-GEN('#define MAYBE_Load Load');
-GEN('#endif');
-
-TEST_F('SettingsAdvancedPageBrowserTest', 'MAYBE_Load', function() {
-  // Assign |self| to |this| instead of binding since 'this' in suite()
-  // and test() will be a Mocha 'Suite' or 'Test' instance.
-  const self = this;
-
-  // Register mocha tests.
-  suite('SettingsPage', function() {
-    suiteSetup(function() {
-      const settingsMain =
-          document.querySelector('settings-ui').$$('settings-main');
-      assert(!!settingsMain);
-      settingsMain.advancedToggleExpanded =
-          !settingsMain.advancedToggleExpanded;
-      Polymer.dom.flush();
-    });
-
-    test('load page', function() {
-      // This will fail if there are any asserts or errors in the Settings page.
-    });
-
-    test('advanced pages', function() {
-      const page = self.basicPage;
-      const sections =
-          ['privacy', 'languages', 'downloads', 'printing', 'reset'];
-      for (let i = 0; i < sections.length; i++) {
-        const section = settings_page_test_util.getSection(page, sections[i]);
-        assertTrue(!!section);
-        self.verifySubpagesHidden(section);
-      }
-    });
-  });
-
-  // Run all registered tests.
-  mocha.run();
-});
diff --git a/chrome/test/data/webui/settings/advanced_page_test.js b/chrome/test/data/webui/settings/advanced_page_test.js
new file mode 100644
index 0000000..9443834
--- /dev/null
+++ b/chrome/test/data/webui/settings/advanced_page_test.js
@@ -0,0 +1,90 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @fileoverview Suite of tests for the Settings advanced page. */
+
+// clang-format off
+// #import {CrSettingsPrefs} from 'chrome://settings/settings.js';
+// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+// #import {getPage, getSection} from 'chrome://test/settings/settings_page_test_util.m.js';
+// clang-format on
+
+suite('AdvancedPage', function() {
+  let basicPage = null;
+
+  suiteSetup(function() {
+    PolymerTest.clearBody();
+    const ui = document.createElement('settings-ui');
+    document.body.appendChild(ui);
+    return CrSettingsPrefs.initialized
+        .then(() => {
+          return settings_page_test_util.getPage('basic');
+        })
+        .then(page => {
+          basicPage = page;
+          const settingsMain =
+              document.querySelector('settings-ui').$$('settings-main');
+          assertTrue(!!settingsMain);
+          settingsMain.advancedToggleExpanded =
+              !settingsMain.advancedToggleExpanded;
+          Polymer.dom.flush();
+        });
+  });
+
+  /**
+   * Verifies the section has a visible #main element and that any possible
+   * sub-pages are hidden.
+   * @param {!Node} The DOM node for the section.
+   */
+  function verifySubpagesHidden(section) {
+    // Check if there are sub-pages to verify.
+    const pages = section.firstElementChild.shadowRoot.querySelector(
+        'settings-animated-pages');
+    if (!pages) {
+      return;
+    }
+
+    const children = pages.getContentChildren();
+    const stampedChildren = children.filter(function(element) {
+      return element.tagName != 'TEMPLATE';
+    });
+
+    // The section's main child should be stamped and visible.
+    const main = stampedChildren.filter(function(element) {
+      return element.getAttribute('route-path') == 'default';
+    });
+    assertEquals(
+        main.length, 1,
+        'default card not found for section ' + section.section);
+    assertGT(main[0].offsetHeight, 0);
+
+    // Any other stamped subpages should not be visible.
+    const subpages = stampedChildren.filter(function(element) {
+      return element.getAttribute('route-path') != 'default';
+    });
+    for (const subpage of subpages) {
+      assertEquals(
+          subpage.offsetHeight, 0,
+          'Expected subpage #' + subpage.id + ' in ' + section.section +
+              ' not to be visible.');
+    }
+  }
+
+  test('load page', function() {
+    // This will fail if there are any asserts or errors in the Settings page.
+  });
+
+  test('advanced pages', function() {
+    const sections = ['a11y', 'languages', 'downloads', 'printing', 'reset'];
+    if (!loadTimeData.getBoolean('privacySettingsRedesignEnabled')) {
+      sections.push('privacy');
+    }
+    for (let i = 0; i < sections.length; i++) {
+      const section =
+          settings_page_test_util.getSection(basicPage, sections[i]);
+      assertTrue(!!section);
+      verifySubpagesHidden(section);
+    }
+  });
+});
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index e033b85..52ad200 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -1272,6 +1272,25 @@
   mocha.grep(assert(os_languages_page_tests.TestNames.InputMethods)).run();
 });
 
+// eslint-disable-next-line no-var
+var OSSettingsSmartInputsPageTest = class extends OSSettingsBrowserTest {
+  /** @override */
+  get browsePreload() {
+    return super.browsePreload +
+        'chromeos/os_languages_page/smart_inputs_page.html';
+  }
+  /** @override */
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'smart_inputs_page_test.js',
+    ]);
+  }
+};
+
+TEST_F('OSSettingsSmartInputsPageTest', 'AllJsTests', () => {
+  mocha.run();
+});
+
 // Tests for the Reset section.
 // eslint-disable-next-line no-var
 var OSSettingsResetPageTest = class extends OSSettingsBrowserTest {
diff --git a/chrome/test/data/webui/settings/chromeos/smart_inputs_page_test.js b/chrome/test/data/webui/settings/chromeos/smart_inputs_page_test.js
new file mode 100644
index 0000000..24fc8aae
--- /dev/null
+++ b/chrome/test/data/webui/settings/chromeos/smart_inputs_page_test.js
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+let smartInputsPage = null;
+
+function createSmartInputsPage() {
+  PolymerTest.clearBody();
+  smartInputsPage = document.createElement('os-settings-smart-inputs-page');
+  document.body.appendChild(smartInputsPage);
+  Polymer.dom.flush();
+}
+
+suite('SmartInputsPage', function() {
+  teardown(function() {
+    smartInputsPage.remove();
+  });
+
+  test(
+      'assistPersonalInfoNotNullWhenAllowAssistivePersonalInfoIsTrue',
+      function() {
+        loadTimeData.overrideValues({allowAssistivePersonalInfo: true});
+        createSmartInputsPage();
+        assertTrue(!!smartInputsPage.$$('#assistPersonalInfo'));
+      });
+
+  test(
+      'assistPersonalInfoNullWhenAllowAssistivePersonalInfoIsFalse',
+      function() {
+        loadTimeData.overrideValues({allowAssistivePersonalInfo: false});
+        createSmartInputsPage();
+        assertFalse(!!smartInputsPage.$$('#assistPersonalInfo'));
+      });
+});
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index fb4ca63..9c8c8a1 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -12,6 +12,7 @@
 GEN('#endif  // defined(OS_CHROMEOS)');
 
 GEN('#include "build/branding_buildflags.h"');
+GEN('#include "chrome/browser/ui/ui_features.h"');
 GEN('#include "chrome/common/chrome_features.h"');
 GEN('#include "components/autofill/core/common/autofill_features.h"');
 GEN('#include "components/omnibox/common/omnibox_features.h"');
@@ -39,6 +40,22 @@
   ],
 
   /** @override */
+  get featureList() {
+    return {
+      enabled: this.featureListInternal.enabled || [],
+      disabled: [
+        'features::kSettingsPolymer3',
+        ...(this.featureListInternal.disabled || []),
+      ],
+    };
+  },
+
+  /** @return {!{enabled: !Array<string>, disabled: !Array<string>}} */
+  get featureListInternal() {
+    return {enabled: [], disabled: []};
+  },
+
+  /** @override */
   setUp: function() {
     PolymerTest.prototype.setUp.call(this);
 
@@ -298,7 +315,9 @@
   /** @override */
   browsePreload: 'chrome://settings/autofill_page/autofill_section.html',
 
-  featureList: {enabled: ['autofill::features::kAutofillEnableCompanyName']},
+  /** @override */
+  featureListInternal:
+      {enabled: ['autofill::features::kAutofillEnableCompanyName']},
 
   /** @override */
   extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
@@ -324,7 +343,9 @@
   /** @override */
   browsePreload: 'chrome://settings/autofill_page/autofill_section.html',
 
-  featureList: {disabled: ['autofill::features::kAutofillEnableCompanyName']},
+  /** @override */
+  featureListInternal:
+      {disabled: ['autofill::features::kAutofillEnableCompanyName']},
 
   /** @override */
   extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
@@ -356,7 +377,9 @@
   /** @override */
   browsePreload: 'chrome://settings/autofill_page/passwords_section.html',
 
-  featureList: {enabled: ['password_manager::features::kPasswordCheck']},
+  /** @override */
+  featureListInternal:
+      {enabled: ['password_manager::features::kPasswordCheck']},
 
   /** @override */
   extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
@@ -389,7 +412,9 @@
   /** @override */
   browsePreload: 'chrome://settings/autofill_page/password_check.html',
 
-  featureList: {enabled: ['password_manager::features::kPasswordCheck']},
+  /** @override */
+  featureListInternal:
+      {enabled: ['password_manager::features::kPasswordCheck']},
 
   /** @override */
   extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
@@ -517,7 +542,8 @@
   // length-checked in this test. The feature is defaulted on here during
   // rollout, reflecting its value in fieldtrial_testing_config.json.
   // See crbug.com/908435.
-  featureList: {enabled: ['omnibox::kDocumentProvider']},
+  /** @override */
+  featureListInternal: {enabled: ['omnibox::kDocumentProvider']},
 
   /** @override */
   extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
@@ -640,7 +666,8 @@
   // length-checked in this test. The feature is defaulted on here during
   // rollout, reflecting its value in fieldtrial_testing_config.json.
   // See crbug.com/908435.
-  featureList: {enabled: ['omnibox::kDocumentProvider']},
+  /** @override */
+  featureListInternal: {enabled: ['omnibox::kDocumentProvider']},
 
   /** @override */
   extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
@@ -1079,7 +1106,8 @@
   /** @override */
   browsePreload: 'chrome://settings/privacy_page/privacy_page.html',
 
-  featureList: {enabled: ['features::kPrivacySettingsRedesign']},
+  /** @override */
+  featureListInternal: {enabled: ['features::kPrivacySettingsRedesign']},
 
   /** @override */
   extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
@@ -1153,11 +1181,12 @@
   /** @override */
   browsePreload: 'chrome://settings/safety_check_page/safety_check_page.html',
 
-  featureList: {
+  /** @override */
+  featureListInternal: {
     enabled: [
       'features::kPrivacySettingsRedesign',
-      'password_manager::features::kPasswordCheck'
-    ]
+      'password_manager::features::kPasswordCheck',
+    ],
   },
 
   /** @override */
@@ -2259,3 +2288,35 @@
 TEST_F('CrSettingsBasicPageTest', 'All', function() {
   mocha.run();
 });
+
+/**
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsAdvancedPageTest() {}
+
+CrSettingsAdvancedPageTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://settings/',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    'settings_page_test_util.js',
+    'advanced_page_test.js',
+  ]),
+};
+
+// Times out on debug builders because the Settings page can take several
+// seconds to load in a Release build and several times that in a Debug build.
+// See https://crbug.com/558434.
+GEN('#if !defined(NDEBUG)');
+GEN('#define MAYBE_Load DISABLED_Load');
+GEN('#else');
+GEN('#define MAYBE_Load Load');
+GEN('#endif');
+
+TEST_F('CrSettingsAdvancedPageTest', 'MAYBE_Load', function() {
+  mocha.run();
+});
diff --git a/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js b/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js
index 981bd16..23dab05 100644
--- a/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js
+++ b/chrome/test/data/webui/settings/cr_settings_interactive_ui_tests.js
@@ -7,6 +7,8 @@
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_interactive_ui_test.js']);
 
+GEN('#include "chrome/browser/ui/ui_features.h"');
+
 /**
  * Test fixture for interactive Polymer Settings elements.
  * @constructor
@@ -29,6 +31,11 @@
   ],
 
   /** @override */
+  get featureList() {
+    return {disabled: ['features::kSettingsPolymer3']};
+  },
+
+  /** @override */
   setUp: function() {
     PolymerInteractiveUITest.prototype.setUp.call(this);
 
diff --git a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
index e2537ef..ee2d70bc 100644
--- a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
@@ -36,10 +36,16 @@
       enabled: [
         'network::features::kOutOfBlinkCors',
         'features::kSettingsPolymer3',
+        ...(this.featureListInternal.enabled || []),
       ],
-      disabled: [],
+      disabled: this.featureListInternal.disabled || [],
     };
   }
+
+  /** @return {!{enabled: !Array<string>, disabled: !Array<string>}} */
+  get featureListInternal() {
+    return {enabled: [], disabled: []};
+  }
 };
 
 // eslint-disable-next-line no-var
@@ -142,10 +148,10 @@
   }
 
   /** @override */
-  get featureList() {
-    const list = super.featureList;
-    list.enabled.push('autofill::features::kAutofillEnableCompanyName');
-    return list;
+  get featureListInternal() {
+    return {
+      enabled: ['autofill::features::kAutofillEnableCompanyName'],
+    };
   }
 };
 
@@ -166,10 +172,8 @@
   }
 
   /** @override */
-  get featureList() {
-    const list = super.featureList;
-    list.disabled.push('autofill::features::kAutofillEnableCompanyName');
-    return list;
+  get featureListInternal() {
+    return {disabled: ['autofill::features::kAutofillEnableCompanyName']};
   }
 };
 
@@ -187,11 +191,10 @@
   get browsePreload() {
     return 'chrome://settings/test_loader.html?module=settings/passwords_section_test.m.js';
   }
+
   /** @override */
-  get featureList() {
-    const list = super.featureList;
-    list.enabled.push('password_manager::features::kPasswordCheck');
-    return list;
+  get featureListInternal() {
+    return {enabled: ['password_manager::features::kPasswordCheck']};
   }
 };
 
@@ -207,10 +210,8 @@
   }
 
   /** @override */
-  get featureList() {
-    const list = super.featureList;
-    list.enabled.push('password_manager::features::kPasswordCheck');
-    return list;
+  get featureListInternal() {
+    return {enabled: ['password_manager::features::kPasswordCheck']};
   }
 };
 
@@ -226,11 +227,13 @@
   }
 
   /** @override */
-  get featureList() {
-    const list = super.featureList;
-    list.enabled.push('features::kPrivacySettingsRedesign');
-    list.enabled.push('password_manager::features::kPasswordCheck');
-    return list;
+  get featureListInternal() {
+    return {
+      enabled: [
+        'features::kPrivacySettingsRedesign',
+        'password_manager::features::kPasswordCheck',
+      ],
+    };
   }
 };
 
@@ -348,10 +351,9 @@
     return 'chrome://settings/test_loader.html?module=settings/privacy_page_test.m.js';
   }
 
-  get featureList() {
-    const list = super.featureList;
-    list.enabled.push('features::kPrivacySettingsRedesign');
-    return list;
+  /** @override */
+  get featureListInternal() {
+    return {enabled: ['features::kPrivacySettingsRedesign']};
   }
 };
 
@@ -389,6 +391,27 @@
   runMochaSuite('NonExistentRoute');
 });
 
+// eslint-disable-next-line no-var
+var CrSettingsAdvancedPageV3Test = class extends CrSettingsV3BrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://settings/test_loader.html?module=settings/advanced_page_test.m.js';
+  }
+};
+
+// Copied from Polymer 2 test:
+// Times out on debug builders because the Settings page can take several
+// seconds to load in a Release build and several times that in a Debug build.
+// See https://crbug.com/558434.
+GEN('#if !defined(NDEBUG)');
+GEN('#define MAYBE_Load DISABLED_Load');
+GEN('#else');
+GEN('#define MAYBE_Load Load');
+GEN('#endif');
+TEST_F('CrSettingsAdvancedPageV3Test', 'MAYBE_Load', function() {
+  mocha.run();
+});
+
 [['AllSites', 'all_sites_tests.m.js'],
  ['AppearanceFontsPage', 'appearance_fonts_page_test.m.js'],
  ['AppearancePage', 'appearance_page_test.m.js'],
diff --git a/chrome/test/data/webui/settings/help_page_browsertest.js b/chrome/test/data/webui/settings/help_page_browsertest.js
index 2596bb9..ca1df7f 100644
--- a/chrome/test/data/webui/settings/help_page_browsertest.js
+++ b/chrome/test/data/webui/settings/help_page_browsertest.js
@@ -7,6 +7,8 @@
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
 
+GEN('#include "chrome/browser/ui/ui_features.h"');
+
 /**
  * @constructor
  * @extends {PolymerTest}
@@ -20,6 +22,9 @@
   browsePreload: 'chrome://help/',
 
   /** @override */
+  featureList: {disabled: ['features::kSettingsPolymer3']},
+
+  /** @override */
   extraLibraries: [
     ...PolymerTest.prototype.extraLibraries,
     'settings_page_test_util.js',
diff --git a/chrome/test/data/webui/settings/privacy_page_test.js b/chrome/test/data/webui/settings/privacy_page_test.js
index a343a40d..f24548c 100644
--- a/chrome/test/data/webui/settings/privacy_page_test.js
+++ b/chrome/test/data/webui/settings/privacy_page_test.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import {CookieControlsMode, SiteSettingsPrefsBrowserProxyImpl} from 'chrome://settings/lazy_load.js';
+// #import {SiteSettingsPrefsBrowserProxyImpl} from 'chrome://settings/lazy_load.js';
 // #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 // #import {MetricsBrowserProxyImpl, PrivacyElementInteractions, PrivacyPageBrowserProxyImpl, SyncBrowserProxyImpl, HatsBrowserProxyImpl, Router, routes} from 'chrome://settings/settings.js';
 // #import {TestMetricsBrowserProxy} from 'chrome://test/settings/test_metrics_browser_proxy.m.js';
@@ -226,30 +226,6 @@
           test_util.isChildVisible(page, '#security-keys-subpage-trigger'));
     }
   });
-
-  test('BlockThirdPartyCookiesToggle', async function() {
-    page.prefs.profile.block_third_party_cookies = {value: false};
-    page.prefs.profile.cookie_controls_mode = {
-      value: settings.CookieControlsMode.DISABLED
-    };
-    settings.Router.getInstance().navigateTo(
-        settings.routes.SITE_SETTINGS_COOKIES);
-    Polymer.dom.flush();
-
-    page.$$('#blockThirdPartyCookies').click();
-    Polymer.dom.flush();
-    assertTrue(page.prefs.profile.block_third_party_cookies.value);
-    assertEquals(
-        page.prefs.profile.cookie_controls_mode.value,
-        settings.CookieControlsMode.ENABLED);
-
-    page.$$('#blockThirdPartyCookies').click();
-    Polymer.dom.flush();
-    assertFalse(page.prefs.profile.block_third_party_cookies.value);
-    assertEquals(
-        page.prefs.profile.cookie_controls_mode.value,
-        settings.CookieControlsMode.DISABLED);
-  });
 });
 
 suite('PrivacyPageRedesignEnabled', function() {
diff --git a/chrome/test/data/webui/settings/settings_idle_load_browsertest.js b/chrome/test/data/webui/settings/settings_idle_load_browsertest.js
index d288328..bcfe82f 100644
--- a/chrome/test/data/webui/settings/settings_idle_load_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_idle_load_browsertest.js
@@ -4,6 +4,7 @@
 
 /** @fileoverview Tests for settings-idle-load. */
 
+GEN('#include "chrome/browser/ui/ui_features.h"');
 
 /**
  * @constructor
@@ -25,6 +26,11 @@
   ],
 
   /** @override */
+  get featureList() {
+    return {disabled: ['features::kSettingsPolymer3']};
+  },
+
+  /** @override */
   isAsync: true,
 };
 
diff --git a/chrome/test/data/webui/settings/settings_page_test_util.js b/chrome/test/data/webui/settings/settings_page_test_util.js
index 037864d..b1496f4 100644
--- a/chrome/test/data/webui/settings/settings_page_test_util.js
+++ b/chrome/test/data/webui/settings/settings_page_test_util.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+// clang-format on
+
 /** @fileoverview Test utils for Settings page tests. */
 
 cr.define('settings_page_test_util', function() {
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index f3f88411..0216b971 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -56,6 +56,8 @@
     "memory/kstaled.h",
     "memory/memory.cc",
     "memory/memory.h",
+    "memory/pagemap.cc",
+    "memory/pagemap.h",
     "memory/swap_configuration.cc",
     "memory/swap_configuration.h",
     "policy/weekly_time/time_utils.cc",
@@ -64,6 +66,8 @@
     "policy/weekly_time/weekly_time.h",
     "policy/weekly_time/weekly_time_interval.cc",
     "policy/weekly_time/weekly_time_interval.h",
+    "printing/cups_printer_status.cc",
+    "printing/cups_printer_status.h",
     "printing/epson_driver_matching.cc",
     "printing/epson_driver_matching.h",
     "printing/ppd_cache.cc",
@@ -192,9 +196,11 @@
     "//url",
   ]
   sources = [
+    "memory/pagemap_unittest.cc",
     "policy/weekly_time/time_utils_unittest.cc",
     "policy/weekly_time/weekly_time_interval_unittest.cc",
     "policy/weekly_time/weekly_time_unittest.cc",
+    "printing/cups_printer_status_unittest.cc",
     "printing/epson_driver_matching_unittest.cc",
     "printing/ppd_cache_unittest.cc",
     "printing/ppd_line_reader_unittest.cc",
diff --git a/chromeos/components/print_management/resources/print_management.js b/chromeos/components/print_management/resources/print_management.js
index bee9efd..bd088d1 100644
--- a/chromeos/components/print_management/resources/print_management.js
+++ b/chromeos/components/print_management/resources/print_management.js
@@ -55,8 +55,19 @@
     // TODO(jimmyxgong): Remove this once the app has more capabilities.
     this.$$('#header').textContent = 'Print Management';
     this.mojoInterfaceProvider_.getPrintJobs()
-        .then((responseParams) => {
-          this.printJobs_ = responseParams.printJobs;
-        });
+        .then(this.onPrintJobsReceived_.bind(this));
   },
+
+  /**
+   * @param {!PrintJobsList} jobs
+   * @private
+   */
+  onPrintJobsReceived_(jobs) {
+    // Sort the printers in descending order based on time the print job was
+    // created.
+    this.printJobs_ = jobs.printJobs.sort((first, second) => {
+      return Number(second.creationTime.internalValue) -
+          Number(first.creationTime.internalValue);
+    });
+  }
 });
diff --git a/chromeos/memory/pagemap.cc b/chromeos/memory/pagemap.cc
new file mode 100644
index 0000000..09c1d84b
--- /dev/null
+++ b/chromeos/memory/pagemap.cc
@@ -0,0 +1,82 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/memory/pagemap.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string>
+
+#include "base/memory/aligned_memory.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/scoped_blocking_call.h"
+
+namespace chromeos {
+namespace memory {
+
+namespace {
+constexpr char kPagemapFileFormat[] = "/proc/%d/pagemap";
+}
+
+Pagemap::~Pagemap() = default;
+
+Pagemap::Pagemap(pid_t pid) {
+  if (pid) {
+    std::string pagemap_file = base::StringPrintf(kPagemapFileFormat, pid);
+    fd_.reset(HANDLE_EINTR(open(pagemap_file.c_str(), O_RDONLY)));
+  }
+}
+
+bool Pagemap::IsValid() const {
+  return fd_.is_valid();
+}
+
+bool Pagemap::GetEntries(uint64_t address,
+                         uint64_t length,
+                         std::vector<PagemapEntry>* entries) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::WILL_BLOCK);
+  DCHECK(IsValid());
+  CHECK(entries);
+
+  const size_t kPageSize = base::GetPageSize();
+  CHECK(base::IsPageAligned(address));
+  CHECK(base::IsPageAligned(length));
+
+  // The size of each pagemap entry to calculate our offset in the file.
+  uint64_t num_pages = length / kPageSize;
+
+  if (entries->size() != num_pages) {
+    // Shrink or grow entries to the correct length if it was not already.
+    entries->resize(num_pages);
+    entries->shrink_to_fit();  // If we made it smaller shrink capacity.
+  }
+
+  uint64_t pagemap_offset = (address / kPageSize) * sizeof(PagemapEntry);
+  uint64_t pagemap_len = num_pages * sizeof(PagemapEntry);
+
+  memset(entries->data(), 0, pagemap_len);
+
+  // The caller was expected to provide a buffer large enough for the number of
+  // pages in the region.
+  uint64_t total_read = 0;
+  while (total_read < pagemap_len) {
+    ssize_t bytes_read = HANDLE_EINTR(
+        pread(fd_.get(), reinterpret_cast<char*>(entries->data()) + total_read,
+              pagemap_len - total_read, pagemap_offset + total_read));
+
+    if (bytes_read <= 0) {
+      return false;
+    }
+    total_read += bytes_read;
+  }
+
+  return true;
+}
+
+}  // namespace memory
+}  // namespace chromeos
diff --git a/chromeos/memory/pagemap.h b/chromeos/memory/pagemap.h
new file mode 100644
index 0000000..8bfb909
--- /dev/null
+++ b/chromeos/memory/pagemap.h
@@ -0,0 +1,63 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_MEMORY_PAGEMAP_H_
+#define CHROMEOS_MEMORY_PAGEMAP_H_
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "chromeos/chromeos_export.h"
+
+namespace chromeos {
+namespace memory {
+
+// Pagemap fetches pagemap entries from procfs for a process.
+class CHROMEOS_EXPORT Pagemap {
+ public:
+  // For more information on the Pagemap layout see the kernel documentation at
+  // https://www.kernel.org/doc/Documentation/vm/pagemap.txt
+  struct PagemapEntry {
+    uint8_t swap_type : 5;
+    uint64_t swap_offset : 50;
+    bool pte_soft_dirty : 1;
+    bool page_exclusively_mapped : 1;
+    uint8_t : 4;  // these bits are unused
+    bool page_file_or_shared_anon : 1;
+    bool page_swapped : 1;
+    bool page_present : 1;
+  } __attribute__((packed));
+
+  static_assert(sizeof(PagemapEntry) == sizeof(uint64_t),
+                "PagemapEntry is expected to be 8 bytes");
+
+  explicit Pagemap(pid_t pid);
+  ~Pagemap();
+
+  bool IsValid() const;
+
+  // GetEntries will populate |entries| for the memory region specified.
+  // It is required that |address| be page aligned and |length| must always be a
+  // page length multiple. Additionally, |entries| is expected to be sized to
+  // the number of pages in the range specified. If it's not properly sized it
+  // will be resized to the appropriate length for the caller.
+  bool GetEntries(uint64_t address,
+                  uint64_t length,
+                  std::vector<PagemapEntry>* entries);
+
+ private:
+  friend class PagemapTest;
+
+  base::ScopedFD fd_;
+
+  DISALLOW_COPY_AND_ASSIGN(Pagemap);
+};
+
+}  // namespace memory
+}  // namespace chromeos
+
+#endif  // CHROMEOS_MEMORY_PAGEMAP_H_
diff --git a/chromeos/memory/pagemap_unittest.cc b/chromeos/memory/pagemap_unittest.cc
new file mode 100644
index 0000000..a596fd2
--- /dev/null
+++ b/chromeos/memory/pagemap_unittest.cc
@@ -0,0 +1,222 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/memory/pagemap.h"
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <chrono>
+#include <random>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace memory {
+
+namespace {
+template <typename T, size_t N>
+constexpr size_t countof(T (&array)[N]) {
+  return N;
+}
+
+}  // namespace
+
+class PagemapTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Use a memfd so we can truncate it to arbitrary lengths to simulate a real
+    // pagemap file in procfs.
+    pagemap_.fd_.reset(memfd_create("pagemap_test", MFD_CLOEXEC));
+    ASSERT_TRUE(pagemap_.fd_.is_valid());
+  }
+
+  void TearDown() override {}
+
+ protected:
+  // Set the size of the pagemap appropriate for this many pages.
+  void CreateStorageForPages(uint64_t pages,
+                             void** start_address,
+                             void** end_address) {
+    ASSERT_NE(
+        ftruncate(pagemap_.fd_.get(), pages * sizeof(Pagemap::PagemapEntry)),
+        -1);
+    *start_address = 0x0;
+    *end_address =
+        reinterpret_cast<char*>(*start_address) + base::GetPageSize() * pages;
+  }
+
+  void PutEntries(void* address, uint64_t* entries, size_t size) {
+    ASSERT_EQ(HANDLE_EINTR(pwrite(
+                  pagemap_.fd_.get(), entries, sizeof(entries[0]) * size,
+                  reinterpret_cast<off_t>(address) / base::GetPageSize())),
+              static_cast<ssize_t>(sizeof(entries[0]) * size));
+  }
+
+  Pagemap pagemap_{0};
+};
+
+// See: https://www.kernel.org/doc/Documentation/vm/pagemap.txt for more
+// information.
+//
+// We make sure that we only have 55 bits set of the PFN which is why we and it
+// with 2^55 - 1.
+#define PFN(VALUE)                                                \
+  ((reinterpret_cast<uint64_t>(reinterpret_cast<void*>(VALUE))) & \
+   ((static_cast<uint64_t>(1) << 55) - 1))
+#define SOFT_DIRTY static_cast<uint64_t>(1) << 55
+#define EXCLUSIVELY_MAPPED static_cast<uint64_t>(1) << 56
+#define FILE_PAGE static_cast<uint64_t>(1) << 61
+#define SWAPPED static_cast<uint64_t>(1) << 62
+#define PRESENT static_cast<uint64_t>(1) << 63
+
+#define PFN_FROM_TYPE_AND_OFFSET(SWAP_TYPE, OFFSET) \
+  ((SWAP_TYPE & 0x1F) | (OFFSET << 5))
+
+TEST_F(PagemapTest, Basic) {
+  void* start_address;
+  void* end_address;
+  CreateStorageForPages(4, &start_address, &end_address);
+
+  uint64_t page_map_entries[] = {PFN(8675309) | SOFT_DIRTY | PRESENT,
+                                 PFN(1234) | SWAPPED,
+                                 PFN(5551212) | SOFT_DIRTY | FILE_PAGE,
+                                 PFN(0xF00) | PRESENT | EXCLUSIVELY_MAPPED};
+  PutEntries(start_address, page_map_entries, countof(page_map_entries));
+
+  // We now have 4 pages populated in the page map from start address to 4 *
+  // pagesize();
+
+  // Validate that the Pagemap class can interpret them correctly.
+  std::vector<Pagemap::PagemapEntry> entries;
+  entries.resize(countof(page_map_entries));
+
+  ASSERT_TRUE(pagemap_.GetEntries(
+      reinterpret_cast<uint64_t>(start_address),
+      countof(page_map_entries) * base::GetPageSize(), &entries));
+
+  ASSERT_EQ(
+      PFN_FROM_TYPE_AND_OFFSET(entries[0].swap_type, entries[0].swap_offset),
+      8675309u);
+  ASSERT_EQ(entries[0].pte_soft_dirty, true);
+  ASSERT_EQ(entries[0].page_present, true);
+  ASSERT_EQ(entries[0].page_swapped, false);
+  ASSERT_EQ(entries[0].page_exclusively_mapped, false);
+  ASSERT_EQ(entries[0].page_file_or_shared_anon, false);
+
+  ASSERT_EQ(
+      PFN_FROM_TYPE_AND_OFFSET(entries[1].swap_type, entries[1].swap_offset),
+      1234u);
+  ASSERT_EQ(entries[1].pte_soft_dirty, false);
+  ASSERT_EQ(entries[1].page_present, false);
+  ASSERT_EQ(entries[1].page_swapped, true);
+  ASSERT_EQ(entries[1].page_exclusively_mapped, false);
+  ASSERT_EQ(entries[1].page_file_or_shared_anon, false);
+
+  ASSERT_EQ(
+      PFN_FROM_TYPE_AND_OFFSET(entries[2].swap_type, entries[2].swap_offset),
+      5551212u);
+  ASSERT_EQ(entries[2].pte_soft_dirty, true);
+  ASSERT_EQ(entries[2].page_present, false);
+  ASSERT_EQ(entries[2].page_swapped, false);
+  ASSERT_EQ(entries[2].page_exclusively_mapped, false);
+  ASSERT_EQ(entries[2].page_file_or_shared_anon, true);
+
+  ASSERT_EQ(
+      PFN_FROM_TYPE_AND_OFFSET(entries[3].swap_type, entries[3].swap_offset),
+      0xF00u);
+  ASSERT_EQ(entries[3].pte_soft_dirty, false);
+  ASSERT_EQ(entries[3].page_present, true);
+  ASSERT_EQ(entries[3].page_swapped, false);
+  ASSERT_EQ(entries[3].page_exclusively_mapped, true);
+  ASSERT_EQ(entries[3].page_file_or_shared_anon, false);
+}
+
+TEST_F(PagemapTest, MidRangeRead) {
+  // This test will validate that we can read only a portion of the pages.
+  void* start_address;
+  void* end_address;
+  CreateStorageForPages(4, &start_address, &end_address);
+
+  uint64_t page_map_entries[] = {PFN(8675309) | SOFT_DIRTY | PRESENT,
+                                 PFN(1234) | SWAPPED,
+                                 PFN(5551212) | SOFT_DIRTY | FILE_PAGE,
+                                 PFN(0xF00) | PRESENT | EXCLUSIVELY_MAPPED};
+  PutEntries(start_address, page_map_entries, countof(page_map_entries));
+
+  // We will read the two middle pages.
+  std::vector<Pagemap::PagemapEntry> entries;
+  ASSERT_TRUE(pagemap_.GetEntries(
+      reinterpret_cast<uint64_t>(start_address) + base::GetPageSize(),
+      2 * base::GetPageSize(), &entries));
+  ASSERT_EQ(entries.size(), 2u);
+
+  ASSERT_EQ(
+      PFN_FROM_TYPE_AND_OFFSET(entries[0].swap_type, entries[0].swap_offset),
+      1234u);
+  ASSERT_EQ(entries[0].pte_soft_dirty, false);
+  ASSERT_EQ(entries[0].page_present, false);
+  ASSERT_EQ(entries[0].page_swapped, true);
+  ASSERT_EQ(entries[0].page_exclusively_mapped, false);
+  ASSERT_EQ(entries[0].page_file_or_shared_anon, false);
+
+  ASSERT_EQ(
+      PFN_FROM_TYPE_AND_OFFSET(entries[1].swap_type, entries[1].swap_offset),
+      5551212u);
+  ASSERT_EQ(entries[1].pte_soft_dirty, true);
+  ASSERT_EQ(entries[1].page_present, false);
+  ASSERT_EQ(entries[1].page_swapped, false);
+  ASSERT_EQ(entries[1].page_exclusively_mapped, false);
+  ASSERT_EQ(entries[1].page_file_or_shared_anon, true);
+}
+
+TEST_F(PagemapTest, VectorResizedWhenIncorrectlySized) {
+  // This test validates that passing in an incorrectly sized vector is handled
+  // automatically.
+  void* start_address;
+  void* end_address;
+  CreateStorageForPages(4, &start_address, &end_address);
+
+  uint64_t page_map_entries[] = {PFN(8675309) | SOFT_DIRTY | PRESENT,
+                                 PFN(1234) | SWAPPED,
+                                 PFN(5551212) | SOFT_DIRTY | FILE_PAGE,
+                                 PFN(0xF00) | PRESENT | EXCLUSIVELY_MAPPED};
+  PutEntries(start_address, page_map_entries, countof(page_map_entries));
+
+  // We will read the two middle pages.
+  std::vector<Pagemap::PagemapEntry> entries;
+  entries.resize(1);  // This is too short, it will be automatically resized.
+
+  ASSERT_TRUE(pagemap_.GetEntries(
+      reinterpret_cast<uint64_t>(start_address) + base::GetPageSize(),
+      2 * base::GetPageSize(), &entries));
+  ASSERT_EQ(entries.size(), 2u);
+
+  ASSERT_EQ(
+      PFN_FROM_TYPE_AND_OFFSET(entries[0].swap_type, entries[0].swap_offset),
+      1234u);
+  ASSERT_EQ(entries[0].pte_soft_dirty, false);
+  ASSERT_EQ(entries[0].page_present, false);
+  ASSERT_EQ(entries[0].page_swapped, true);
+  ASSERT_EQ(entries[0].page_exclusively_mapped, false);
+  ASSERT_EQ(entries[0].page_file_or_shared_anon, false);
+
+  ASSERT_EQ(
+      PFN_FROM_TYPE_AND_OFFSET(entries[1].swap_type, entries[1].swap_offset),
+      5551212u);
+  ASSERT_EQ(entries[1].pte_soft_dirty, true);
+  ASSERT_EQ(entries[1].page_present, false);
+  ASSERT_EQ(entries[1].page_swapped, false);
+  ASSERT_EQ(entries[1].page_exclusively_mapped, false);
+  ASSERT_EQ(entries[1].page_file_or_shared_anon, true);
+}
+
+}  // namespace memory
+}  // namespace chromeos
diff --git a/chromeos/printing/cups_printer_status.cc b/chromeos/printing/cups_printer_status.cc
new file mode 100644
index 0000000..d58493c
--- /dev/null
+++ b/chromeos/printing/cups_printer_status.cc
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/printing/cups_printer_status.h"
+
+#include <stddef.h>
+
+namespace chromeos {
+
+using CupsPrinterStatusReason = CupsPrinterStatus::CupsPrinterStatusReason;
+
+CupsPrinterStatusReason::CupsPrinterStatusReason(const Reason& reason,
+                                                 const Severity& severity)
+    : reason_(reason), severity_(severity) {}
+
+CupsPrinterStatusReason::~CupsPrinterStatusReason() = default;
+
+const CupsPrinterStatusReason::Reason& CupsPrinterStatusReason::GetReason()
+    const {
+  return reason_;
+}
+
+const CupsPrinterStatusReason::Severity& CupsPrinterStatusReason::GetSeverity()
+    const {
+  return severity_;
+}
+
+CupsPrinterStatus::CupsPrinterStatus(const std::string& printer_id)
+    : printer_id_(printer_id), timestamp_(base::Time::Now()) {}
+CupsPrinterStatus::CupsPrinterStatus() = default;
+CupsPrinterStatus::CupsPrinterStatus(const CupsPrinterStatus& other) = default;
+CupsPrinterStatus& CupsPrinterStatus::operator=(
+    const CupsPrinterStatus& other) = default;
+
+CupsPrinterStatus::~CupsPrinterStatus() = default;
+
+const std::string& CupsPrinterStatus::GetPrinterId() const {
+  return printer_id_;
+}
+
+const base::flat_set<CupsPrinterStatusReason>&
+CupsPrinterStatus::GetStatusReasons() const {
+  return status_reasons_;
+}
+
+const base::Time& CupsPrinterStatus::GetTimestamp() const {
+  return timestamp_;
+}
+
+void CupsPrinterStatus::AddStatusReason(
+    const CupsPrinterStatusReason::Reason& reason,
+    const CupsPrinterStatusReason::Severity& severity) {
+  status_reasons_.emplace(CupsPrinterStatusReason(reason, severity));
+}
+
+}  // namespace chromeos
diff --git a/chromeos/printing/cups_printer_status.h b/chromeos/printing/cups_printer_status.h
new file mode 100644
index 0000000..cc3ad28
--- /dev/null
+++ b/chromeos/printing/cups_printer_status.h
@@ -0,0 +1,105 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_PRINTING_CUPS_PRINTER_STATUS_H_
+#define CHROMEOS_PRINTING_CUPS_PRINTER_STATUS_H_
+
+#include <string>
+
+#include "base/containers/flat_set.h"
+#include "base/time/time.h"
+#include "chromeos/chromeos_export.h"
+
+namespace chromeos {
+
+// A container for the results of a printer status query. A printer status query
+// can return multiple error reasons so CupsPrinterStatus contains multiple
+// CupsPrinterStatusReasons. |timestamp| is set at the time of CupsPrinterStatus
+// creation.
+class CHROMEOS_EXPORT CupsPrinterStatus {
+ public:
+  // A combination of a reason, which describes the state of a printer, and a
+  // severity, which is the level of seriousness of that state.
+  class CHROMEOS_EXPORT CupsPrinterStatusReason {
+   public:
+    enum class Reason {
+      kConnectingToDevice = 0,
+      kDeviceError,
+      kDoorOpen,
+      kLowOnInk,
+      kLowOnPaper,
+      kNoError,
+      kOutOfInk,
+      kOutOfPaper,
+      kOutputAreaAlmostFull,
+      kOutputFull,
+      kPaperJam,
+      kPaused,
+      kPrinterQueueFull,
+      kPrinterUnreachable,
+      kStopped,
+      kTrayMissing,
+      kUnknownReason,
+    };
+
+    enum class Severity {
+      kUnknownSeverity = 0,
+      kReport,
+      kWarning,
+      kError,
+    };
+
+    CupsPrinterStatusReason(const Reason& reason, const Severity& severity);
+    ~CupsPrinterStatusReason();
+
+    const Reason& GetReason() const;
+    const Severity& GetSeverity() const;
+
+    bool operator==(const CupsPrinterStatusReason& other) const {
+      return reason_ == other.reason_ && severity_ == other.severity_;
+    }
+
+    // Comparison operator to support storing CupsPrinterStatusReason in a
+    // flat_set. Two CupsPrinterStatusReasons are considered matching iff
+    // |reason| and |severity| are the same.
+    bool operator<(const CupsPrinterStatusReason& other) const {
+      return reason_ < other.reason_ ||
+             (reason_ == other.reason_ && severity_ < other.severity_);
+    }
+
+   private:
+    Reason reason_;
+    Severity severity_;
+  };
+
+  // Creates a CupsPrinterStatus from an existing printing::PrinterStatus.
+  explicit CupsPrinterStatus(const std::string& printer_id);
+
+  CupsPrinterStatus();
+  CupsPrinterStatus(const CupsPrinterStatus& other);
+  CupsPrinterStatus& operator=(const CupsPrinterStatus& other);
+
+  ~CupsPrinterStatus();
+
+  const std::string& GetPrinterId() const;
+
+  // Returns set of status reasons. Each reason describing status of the
+  // printer.
+  const base::flat_set<CupsPrinterStatusReason>& GetStatusReasons() const;
+
+  const base::Time& GetTimestamp() const;
+
+  // Adds a new CupsPrinterStatusReason to an existing CupsPrinterStatus.
+  void AddStatusReason(const CupsPrinterStatusReason::Reason& reason,
+                       const CupsPrinterStatusReason::Severity& severity);
+
+ private:
+  std::string printer_id_;
+  base::flat_set<CupsPrinterStatusReason> status_reasons_;
+  base::Time timestamp_;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_PRINTING_CUPS_PRINTER_STATUS_H_
diff --git a/chromeos/printing/cups_printer_status_unittest.cc b/chromeos/printing/cups_printer_status_unittest.cc
new file mode 100644
index 0000000..f9bb9068
--- /dev/null
+++ b/chromeos/printing/cups_printer_status_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/printing/cups_printer_status.h"
+
+#include <string>
+#include <vector>
+
+#include "base/test/scoped_mock_clock_override.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+using CupsPrinterStatusReason = CupsPrinterStatus::CupsPrinterStatusReason;
+using CupsReason = CupsPrinterStatus::CupsPrinterStatusReason::Reason;
+using CupsSeverity = CupsPrinterStatus::CupsPrinterStatusReason::Severity;
+
+class CupsPrinterStatusTest : public testing::Test {
+ public:
+  CupsPrinterStatusTest() = default;
+  ~CupsPrinterStatusTest() override = default;
+
+ protected:
+  base::ScopedMockClockOverride clock_;
+};
+
+// Baseline test for creating a chromeos::CupsPrinterStatus.
+TEST_F(CupsPrinterStatusTest, CreateCupsPrinterStatus) {
+  CupsPrinterStatus cups_printer_status("id");
+  EXPECT_EQ("id", cups_printer_status.GetPrinterId());
+  EXPECT_EQ(clock_.Now(), cups_printer_status.GetTimestamp());
+}
+
+TEST_F(CupsPrinterStatusTest, AddStatusReasons) {
+  CupsPrinterStatus cups_printer_status("id");
+  cups_printer_status.AddStatusReason(
+      CupsPrinterStatusReason::Reason::kNoError,
+      CupsPrinterStatusReason::Severity::kReport);
+  cups_printer_status.AddStatusReason(
+      CupsPrinterStatusReason::Reason::kDoorOpen,
+      CupsPrinterStatusReason::Severity::kWarning);
+
+  EXPECT_EQ(2u, cups_printer_status.GetStatusReasons().size());
+  EXPECT_EQ("id", cups_printer_status.GetPrinterId());
+  EXPECT_EQ(clock_.Now(), cups_printer_status.GetTimestamp());
+
+  std::vector<CupsPrinterStatus::CupsPrinterStatusReason> expected_reasons{
+      CupsPrinterStatus::CupsPrinterStatusReason(CupsReason::kNoError,
+                                                 CupsSeverity::kReport),
+      CupsPrinterStatus::CupsPrinterStatusReason(CupsReason::kDoorOpen,
+                                                 CupsSeverity::kWarning)};
+  EXPECT_THAT(cups_printer_status.GetStatusReasons(), expected_reasons);
+}
+
+// Ensure that if printer returns two of the same status but each with different
+// severities, make sure both are saved.
+TEST_F(CupsPrinterStatusTest, SameReasonDifferentSeverity) {
+  CupsPrinterStatus cups_printer_status("id");
+  cups_printer_status.AddStatusReason(
+      CupsPrinterStatusReason::Reason::kDeviceError,
+      CupsPrinterStatusReason::Severity::kReport);
+  cups_printer_status.AddStatusReason(
+      CupsPrinterStatusReason::Reason::kDeviceError,
+      CupsPrinterStatusReason::Severity::kWarning);
+
+  EXPECT_EQ(2u, cups_printer_status.GetStatusReasons().size());
+  EXPECT_EQ("id", cups_printer_status.GetPrinterId());
+  EXPECT_EQ(clock_.Now(), cups_printer_status.GetTimestamp());
+
+  std::vector<CupsPrinterStatus::CupsPrinterStatusReason> expected_reasons{
+      CupsPrinterStatus::CupsPrinterStatusReason(CupsReason::kDeviceError,
+                                                 CupsSeverity::kReport),
+      CupsPrinterStatus::CupsPrinterStatusReason(CupsReason::kDeviceError,
+                                                 CupsSeverity::kWarning)};
+  EXPECT_THAT(cups_printer_status.GetStatusReasons(), expected_reasons);
+}
+
+// Ensure if printer returns the same status and severity twice, duplicates are
+// not added to CupsPrinterStatus.
+TEST_F(CupsPrinterStatusTest, SameReasonSameSeverity) {
+  CupsPrinterStatus cups_printer_status("id");
+  cups_printer_status.AddStatusReason(
+      CupsPrinterStatusReason::Reason::kPaused,
+      CupsPrinterStatusReason::Severity::kError);
+  cups_printer_status.AddStatusReason(
+      CupsPrinterStatusReason::Reason::kPaused,
+      CupsPrinterStatusReason::Severity::kError);
+
+  EXPECT_EQ(1u, cups_printer_status.GetStatusReasons().size());
+  EXPECT_EQ("id", cups_printer_status.GetPrinterId());
+  EXPECT_EQ(clock_.Now(), cups_printer_status.GetTimestamp());
+
+  std::vector<CupsPrinterStatus::CupsPrinterStatusReason> expected_reasons{
+      CupsPrinterStatus::CupsPrinterStatusReason(CupsReason::kPaused,
+                                                 CupsSeverity::kError)};
+  EXPECT_THAT(cups_printer_status.GetStatusReasons(), expected_reasons);
+}
+
+}  // namespace chromeos
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc
index aed165c..09f2d62 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.cc
+++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -322,6 +322,9 @@
             assistant_client::AlarmTimerManager::EventActionType ignore) {
           listener.Run();
         });
+
+    // Force sync initial alarm/timer state.
+    OnAlarmTimerStateChanged();
   }
 }
 
diff --git a/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc b/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc
index c18bb934..640aaa72 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc
+++ b/chromeos/services/assistant/assistant_manager_service_impl_unittest.cc
@@ -709,13 +709,18 @@
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(features::kAssistantTimersV2);
 
+  StrictMock<AssistantAlarmTimerControllerMock> alarm_timer_controller;
+  fake_service_context()->set_assistant_alarm_timer_controller(
+      &alarm_timer_controller);
+
+  // We expect OnTimerStateChanged() to be invoked when starting LibAssistant.
+  EXPECT_CALL(alarm_timer_controller, OnTimerStateChanged).Times(1);
+
   Start();
   WaitUntilStartIsFinished();
   assistant_manager_service()->OnStartFinished();
 
-  StrictMock<AssistantAlarmTimerControllerMock> alarm_timer_controller;
-  fake_service_context()->set_assistant_alarm_timer_controller(
-      &alarm_timer_controller);
+  testing::Mock::VerifyAndClearExpectations(&alarm_timer_controller);
 
   std::vector<ash::mojom::AssistantTimerPtr> timers;
   EXPECT_CALL(alarm_timer_controller, OnTimerStateChanged)
@@ -742,5 +747,36 @@
   EXPECT_EQ(ash::mojom::AssistantTimerState::kFired, timers[2]->state);
 }
 
+TEST_F(AssistantManagerServiceImplTest,
+       ShouldNotifyAlarmTimerControllerOfTimersWhenStartingLibAssistantInV2) {
+  // Enable timers V2.
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(features::kAssistantTimersV2);
+
+  // Pre-populate the AlarmTimerManager with a single scheduled timer.
+  std::vector<assistant_client::AlarmTimerEvent> events;
+  AddTimerEvent(events, assistant_client::Timer::State::SCHEDULED);
+  fake_alarm_timer_manager()->SetAllEvents(std::move(events));
+
+  // Bind AssistantAlarmTimerController.
+  StrictMock<AssistantAlarmTimerControllerMock> alarm_timer_controller;
+  fake_service_context()->set_assistant_alarm_timer_controller(
+      &alarm_timer_controller);
+
+  // Expect (and capture) |timers| to be sent to AssistantAlarmTimerController.
+  std::vector<ash::mojom::AssistantTimerPtr> timers;
+  EXPECT_CALL(alarm_timer_controller, OnTimerStateChanged)
+      .WillOnce(CloneArg<0>(&timers));
+
+  // Start LibAssistant.
+  Start();
+  WaitUntilStartIsFinished();
+  assistant_manager_service()->OnStartFinished();
+
+  // Verify AssistantAlarmTimerController is notified of the scheduled timer.
+  ASSERT_EQ(1u, timers.size());
+  EXPECT_EQ(ash::mojom::AssistantTimerState::kScheduled, timers[0]->state);
+}
+
 }  // namespace assistant
 }  // namespace chromeos
diff --git a/components/arc/mojom/intent_helper.mojom b/components/arc/mojom/intent_helper.mojom
index a826bc1..5f8308c 100644
--- a/components/arc/mojom/intent_helper.mojom
+++ b/components/arc/mojom/intent_helper.mojom
@@ -183,8 +183,9 @@
   OSPRIVACY,
   OSSEARCH,
   OSRESET,
+  OSLANGUAGESSMARTINPUTS,
 
-  LAST = OSRESET,
+  LAST = OSLANGUAGESSMARTINPUTS
 };
 
 // Describes an unique chrome app.
diff --git a/components/client_hints/DEPS b/components/client_hints/DEPS
new file mode 100644
index 0000000..e8b26c7
--- /dev/null
+++ b/components/client_hints/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+components/content_settings/core/common",
+  "+content/public/common",
+]
diff --git a/components/client_hints/OWNERS b/components/client_hints/OWNERS
new file mode 100644
index 0000000..9f8f91b
--- /dev/null
+++ b/components/client_hints/OWNERS
@@ -0,0 +1,5 @@
+yoavweiss@chromium.org
+tbansal@chromium.org
+ryansturm@chromium.org
+
+# COMPONENT: Blink>Loader
diff --git a/components/client_hints/browser/BUILD.gn b/components/client_hints/browser/BUILD.gn
new file mode 100644
index 0000000..710d6e7
--- /dev/null
+++ b/components/client_hints/browser/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("browser") {
+  sources = [
+    "client_hints.cc",
+    "client_hints.h",
+  ]
+  deps = [
+    "//base",
+    "//components/content_settings/core/common",
+    "//components/content_settings/core/browser",
+    "//components/keyed_service/core",
+    "//components/client_hints/common",
+    "//content/public/browser",
+    "//services/network/public/cpp",
+    "//third_party/blink/public/common:headers",
+  ]
+}
diff --git a/components/client_hints/browser/DEPS b/components/client_hints/browser/DEPS
new file mode 100644
index 0000000..c9affb9
--- /dev/null
+++ b/components/client_hints/browser/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "+components/content_settings/core/browser",
+  "+components/keyed_service",
+  "+content/public/browser",
+]
diff --git a/chrome/browser/client_hints/client_hints.cc b/components/client_hints/browser/client_hints.cc
similarity index 63%
rename from chrome/browser/client_hints/client_hints.cc
rename to components/client_hints/browser/client_hints.cc
index c02028a..fb8cd21 100644
--- a/chrome/browser/client_hints/client_hints.cc
+++ b/components/client_hints/browser/client_hints.cc
@@ -6,84 +6,85 @@
 #include <functional>
 #include <string>
 
-#include "chrome/browser/client_hints/client_hints.h"
+#include "components/client_hints/browser/client_hints.h"
 
 #include "base/metrics/histogram_macros.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_content_browser_client.h"
-#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/client_hints/client_hints.h"
+#include "components/client_hints/common/client_hints.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings_utils.h"
-#include "components/language/core/browser/pref_names.h"
-#include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/origin_util.h"
 
 namespace client_hints {
 
-ClientHints::ClientHints(content::BrowserContext* context)
-    : context_(context) {}
-
-ClientHints::ClientHints(content::WebContents* tab) {
-  receiver_ = std::make_unique<
-      content::WebContentsFrameReceiverSet<client_hints::mojom::ClientHints>>(
-      tab, this);
+ClientHints::ClientHints(
+    content::BrowserContext* context,
+    network::NetworkQualityTracker* network_quality_tracker,
+    HostContentSettingsMap* settings_map,
+    const blink::UserAgentMetadata& user_agent_metadata)
+    : context_(context),
+      network_quality_tracker_(network_quality_tracker),
+      settings_map_(settings_map),
+      user_agent_metadata_(user_agent_metadata) {
+  DCHECK(context_);
+  DCHECK(network_quality_tracker_);
+  DCHECK(settings_map_);
 }
 
-content::BrowserContext* ClientHints::GetContext() {
-  if (!context_) {
-    content::RenderProcessHost* rph =
-        receiver_->GetCurrentTargetFrame()->GetProcess();
-    DCHECK(rph);
-    context_ = rph->GetBrowserContext();
+// static
+void ClientHints::CreateForWebContents(
+    content::WebContents* web_contents,
+    network::NetworkQualityTracker* network_quality_tracker,
+    HostContentSettingsMap* settings_map,
+    const blink::UserAgentMetadata& user_agent_metadata) {
+  DCHECK(web_contents);
+  if (!FromWebContents(web_contents)) {
+    web_contents->SetUserData(
+        UserDataKey(),
+        base::WrapUnique(new ClientHints(web_contents, network_quality_tracker,
+                                         settings_map, user_agent_metadata)));
   }
-  return context_;
 }
 
 ClientHints::~ClientHints() = default;
 
 network::NetworkQualityTracker* ClientHints::GetNetworkQualityTracker() {
-  DCHECK(g_browser_process);
-  return g_browser_process->network_quality_tracker();
+  return network_quality_tracker_;
 }
 
 void ClientHints::GetAllowedClientHintsFromSource(
     const GURL& url,
     blink::WebEnabledClientHints* client_hints) {
   ContentSettingsForOneType client_hints_rules;
-  Profile* profile = Profile::FromBrowserContext(GetContext());
-  if (!profile)
-    return;
-
-  HostContentSettingsMapFactory::GetForProfile(profile)->GetSettingsForOneType(
-      ContentSettingsType::CLIENT_HINTS, std::string(), &client_hints_rules);
+  settings_map_->GetSettingsForOneType(ContentSettingsType::CLIENT_HINTS,
+                                       std::string(), &client_hints_rules);
   client_hints::GetAllowedClientHintsFromSource(url, client_hints_rules,
                                                 client_hints);
 }
 
 bool ClientHints::IsJavaScriptAllowed(const GURL& url) {
-  Profile* profile = Profile::FromBrowserContext(GetContext());
-  if (!profile)
-    return false;
-
-  return HostContentSettingsMapFactory::GetForProfile(profile)
-             ->GetContentSetting(url, url, ContentSettingsType::JAVASCRIPT,
-                                 std::string()) == CONTENT_SETTING_ALLOW;
-}
-
-std::string ClientHints::GetAcceptLanguageString() {
-  Profile* profile = Profile::FromBrowserContext(GetContext());
-  if (!profile)
-    return std::string();
-  DCHECK(profile->GetPrefs());
-  return profile->GetPrefs()->GetString(language::prefs::kAcceptLanguages);
+  return settings_map_->GetContentSetting(
+             url, url, ContentSettingsType::JAVASCRIPT, std::string()) ==
+         CONTENT_SETTING_ALLOW;
 }
 
 blink::UserAgentMetadata ClientHints::GetUserAgentMetadata() {
-  return ::GetUserAgentMetadata();
+  return user_agent_metadata_;
+}
+
+ClientHints::ClientHints(
+    content::WebContents* web_contents,
+    network::NetworkQualityTracker* network_quality_tracker,
+    HostContentSettingsMap* settings_map,
+    const blink::UserAgentMetadata& user_agent_metadata)
+    : ClientHints(web_contents->GetBrowserContext(),
+                  network_quality_tracker,
+                  settings_map,
+                  user_agent_metadata) {
+  receiver_ = std::make_unique<
+      content::WebContentsFrameReceiverSet<client_hints::mojom::ClientHints>>(
+      web_contents, this);
 }
 
 void ClientHints::PersistClientHints(
@@ -117,11 +118,6 @@
   if (expiration_duration <= base::TimeDelta::FromSeconds(0))
     return;
 
-  Profile* profile = Profile::FromBrowserContext(GetContext());
-
-  HostContentSettingsMap* map =
-      HostContentSettingsMapFactory::GetForProfile(profile);
-
   std::unique_ptr<base::ListValue> expiration_times_list =
       std::make_unique<base::ListValue>();
   expiration_times_list->Reserve(client_hints.size());
@@ -141,7 +137,7 @@
 
   // TODO(tbansal): crbug.com/735518. Disable updates to client hints settings
   // when cookies are disabled for |primary_origin|.
-  map->SetWebsiteSettingDefaultScope(
+  settings_map_->SetWebsiteSettingDefaultScope(
       primary_url, GURL(), ContentSettingsType::CLIENT_HINTS, std::string(),
       std::move(expiration_times_dictionary));
 
diff --git a/chrome/browser/client_hints/client_hints.h b/components/client_hints/browser/client_hints.h
similarity index 60%
rename from chrome/browser/client_hints/client_hints.h
rename to components/client_hints/browser/client_hints.h
index bb349dd8b..4d9d004 100644
--- a/chrome/browser/client_hints/client_hints.h
+++ b/components/client_hints/browser/client_hints.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CLIENT_HINTS_CLIENT_HINTS_H_
-#define CHROME_BROWSER_CLIENT_HINTS_CLIENT_HINTS_H_
+#ifndef COMPONENTS_CLIENT_HINTS_BROWSER_CLIENT_HINTS_H_
+#define COMPONENTS_CLIENT_HINTS_BROWSER_CLIENT_HINTS_H_
 
 #include <memory>
 #include <string>
@@ -16,6 +16,7 @@
 #include "content/public/browser/web_contents_user_data.h"
 
 class GURL;
+class HostContentSettingsMap;
 
 namespace client_hints {
 
@@ -23,10 +24,18 @@
                     public content::ClientHintsControllerDelegate,
                     public content::WebContentsUserData<ClientHints> {
  public:
-  explicit ClientHints(content::BrowserContext* context);
-  explicit ClientHints(content::WebContents* tab);
+  ClientHints(content::BrowserContext* context,
+              network::NetworkQualityTracker* network_quality_tracker,
+              HostContentSettingsMap* settings_map,
+              const blink::UserAgentMetadata& user_agent_metadata);
   ~ClientHints() override;
 
+  static void CreateForWebContents(
+      content::WebContents* web_contents,
+      network::NetworkQualityTracker* network_quality_tracker,
+      HostContentSettingsMap* settings_map,
+      const blink::UserAgentMetadata& user_agent_metadata);
+
   // content::ClientHintsControllerDelegate:
   network::NetworkQualityTracker* GetNetworkQualityTracker() override;
 
@@ -36,8 +45,6 @@
 
   bool IsJavaScriptAllowed(const GURL& url) override;
 
-  std::string GetAcceptLanguageString() override;
-
   blink::UserAgentMetadata GetUserAgentMetadata() override;
 
   void PersistClientHints(
@@ -46,10 +53,17 @@
       base::TimeDelta expiration_duration) override;
 
  private:
-  content::BrowserContext* GetContext();
-
   friend class content::WebContentsUserData<ClientHints>;
+
+  ClientHints(content::WebContents* web_contents,
+              network::NetworkQualityTracker* network_quality_tracker,
+              HostContentSettingsMap* settings_map,
+              const blink::UserAgentMetadata& user_agent_metadata);
+
   content::BrowserContext* context_ = nullptr;
+  network::NetworkQualityTracker* network_quality_tracker_ = nullptr;
+  HostContentSettingsMap* settings_map_ = nullptr;
+  blink::UserAgentMetadata user_agent_metadata_;
   std::unique_ptr<
       content::WebContentsFrameReceiverSet<client_hints::mojom::ClientHints>>
       receiver_;
@@ -61,4 +75,4 @@
 
 }  // namespace client_hints
 
-#endif  // CHROME_BROWSER_CLIENT_HINTS_CLIENT_HINTS_H_
+#endif  // COMPONENTS_CLIENT_HINTS_BROWSER_CLIENT_HINTS_H_
diff --git a/components/client_hints/common/BUILD.gn b/components/client_hints/common/BUILD.gn
new file mode 100644
index 0000000..99236f41
--- /dev/null
+++ b/components/client_hints/common/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("common") {
+  sources = [
+    "client_hints.cc",
+    "client_hints.h",
+  ]
+  deps = [
+    "//components/content_settings/core/common",
+    "//content/public/common",
+    "//third_party/blink/public:blink_headers",
+    "//url",
+  ]
+}
diff --git a/components/client_hints/common/DEPS b/components/client_hints/common/DEPS
new file mode 100644
index 0000000..dc180c4a
--- /dev/null
+++ b/components/client_hints/common/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/blink/public/platform",
+]
diff --git a/chrome/common/client_hints/client_hints.cc b/components/client_hints/common/client_hints.cc
similarity index 96%
rename from chrome/common/client_hints/client_hints.cc
rename to components/client_hints/common/client_hints.cc
index ea7717fb..202ca45d 100644
--- a/chrome/common/client_hints/client_hints.cc
+++ b/components/client_hints/common/client_hints.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/common/client_hints/client_hints.h"
+#include "components/client_hints/common/client_hints.h"
 
 #include "content/public/common/origin_util.h"
 #include "third_party/blink/public/platform/web_client_hints_type.h"
diff --git a/chrome/common/client_hints/client_hints.h b/components/client_hints/common/client_hints.h
similarity index 81%
rename from chrome/common/client_hints/client_hints.h
rename to components/client_hints/common/client_hints.h
index a904642..4a02df3 100644
--- a/chrome/common/client_hints/client_hints.h
+++ b/components/client_hints/common/client_hints.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_COMMON_CLIENT_HINTS_CLIENT_HINTS_H_
-#define CHROME_COMMON_CLIENT_HINTS_CLIENT_HINTS_H_
+#ifndef COMPONENTS_CLIENT_HINTS_COMMON_CLIENT_HINTS_H_
+#define COMPONENTS_CLIENT_HINTS_COMMON_CLIENT_HINTS_H_
 
 #include "components/content_settings/core/common/content_settings.h"
 
@@ -25,4 +25,4 @@
 
 }  // namespace client_hints
 
-#endif  // CHROME_COMMON_CLIENT_HINTS_CLIENT_HINTS_H_
+#endif  // COMPONENTS_CLIENT_HINTS_COMMON_CLIENT_HINTS_H_
diff --git a/components/dom_distiller/core/css/distilledpage.css b/components/dom_distiller/core/css/distilledpage.css
index 4870bff..d5c5932 100644
--- a/components/dom_distiller/core/css/distilledpage.css
+++ b/components/dom_distiller/core/css/distilledpage.css
@@ -10,8 +10,13 @@
  * *::after and *::before used to select pseudo-elements not selectable by *. */
 
 :root {
+  --google-blue-300: 138, 180, 248;
+  --google-blue-600: 26, 115, 232;
   --google-blue-700: 25, 103, 210;
   --google-brown-900: 62, 39, 35;
+  --google-grey-50: 248, 249, 250;
+  --google-grey-900: 32, 33, 36;
+  --google-purple-300: 197, 138, 249;
   --google-purple-700: 132, 48, 206;
   --google-yellow-50: 254, 247, 224;
   --google-yellow-100: 254, 239, 195;
@@ -111,13 +116,13 @@
  * and with CSS class constants in viewer.cc */
 
 .light {
-  background-color: #FAFAFA;
-  color: #424242;
+  background-color: #FFF;
+  color: rgb(var(--google-grey-900));
 }
 
 .dark {
-  background-color: #212121;
-  color: #E0E0E0;
+  background-color: rgb(var(--google-grey-900));
+  color: #FFF;
 }
 
 .sepia {
@@ -126,7 +131,7 @@
 }
 
 .light a:link {
-  color: rgb(85, 85, 255);
+  color: rgb(var(--google-blue-600));
 }
 
 .sepia a:link {
@@ -134,11 +139,11 @@
 }
 
 .dark a:link {
-  color: rgb(136, 136, 255);
+  color: rgb(var(--google-blue-300));
 }
 
 .light a:visited {
-  color: rgb(144, 34, 144);
+  color: rgb(var(--google-purple-700));
 }
 
 .sepia a:visited {
@@ -146,13 +151,13 @@
 }
 
 .dark a:visited {
-  color: rgb(216, 114, 216);
+  color: rgb(var(--google-purple-300));
 }
 
 .light code,
 .light pre {
-  background-color: #EEE;
-  border-color: #AAA;
+  background-color: rgb(var(--google-grey-50));
+  border-color: rgb(var(--google-grey-900));
 }
 
 .sepia code,
@@ -163,8 +168,8 @@
 
 .dark code,
 .dark pre {
-  background-color: #333;
-  border-color: #555;
+  background-color: #000;
+  border-color: rgba(255, 255, 255, 0.5);
 }
 
 .light tbody tr:nth-child(odd) {
diff --git a/components/dom_distiller/core/css/distilledpage_desktop.css b/components/dom_distiller/core/css/distilledpage_desktop.css
index 06a6f2e4..87a8588 100644
--- a/components/dom_distiller/core/css/distilledpage_desktop.css
+++ b/components/dom_distiller/core/css/distilledpage_desktop.css
@@ -5,7 +5,6 @@
 /* This file should contain style used on desktop but not Android or iOS. */
 
 :root {
-  --google-blue-600: 26, 115, 232;
   --google-grey-700: 95, 99, 104;
   --google-grey-800: 60, 64, 67;
 }
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 22ec4ffc..e6d53cc 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -34,6 +34,7 @@
     "blank.icon",
     "bookmark.icon",
     "calculator.icon",
+    "chevron.icon",
     "clear.icon",
     "clock.icon",
     "drive_docs.icon",
diff --git a/components/omnibox/browser/vector_icons/chevron.icon b/components/omnibox/browser/vector_icons/chevron.icon
new file mode 100644
index 0000000..415e7c0ca
--- /dev/null
+++ b/components/omnibox/browser/vector_icons/chevron.icon
@@ -0,0 +1,19 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 12.88f, 16.12f,
+CUBIC_TO, 12.66f, 16.36f, 12.35f, 16.5f, 12, 16.5f,
+CUBIC_TO, 11.66f, 16.5f, 11.34f, 16.36f, 11.12f, 16.12f,
+LINE_TO, 4.87f, 9.69f,
+CUBIC_TO, 4.64f, 9.46f, 4.5f, 9.14f, 4.5f, 8.79f,
+CUBIC_TO, 4.5f, 8.08f, 5.06f, 7.5f, 5.75f, 7.5f,
+CUBIC_TO, 6.1f, 7.5f, 6.41f, 7.64f, 6.63f, 7.88f,
+LINE_TO, 12, 13.4f,
+LINE_TO, 17.37f, 7.88f,
+CUBIC_TO, 17.59f, 7.64f, 17.91f, 7.5f, 18.25f, 7.5f,
+CUBIC_TO, 18.94f, 7.5f, 19.5f, 8.08f, 19.5f, 8.79f,
+CUBIC_TO, 19.5f, 9.14f, 19.36f, 9.46f, 19.13f, 9.69f,
+LINE_TO, 12.88f, 16.12f,
+CLOSE
diff --git a/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java b/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java
index 5b26861..57ef7fc9 100644
--- a/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java
+++ b/components/payments/content/android/java/src/org/chromium/components/payments/intent/WebPaymentIntentHelper.java
@@ -120,59 +120,102 @@
             PaymentSuccessCallback successCallback) {
         if (data == null) {
             errorCallback.onPaymentError(ErrorStrings.MISSING_INTENT_DATA);
-        } else if (data.getExtras() == null) {
+            return;
+        }
+        if (data.getExtras() == null) {
             errorCallback.onPaymentError(ErrorStrings.MISSING_INTENT_EXTRAS);
-        } else if (resultCode == Activity.RESULT_CANCELED) {
+            return;
+        }
+        if (resultCode == Activity.RESULT_CANCELED) {
             errorCallback.onPaymentError(ErrorStrings.RESULT_CANCELED);
-        } else if (resultCode != Activity.RESULT_OK) {
+            return;
+        }
+        if (resultCode != Activity.RESULT_OK) {
             errorCallback.onPaymentError(String.format(
                     Locale.US, ErrorStrings.UNRECOGNIZED_ACTIVITY_RESULT, resultCode));
-        } else {
-            // TODO(https://crbug.com/1026667): Validate presence of required fields and call
-            // errorCallback to make error handling consistent with Desktop.
-            String details = data.getExtras().getString(EXTRA_RESPONSE_DETAILS);
-            if (details == null) {
-                details = data.getExtras().getString(EXTRA_DEPRECATED_RESPONSE_INSTRUMENT_DETAILS);
-            }
-            if (details == null) details = EMPTY_JSON_DATA;
-            String methodName = data.getExtras().getString(EXTRA_RESPONSE_METHOD_NAME);
-            if (methodName == null) methodName = "";
-
-            PayerData payerData;
-            if (requestedPaymentOptions != null) {
-                // Create payer data based on requested payment options.
-                Address shippingAddress = !requestedPaymentOptions.requestShipping
-                        ? new Address()
-                        : new Address(getStringOrEmpty(data, EXTRA_ADDRESS_COUNTRY),
-                                data.getExtras().getStringArray(EXTRA_ADDRESS_LINES),
-                                getStringOrEmpty(data, EXTRA_ADDRESS_REGION),
-                                getStringOrEmpty(data, EXTRA_ADDRESS_CITY),
-                                getStringOrEmpty(data, EXTRA_ADDRESS_DEPENDENT_LOCALITY),
-                                getStringOrEmpty(data, EXTRA_ADDRESS_POSTAL_CODE),
-                                getStringOrEmpty(data, EXTRA_ADDRESS_SORTING_CODE),
-                                getStringOrEmpty(data, EXTRA_ADDRESS_ORGANIZATION),
-                                getStringOrEmpty(data, EXTRA_ADDRESS_RECIPIENT),
-                                getStringOrEmpty(data, EXTRA_ADDRESS_PHONE));
-                payerData = new PayerData(requestedPaymentOptions.requestPayerName
-                                ? data.getExtras().getString(EXTRA_RESPONSE_PAYER_NAME)
-                                : "",
-                        requestedPaymentOptions.requestPayerPhone
-                                ? data.getExtras().getString(EXTRA_RESPONSE_PAYER_PHONE)
-                                : "",
-                        requestedPaymentOptions.requestPayerEmail
-                                ? data.getExtras().getString(EXTRA_RESPONSE_PAYER_EMAIL)
-                                : "",
-                        shippingAddress,
-                        requestedPaymentOptions.requestShipping
-                                ? data.getExtras().getString(EXTRA_SHIPPING_OPTION_ID)
-                                : "");
-            } else {
-                payerData = new PayerData();
-            }
-
-            successCallback.onPaymentSuccess(
-                    /*methodName=*/methodName, /*details=*/details, payerData);
+            return;
         }
+
+        String details = data.getExtras().getString(EXTRA_RESPONSE_DETAILS);
+        if (details == null) {
+            // try to get deprecated details rather than early returning.
+            details = data.getExtras().getString(EXTRA_DEPRECATED_RESPONSE_INSTRUMENT_DETAILS);
+        }
+        if (TextUtils.isEmpty(details)) {
+            errorCallback.onPaymentError(ErrorStrings.MISSING_DETAILS_FROM_PAYMENT_APP);
+            return;
+        }
+
+        String methodName = data.getExtras().getString(EXTRA_RESPONSE_METHOD_NAME);
+        if (TextUtils.isEmpty(methodName)) {
+            errorCallback.onPaymentError(ErrorStrings.MISSING_METHOD_NAME_FROM_PAYMENT_APP);
+            return;
+        }
+
+        if (requestedPaymentOptions == null) {
+            successCallback.onPaymentSuccess(
+                    /*methodName=*/methodName, /*details=*/details, new PayerData());
+            return;
+        }
+
+        Address shippingAddress;
+        if (requestedPaymentOptions.requestShipping) {
+            Bundle addressBundle = data.getExtras().getBundle(EXTRA_SHIPPING_ADDRESS);
+            if (addressBundle == null || addressBundle.isEmpty()) {
+                errorCallback.onPaymentError(ErrorStrings.SHIPPING_ADDRESS_INVALID);
+                return;
+            }
+            shippingAddress = new Address(getStringOrEmpty(addressBundle, EXTRA_ADDRESS_COUNTRY),
+                    addressBundle.getStringArray(EXTRA_ADDRESS_LINES),
+                    getStringOrEmpty(addressBundle, EXTRA_ADDRESS_REGION),
+                    getStringOrEmpty(addressBundle, EXTRA_ADDRESS_CITY),
+                    getStringOrEmpty(addressBundle, EXTRA_ADDRESS_DEPENDENT_LOCALITY),
+                    getStringOrEmpty(addressBundle, EXTRA_ADDRESS_POSTAL_CODE),
+                    getStringOrEmpty(addressBundle, EXTRA_ADDRESS_SORTING_CODE),
+                    getStringOrEmpty(addressBundle, EXTRA_ADDRESS_ORGANIZATION),
+                    getStringOrEmpty(addressBundle, EXTRA_ADDRESS_RECIPIENT),
+                    getStringOrEmpty(addressBundle, EXTRA_ADDRESS_PHONE));
+        } else { // !requestedPaymentOptions.requestShipping
+            shippingAddress = new Address();
+        }
+
+        String payerName = requestedPaymentOptions.requestPayerName
+                ? getStringOrEmpty(data, EXTRA_RESPONSE_PAYER_NAME)
+                : "";
+        if (requestedPaymentOptions.requestPayerName && TextUtils.isEmpty(payerName)) {
+            errorCallback.onPaymentError(ErrorStrings.PAYER_NAME_EMPTY);
+            return;
+        }
+
+        String payerPhone = requestedPaymentOptions.requestPayerPhone
+                ? getStringOrEmpty(data, EXTRA_RESPONSE_PAYER_PHONE)
+                : "";
+        if (requestedPaymentOptions.requestPayerPhone && TextUtils.isEmpty(payerPhone)) {
+            errorCallback.onPaymentError(ErrorStrings.PAYER_PHONE_EMPTY);
+            return;
+        }
+
+        String payerEmail = requestedPaymentOptions.requestPayerEmail
+                ? getStringOrEmpty(data, EXTRA_RESPONSE_PAYER_EMAIL)
+                : "";
+        if (requestedPaymentOptions.requestPayerEmail && TextUtils.isEmpty(payerEmail)) {
+            errorCallback.onPaymentError(ErrorStrings.PAYER_EMAIL_EMPTY);
+            return;
+        }
+
+        String selectedShippingOptionId = requestedPaymentOptions.requestShipping
+                ? getStringOrEmpty(data, EXTRA_SHIPPING_OPTION_ID)
+                : "";
+        if (requestedPaymentOptions.requestShipping
+                && TextUtils.isEmpty(selectedShippingOptionId)) {
+            errorCallback.onPaymentError(ErrorStrings.SHIPPING_OPTION_EMPTY);
+            return;
+        }
+
+        successCallback.onPaymentSuccess(
+                /*methodName=*/methodName, /*details=*/details, /*payerData=*/
+                new PayerData(payerName, payerPhone, payerEmail, shippingAddress,
+                        selectedShippingOptionId));
     }
 
     /**
@@ -542,6 +585,10 @@
     }
 
     private static String getStringOrEmpty(Intent data, String key) {
-        return data.getExtras().getString(key, /*defaultValue =*/"");
+        return getStringOrEmpty(data.getExtras(), key);
+    }
+
+    private static String getStringOrEmpty(Bundle bundle, String key) {
+        return bundle.getString(key, /*defaultValue =*/"");
     }
 }
diff --git a/components/payments/core/error_strings.cc b/components/payments/core/error_strings.cc
index ccf6dfa..72b21b1 100644
--- a/components/payments/core/error_strings.cc
+++ b/components/payments/core/error_strings.cc
@@ -9,7 +9,7 @@
 
 // Please keep the list alphabetized.
 // Each string must be on a single line to correctly generate ErrorStrings.java.
-
+// clang-format off
 const char kAnotherUiShowing[] = "Another PaymentRequest UI is already showing in a different tab or window.";
 const char kAttemptedInitializationTwice[] = "Attempted initialization twice.";
 const char kCannotShowInBackgroundTab[] = "Cannot show PaymentRequest UI in a background tab.";
@@ -18,12 +18,19 @@
 const char kCannotUpdateWithoutInit[] = "Attempted updateWith without initialization.";
 const char kCannotUpdateWithoutShow[] = "Attempted updateWith without show.";
 const char kInvalidState[] = "Invalid state.";
+const char kMissingDetailsFromPaymentApp[] = "Payment app returned invalid response. Missing field \"details\".";
+const char kMissingMethodNameFromPaymentApp[] = "Payment app returned invalid response. Missing field \"methodName\".";
 const char kNotInASecureOrigin[] = "Not in a secure origin.";
+const char kPayerEmailEmpty[] = "Payment app returned invalid response. Missing field \"payerEmail\".";
+const char kPayerNameEmpty[] = "Payment app returned invalid response. Missing field \"payerName\".";
+const char kPayerPhoneEmpty[] = "Payment app returned invalid response. Missing field \"payerPhone\".";
 const char kProhibitedOrigin[] = "Only localhost, file://, and cryptographic scheme origins allowed.";
 const char kProhibitedOriginOrInvalidSslExplanation[] = "No UI will be shown. CanMakePayment and hasEnrolledInstrument will always return false. Show will be rejected with NotSupportedError.";
+const char kShippingAddressInvalid[] = "Payment app returned invalid shipping address in response.";
+const char kShippingOptionEmpty[] = "Payment app returned invalid response. Missing field \"shipping option\".";
 const char kStrictBasicCardShowReject[] = "User does not have valid information on file.";
 const char kTotalRequired[] = "Total required.";
 const char kUserCancelled[] = "User closed the Payment Request UI.";
-
+// clang-format on
 }  // namespace errors
 }  // namespace payments
diff --git a/components/payments/core/error_strings.h b/components/payments/core/error_strings.h
index 7187e4d8..521138f 100644
--- a/components/payments/core/error_strings.h
+++ b/components/payments/core/error_strings.h
@@ -38,9 +38,24 @@
 // Used when an invalid state is encountered generically.
 extern const char kInvalidState[];
 
+// The payment handler responded with an empty "details" field.
+extern const char kMissingDetailsFromPaymentApp[];
+
+// The payment handler responded with an empty "methodName" field.
+extern const char kMissingMethodNameFromPaymentApp[];
+
 // The PaymentRequest API is available only on secure origins.
 extern const char kNotInASecureOrigin[];
 
+// The payment handler responded with an empty "payer name" field.
+extern const char kPayerNameEmpty[];
+
+// The payment handler responded with an empty "payer email" field.
+extern const char kPayerEmailEmpty[];
+
+// The payment handler responded with an empty "payer phone" field.
+extern const char kPayerPhoneEmpty[];
+
 // Chrome provides payment information only to a whitelist of origin types.
 extern const char kProhibitedOrigin[];
 
@@ -48,6 +63,12 @@
 // or kInvalidSslCertificate error.
 extern const char kProhibitedOriginOrInvalidSslExplanation[];
 
+// The payment handler responded with an invalid shipping address.
+extern const char kShippingAddressInvalid[];
+
+// The payment handler responded with an empty "shipping option" field.
+extern const char kShippingOptionEmpty[];
+
 // Used when rejecting show() with NotSupportedError, because the user did not
 // have all valid autofill data.
 extern const char kStrictBasicCardShowReject[];
diff --git a/components/payments/core/native_error_strings.cc b/components/payments/core/native_error_strings.cc
index a1b9f77e..229a892 100644
--- a/components/payments/core/native_error_strings.cc
+++ b/components/payments/core/native_error_strings.cc
@@ -77,12 +77,6 @@
 
 const char kMethodNameRequired[] = "Method name required.";
 
-const char kMissingDetailsFromPaymentApp[] =
-    "Payment app returned invalid response. Missing field \"details\".";
-
-const char kMissingMethodNameFromPaymentApp[] =
-    "Payment app returned invalid response. Missing field \"methodName\".";
-
 const char kMultiplePaymentMethodsNotSupportedFormat[] =
     "The payment methods $ are not supported.";
 
@@ -93,15 +87,6 @@
 
 const char kNotShown[] = "Not shown.";
 
-const char kPayerEmailEmpty[] =
-    "Payment app returned invalid response. Missing field \"payerEmail\".";
-
-const char kPayerNameEmpty[] =
-    "Payment app returned invalid response. Missing field \"payerName\".";
-
-const char kPayerPhoneEmpty[] =
-    "Payment app returned invalid response. Missing field \"payerPhone\".";
-
 const char kPaymentManifestCrossSiteRedirectNotAllowed[] =
     "Cross-site redirect from \"$1\" to \"$2\" not allowed for payment "
     "manifests.";
@@ -151,12 +136,6 @@
 
 const char kShippingOptionIdRequired[] = "Shipping option identifier required.";
 
-const char kShippingAddressInvalid[] =
-    "Payment app returned invalid shipping address in response.";
-
-const char kShippingOptionEmpty[] =
-    "Payment app returned invalid response. Missing field \"shipping option\".";
-
 const char kCanMakePaymentEventRejected[] =
     "Payment handler rejected the promise passed into "
     "CanMakePaymentEvent.respondWith().";
diff --git a/components/payments/core/native_error_strings.h b/components/payments/core/native_error_strings.h
index cab74f5c..64a88832 100644
--- a/components/payments/core/native_error_strings.h
+++ b/components/payments/core/native_error_strings.h
@@ -102,12 +102,6 @@
 // Used when non-empty "supportedMethods": "" is required, but not provided.
 extern const char kMethodNameRequired[];
 
-// The payment handler responded with an empty "details" field.
-extern const char kMissingDetailsFromPaymentApp[];
-
-// The payment handler responded with an empty "methodName" field.
-extern const char kMissingMethodNameFromPaymentApp[];
-
 // The format for the message about multiple payment methods that are not
 // supported. This format should be used with base::ReplaceChars() function,
 // where "$" is the character to replace.
@@ -122,15 +116,6 @@
 // Used when PaymentRequest::Show() has not been called, but should have been.
 extern const char kNotShown[];
 
-// The payment handler responded with an empty "payer name" field.
-extern const char kPayerNameEmpty[];
-
-// The payment handler responded with an empty "payer email" field.
-extern const char kPayerEmailEmpty[];
-
-// The payment handler responded with an empty "payer phone" field.
-extern const char kPayerPhoneEmpty[];
-
 // Used for errors about cross-site redirects from A to B. This format should be
 // used with base::ReplaceStringPlaceholders(fmt, {A, B}, nullptr).
 extern const char kPaymentManifestCrossSiteRedirectNotAllowed[];
@@ -181,12 +166,6 @@
 // Used when non-empty "shippingOptionId": "" is required, but not provided.
 extern const char kShippingOptionIdRequired[];
 
-// The payment handler responded with an invalid shipping address.
-extern const char kShippingAddressInvalid[];
-
-// The payment handler responded with an empty "shipping option" field.
-extern const char kShippingOptionEmpty[];
-
 // The payment handler rejected the promise passed into
 // CanMakePaymentEvent.respondWith().
 extern const char kCanMakePaymentEventRejected[];
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn
index edc7555..e248ba7 100644
--- a/components/performance_manager/BUILD.gn
+++ b/components/performance_manager/BUILD.gn
@@ -30,6 +30,7 @@
     "graph/node_attached_data_impl.h",
     "graph/node_base.cc",
     "graph/node_base.h",
+    "graph/node_data_describer.cc",
     "graph/node_type.h",
     "graph/page_node.cc",
     "graph/page_node_impl.cc",
@@ -71,6 +72,8 @@
     "public/graph/graph_operations.h",
     "public/graph/node.h",
     "public/graph/node_attached_data.h",
+    "public/graph/node_data_describer.h",
+    "public/graph/node_data_describer_registry.h",
     "public/graph/page_node.h",
     "public/graph/policies/background_tab_loading_policy.h",
     "public/graph/process_node.h",
diff --git a/components/performance_manager/graph/graph_impl.cc b/components/performance_manager/graph/graph_impl.cc
index 20788df5..4dc9a76 100644
--- a/components/performance_manager/graph/graph_impl.cc
+++ b/components/performance_manager/graph/graph_impl.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -19,6 +20,8 @@
 #include "components/performance_manager/graph/process_node_impl.h"
 #include "components/performance_manager/graph/system_node_impl.h"
 #include "components/performance_manager/graph/worker_node_impl.h"
+#include "components/performance_manager/public/graph/node_data_describer.h"
+#include "components/performance_manager/public/graph/node_data_describer_registry.h"
 
 namespace ukm {
 class UkmEntryBuilder;
@@ -55,6 +58,97 @@
   DCHECK(it == observers->end());
 }
 
+class NodeDataDescriberRegistryImpl : public NodeDataDescriberRegistry {
+ public:
+  ~NodeDataDescriberRegistryImpl() override;
+
+  void RegisterDescriber(const NodeDataDescriber* describer,
+                         base::StringPiece name) override;
+  void UnregisterDescriber(const NodeDataDescriber* describer) override;
+
+  base::Value DescribeFrameNodeData(const FrameNode* node) const override;
+  base::Value DescribePageNodeData(const PageNode* node) const override;
+  base::Value DescribeProcessNodeData(const ProcessNode* node) const override;
+  base::Value DescribeSystemNodeData(const SystemNode* node) const override;
+  base::Value DescribeWorkerNodeData(const WorkerNode* node) const override;
+
+ private:
+  template <typename NodeType>
+  base::Value DescribeNodeImpl(
+      base::Value (NodeDataDescriber::*DescribeFn)(const NodeType*) const,
+      const NodeType* node) const;
+
+  base::flat_map<const NodeDataDescriber*, std::string> describers_;
+};
+
+template <typename NodeType>
+base::Value NodeDataDescriberRegistryImpl::DescribeNodeImpl(
+    base::Value (NodeDataDescriber::*Describe)(const NodeType*) const,
+    const NodeType* node) const {
+  base::Value result(base::Value::Type::DICTIONARY);
+
+  bool inserted = false;
+  for (const auto& name_and_describer : describers_) {
+    base::Value description = (name_and_describer.first->*Describe)(node);
+    if (!description.is_none()) {
+      DCHECK_EQ(nullptr, result.FindDictKey(name_and_describer.second));
+      result.SetKey(name_and_describer.second, std::move(description));
+      inserted = true;
+    }
+  }
+
+  return inserted ? std::move(result) : base::Value();
+}
+
+NodeDataDescriberRegistryImpl::~NodeDataDescriberRegistryImpl() {
+  // All describers should have unregistered before the graph is destroyed.
+  DCHECK(describers_.empty());
+}
+
+void NodeDataDescriberRegistryImpl::RegisterDescriber(
+    const NodeDataDescriber* describer,
+    base::StringPiece name) {
+#if DCHECK_IS_ON()
+  for (const auto& kv : describers_) {
+    DCHECK_NE(kv.second, name) << "Name must be unique";
+  }
+#endif
+  bool inserted =
+      describers_.insert(std::make_pair(describer, name.as_string())).second;
+  DCHECK(inserted);
+}
+
+void NodeDataDescriberRegistryImpl::UnregisterDescriber(
+    const NodeDataDescriber* describer) {
+  size_t erased = describers_.erase(describer);
+  DCHECK_EQ(1u, erased);
+}
+
+base::Value NodeDataDescriberRegistryImpl::DescribeFrameNodeData(
+    const FrameNode* node) const {
+  return DescribeNodeImpl(&NodeDataDescriber::DescribeFrameNodeData, node);
+}
+
+base::Value NodeDataDescriberRegistryImpl::DescribePageNodeData(
+    const PageNode* node) const {
+  return DescribeNodeImpl(&NodeDataDescriber::DescribePageNodeData, node);
+}
+
+base::Value NodeDataDescriberRegistryImpl::DescribeProcessNodeData(
+    const ProcessNode* node) const {
+  return DescribeNodeImpl(&NodeDataDescriber::DescribeProcessNodeData, node);
+}
+
+base::Value NodeDataDescriberRegistryImpl::DescribeSystemNodeData(
+    const SystemNode* node) const {
+  return DescribeNodeImpl(&NodeDataDescriber::DescribeSystemNodeData, node);
+}
+
+base::Value NodeDataDescriberRegistryImpl::DescribeWorkerNodeData(
+    const WorkerNode* node) const {
+  return DescribeNodeImpl(&NodeDataDescriber::DescribeWorkerNodeData, node);
+}
+
 }  // namespace
 
 GraphImpl::GraphImpl() {
@@ -220,6 +314,13 @@
   return ukm_recorder();
 }
 
+NodeDataDescriberRegistry* GraphImpl::GetNodeDataDescriberRegistry() const {
+  if (!describer_registry_)
+    describer_registry_ = std::make_unique<NodeDataDescriberRegistryImpl>();
+
+  return describer_registry_.get();
+}
+
 uintptr_t GraphImpl::GetImplType() const {
   return kGraphImplType;
 }
diff --git a/components/performance_manager/graph/graph_impl.h b/components/performance_manager/graph/graph_impl.h
index 87bee66..629630b 100644
--- a/components/performance_manager/graph/graph_impl.h
+++ b/components/performance_manager/graph/graph_impl.h
@@ -72,6 +72,7 @@
   std::vector<const WorkerNode*> GetAllWorkerNodes() const override;
   bool IsEmpty() const override;
   ukm::UkmRecorder* GetUkmRecorder() const override;
+  NodeDataDescriberRegistry* GetNodeDataDescriberRegistry() const override;
   uintptr_t GetImplType() const override;
   const void* GetImpl() const override;
 
@@ -183,6 +184,9 @@
   // flat_map.
   base::flat_map<GraphOwned*, std::unique_ptr<GraphOwned>> graph_owned_;
 
+  // Allocated on first use.
+  mutable std::unique_ptr<NodeDataDescriberRegistry> describer_registry_;
+
   // User data storage for the graph.
   friend class NodeAttachedDataMapHelper;
   using NodeAttachedDataKey = std::pair<const Node*, const void*>;
diff --git a/components/performance_manager/graph/graph_impl_unittest.cc b/components/performance_manager/graph/graph_impl_unittest.cc
index 049f26c..7236d50 100644
--- a/components/performance_manager/graph/graph_impl_unittest.cc
+++ b/components/performance_manager/graph/graph_impl_unittest.cc
@@ -10,6 +10,8 @@
 #include "components/performance_manager/graph/frame_node_impl.h"
 #include "components/performance_manager/graph/process_node_impl.h"
 #include "components/performance_manager/graph/system_node_impl.h"
+#include "components/performance_manager/public/graph/node_data_describer.h"
+#include "components/performance_manager/public/graph/node_data_describer_registry.h"
 #include "components/performance_manager/test_support/graph_test_harness.h"
 #include "components/performance_manager/test_support/mock_graphs.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -221,4 +223,125 @@
   EXPECT_EQ(2, destructor_count);
 }
 
+namespace {
+
+class TestNodeDataDescriber : public NodeDataDescriber {
+ public:
+  explicit TestNodeDataDescriber(base::StringPiece name) : name_(name) {}
+
+  base::Value DescribeFrameNodeData(const FrameNode* node) const override {
+    base::Value list(base::Value::Type::LIST);
+    list.Append(name_);
+    list.Append("FrameNode");
+    return list;
+  }
+
+  base::Value DescribePageNodeData(const PageNode* node) const override {
+    base::Value list(base::Value::Type::LIST);
+    list.Append(name_);
+    list.Append("PageNode");
+    return list;
+  }
+
+  base::Value DescribeProcessNodeData(const ProcessNode* node) const override {
+    base::Value list(base::Value::Type::LIST);
+    list.Append(name_);
+    list.Append("ProcessNode");
+    return list;
+  }
+
+  base::Value DescribeSystemNodeData(const SystemNode* node) const override {
+    base::Value list(base::Value::Type::LIST);
+    list.Append(name_);
+    list.Append("SystemNode");
+    return list;
+  }
+
+  base::Value DescribeWorkerNodeData(const WorkerNode* node) const override {
+    base::Value list(base::Value::Type::LIST);
+    list.Append(name_);
+    list.Append("WorkerNode");
+    return list;
+  }
+
+ private:
+  const std::string name_;
+};
+
+void AssertDictValueContainsListKey(const base::Value& descr,
+                                    const char* key,
+                                    const char* s1,
+                                    const char* s2) {
+  ASSERT_TRUE(descr.is_dict());
+  const base::Value* v = descr.FindListKey(key);
+  ASSERT_NE(nullptr, v);
+
+  const auto list = v->GetList();
+  ASSERT_EQ(2u, list.size());
+  ASSERT_EQ(list[0], base::Value(s1));
+  ASSERT_EQ(list[1], base::Value(s2));
+}
+
+}  // namespace
+
+TEST_F(GraphImplTest, NodeDataDescribers) {
+  MockSinglePageInSingleProcessGraph mock_graph(graph());
+  NodeDataDescriberRegistry* registry = graph()->GetNodeDataDescriberRegistry();
+
+  // No describers->no description.
+  base::Value descr = registry->DescribeFrameNodeData(mock_graph.frame.get());
+  EXPECT_TRUE(descr.is_none());
+
+  // Test that the default impl does nothing.
+  NodeDataDescriberDefaultImpl default_impl;
+  registry->RegisterDescriber(&default_impl, "default_impl");
+
+  // Test a single non-default describer for each node type.
+  TestNodeDataDescriber d1("d1");
+  registry->RegisterDescriber(&d1, "d1");
+
+  descr = registry->DescribeFrameNodeData(mock_graph.frame.get());
+  AssertDictValueContainsListKey(descr, "d1", "d1", "FrameNode");
+  EXPECT_EQ(1u, descr.DictSize());
+
+  descr = registry->DescribePageNodeData(mock_graph.page.get());
+  AssertDictValueContainsListKey(descr, "d1", "d1", "PageNode");
+  EXPECT_EQ(1u, descr.DictSize());
+
+  descr = registry->DescribeProcessNodeData(mock_graph.process.get());
+  AssertDictValueContainsListKey(descr, "d1", "d1", "ProcessNode");
+  EXPECT_EQ(1u, descr.DictSize());
+
+  descr =
+      registry->DescribeSystemNodeData(graph()->FindOrCreateSystemNodeImpl());
+  AssertDictValueContainsListKey(descr, "d1", "d1", "SystemNode");
+  EXPECT_EQ(1u, descr.DictSize());
+
+  auto worker = CreateNode<WorkerNodeImpl>(WorkerNode::WorkerType::kDedicated,
+                                           mock_graph.process.get());
+  descr = registry->DescribeWorkerNodeData(worker.get());
+  AssertDictValueContainsListKey(descr, "d1", "d1", "WorkerNode");
+  EXPECT_EQ(1u, descr.DictSize());
+
+  // Unregister the default impl now that it's been verified to say nothing
+  // about all node types.
+  registry->UnregisterDescriber(&default_impl);
+
+  // Register a second describer and test one node type.
+  TestNodeDataDescriber d2("d2");
+  registry->RegisterDescriber(&d2, "d2");
+
+  descr = registry->DescribeFrameNodeData(mock_graph.frame.get());
+  EXPECT_EQ(2u, descr.DictSize());
+  AssertDictValueContainsListKey(descr, "d1", "d1", "FrameNode");
+  AssertDictValueContainsListKey(descr, "d2", "d2", "FrameNode");
+
+  registry->UnregisterDescriber(&d2);
+  registry->UnregisterDescriber(&d1);
+
+  // No describers after unregistration->no description.
+  descr = registry->DescribeFrameNodeData(mock_graph.frame.get());
+  EXPECT_TRUE(descr.is_none());
+}
+
 }  // namespace performance_manager
diff --git a/components/performance_manager/graph/node_data_describer.cc b/components/performance_manager/graph/node_data_describer.cc
new file mode 100644
index 0000000..3b8e88d
--- /dev/null
+++ b/components/performance_manager/graph/node_data_describer.cc
@@ -0,0 +1,34 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/performance_manager/public/graph/node_data_describer.h"
+
+namespace performance_manager {
+
+base::Value NodeDataDescriberDefaultImpl::DescribeFrameNodeData(
+    const FrameNode* node) const {
+  return base::Value();
+}
+
+base::Value NodeDataDescriberDefaultImpl::DescribePageNodeData(
+    const PageNode* node) const {
+  return base::Value();
+}
+
+base::Value NodeDataDescriberDefaultImpl::DescribeProcessNodeData(
+    const ProcessNode* node) const {
+  return base::Value();
+}
+
+base::Value NodeDataDescriberDefaultImpl::DescribeSystemNodeData(
+    const SystemNode* node) const {
+  return base::Value();
+}
+
+base::Value NodeDataDescriberDefaultImpl::DescribeWorkerNodeData(
+    const WorkerNode* node) const {
+  return base::Value();
+}
+
+}  // namespace performance_manager
diff --git a/components/performance_manager/public/graph/graph.h b/components/performance_manager/public/graph/graph.h
index e69bdbc..5dc7535 100644
--- a/components/performance_manager/public/graph/graph.h
+++ b/components/performance_manager/public/graph/graph.h
@@ -31,6 +31,8 @@
 class WorkerNode;
 class WorkerNodeObserver;
 
+class NodeDataDescriberRegistry;
+
 // Represents a graph of the nodes representing a single browser. Maintains a
 // set of nodes that can be retrieved in different ways, some indexed. Keeps
 // a list of observers that are notified of node addition and removal.
@@ -86,6 +88,9 @@
   // Returns the associated UKM recorder if it is defined.
   virtual ukm::UkmRecorder* GetUkmRecorder() const = 0;
 
+  // Returns the data describer registry.
+  virtual NodeDataDescriberRegistry* GetNodeDataDescriberRegistry() const = 0;
+
   // The following functions are implementation detail and should not need to be
   // used by external clients. They provide the ability to safely downcast to
   // the underlying implementation.
diff --git a/components/performance_manager/public/graph/node_data_describer.h b/components/performance_manager/public/graph/node_data_describer.h
new file mode 100644
index 0000000..16bf44b
--- /dev/null
+++ b/components/performance_manager/public/graph/node_data_describer.h
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_DATA_DESCRIBER_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_DATA_DESCRIBER_H_
+
+#include "base/values.h"
+
+namespace performance_manager {
+
+class FrameNode;
+class PageNode;
+class ProcessNode;
+class SystemNode;
+class WorkerNode;
+
+// An interface for decoding node-private data for ultimate display as
+// human-comprehensible text to allow diagnosis of node private data.
+class NodeDataDescriber {
+ public:
+  virtual ~NodeDataDescriber() = default;
+
+  virtual base::Value DescribeFrameNodeData(const FrameNode* node) const = 0;
+  virtual base::Value DescribePageNodeData(const PageNode* node) const = 0;
+  virtual base::Value DescribeProcessNodeData(
+      const ProcessNode* node) const = 0;
+  virtual base::Value DescribeSystemNodeData(const SystemNode* node) const = 0;
+  virtual base::Value DescribeWorkerNodeData(const WorkerNode* node) const = 0;
+};
+
+// A convenience do-nothing implementation of the interface above. Returns
+// an is_none() value for all nodes.
+class NodeDataDescriberDefaultImpl : public NodeDataDescriber {
+ public:
+  base::Value DescribeFrameNodeData(const FrameNode* node) const override;
+  base::Value DescribePageNodeData(const PageNode* node) const override;
+  base::Value DescribeProcessNodeData(const ProcessNode* node) const override;
+  base::Value DescribeSystemNodeData(const SystemNode* node) const override;
+  base::Value DescribeWorkerNodeData(const WorkerNode* node) const override;
+};
+
+}  // namespace performance_manager
+
+#endif  // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_DATA_DESCRIBER_H_
diff --git a/components/performance_manager/public/graph/node_data_describer_registry.h b/components/performance_manager/public/graph/node_data_describer_registry.h
new file mode 100644
index 0000000..ad9ae62
--- /dev/null
+++ b/components/performance_manager/public/graph/node_data_describer_registry.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_DATA_DESCRIBER_REGISTRY_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_DATA_DESCRIBER_REGISTRY_H_
+
+#include <map>
+
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+
+namespace performance_manager {
+
+class FrameNode;
+class PageNode;
+class ProcessNode;
+class SystemNode;
+class WorkerNode;
+class NodeDataDescriber;
+
+// Allows registering NodeDataDescribers.
+class NodeDataDescriberRegistry {
+ public:
+  virtual ~NodeDataDescriberRegistry() = default;
+
+  // Register |describer| with |name|.
+  // The |describer| must not be registered already, and |name| must be unique
+  // to this registration.
+  virtual void RegisterDescriber(const NodeDataDescriber* describer,
+                                 base::StringPiece name) = 0;
+  // Unregister previously registered |describer|.
+  virtual void UnregisterDescriber(const NodeDataDescriber* describer) = 0;
+
+  // Invoke all registered describers for |node| and return a dictionary from
+  // their name to their description - if any.
+  virtual base::Value DescribeFrameNodeData(const FrameNode* node) const = 0;
+  virtual base::Value DescribePageNodeData(const PageNode* node) const = 0;
+  virtual base::Value DescribeProcessNodeData(
+      const ProcessNode* node) const = 0;
+  virtual base::Value DescribeSystemNodeData(const SystemNode* node) const = 0;
+  virtual base::Value DescribeWorkerNodeData(const WorkerNode* node) const = 0;
+};
+
+}  // namespace performance_manager
+
+#endif  // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_GRAPH_NODE_DATA_DESCRIBER_REGISTRY_H_
diff --git a/components/safe_browsing/content/web_ui/safe_browsing_ui.cc b/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
index 82c9180..6348b16f 100644
--- a/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
+++ b/components/safe_browsing/content/web_ui/safe_browsing_ui.cc
@@ -1446,6 +1446,8 @@
     }
 
     dlp_verdict.SetKey("triggered_rules", std::move(triggered_rules));
+
+    response_dict.SetKey("dlp_scan_verdict", std::move(dlp_verdict));
   }
 
   std::string response_serialized;
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc
index 8cc9764..13bf4eb 100644
--- a/components/viz/service/gl/gpu_service_impl.cc
+++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -25,13 +25,13 @@
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/command_buffer/service/skia_utils.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/config/dx_diag_node.h"
 #include "gpu/config/gpu_finch_features.h"
 #include "gpu/config/gpu_info_collector.h"
 #include "gpu/config/gpu_switches.h"
 #include "gpu/config/gpu_util.h"
-#include "gpu/config/skia_limits.h"
 #include "gpu/ipc/common/gpu_client_ids.h"
 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
 #include "gpu/ipc/common/gpu_peak_memory.h"
@@ -294,13 +294,8 @@
   protected_buffer_manager_ = new arc::ProtectedBufferManager();
 #endif  // defined(OS_CHROMEOS)
 
-  size_t max_resource_cache_bytes;
-  size_t max_glyph_cache_texture_bytes;
-  gpu::DetermineGrCacheLimitsFromAvailableMemory(
-      &max_resource_cache_bytes, &max_glyph_cache_texture_bytes);
-  GrContextOptions context_options;
-  context_options.fGlyphCacheTextureMaximumBytes =
-      max_glyph_cache_texture_bytes;
+  GrContextOptions context_options =
+      GetDefaultGrContextOptions(gpu_preferences_.gr_context_type);
   if (gpu_preferences_.force_max_texture_size) {
     context_options.fMaxTextureSizeOverride =
         gpu_preferences_.force_max_texture_size;
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index 3b78d022..f197636 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -405,6 +405,13 @@
       }
       return false;
     }
+
+    // It's a bug if we got an update containing more nodes than
+    // the size of the resulting tree. If Unserialize succeeded that
+    // means a node just got repeated or something harmless like that,
+    // but it should still be investigated and could be the sign of a
+    // performance issue.
+    DCHECK_LE(int{tree_update.nodes.size()}, ax_tree()->size());
   }
 
   // If this page is hidden by an interstitial, suppress all events.
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 768746236..384b4e37 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -2382,6 +2382,10 @@
   RunRegressionTest(FILE_PATH_LITERAL("xml-in-iframe-crash.html"));
 }
 
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, HiddenTable) {
+  RunRegressionTest(FILE_PATH_LITERAL("hidden-table.html"));
+}
+
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
                        LanguageDetectionLangAttribute) {
   RunLanguageDetectionTest(FILE_PATH_LITERAL("lang-attribute.html"));
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index d2e2947..7abae1b8 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -233,8 +233,11 @@
 
 bool ChildProcessSecurityPolicyImpl::Handle::CanAccessDataForOrigin(
     const GURL& url) {
-  if (child_id_ == ChildProcessHost::kInvalidUniqueID)
+  if (child_id_ == ChildProcessHost::kInvalidUniqueID) {
+    LogCanAccessDataForOriginCrashKeys(
+        "(unknown)", "(unknown)", url.GetOrigin().spec(), "handle_not_valid");
     return false;
+  }
 
   auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
   return policy->CanAccessDataForOrigin(child_id_, url);
@@ -242,8 +245,11 @@
 
 bool ChildProcessSecurityPolicyImpl::Handle::CanAccessDataForOrigin(
     const url::Origin& origin) {
-  if (child_id_ == ChildProcessHost::kInvalidUniqueID)
+  if (child_id_ == ChildProcessHost::kInvalidUniqueID) {
+    LogCanAccessDataForOriginCrashKeys(
+        "(unknown)", "(unknown)", origin.GetDebugString(), "handle_not_valid");
     return false;
+  }
 
   auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
   return policy->CanAccessDataForOrigin(child_id_, origin);
diff --git a/content/browser/client_hints/client_hints.cc b/content/browser/client_hints/client_hints.cc
index 3bfd298..7497af4 100644
--- a/content/browser/client_hints/client_hints.cc
+++ b/content/browser/client_hints/client_hints.cc
@@ -21,6 +21,7 @@
 #include "content/browser/frame_host/navigator.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/host_zoom_map.h"
+#include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "net/base/url_util.h"
@@ -337,10 +338,11 @@
 }
 
 void AddLangHeader(net::HttpRequestHeaders* headers,
-                   content::ClientHintsControllerDelegate* delegate) {
+                   content::BrowserContext* context) {
   SetHeaderToString(
       headers, network::mojom::WebClientHintsType::kLang,
-      blink::SerializeLangClientHint(delegate->GetAcceptLanguageString()));
+      blink::SerializeLangClientHint(
+          content::GetContentClient()->browser()->GetAcceptLangs(context)));
 }
 
 bool IsValidURLForClientHints(const GURL& url) {
@@ -505,7 +507,7 @@
           web_client_hints, is_main_frame, is_1p_origin, feature_policy,
           resource_origin, network::mojom::WebClientHintsType::kLang,
           blink::mojom::FeaturePolicyFeature::kClientHintLang)) {
-    AddLangHeader(headers, delegate);
+    AddLangHeader(headers, context);
   }
 
   base::Optional<blink::UserAgentMetadata> ch_ua_override;
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index a608b5c1..55e1a04 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1263,7 +1263,14 @@
 }
 
 const net::NetworkIsolationKey& RenderFrameHostImpl::GetNetworkIsolationKey() {
-  return network_isolation_key_;
+  DCHECK(!isolation_info_.IsEmpty());
+  return isolation_info_.network_isolation_key();
+}
+
+const net::IsolationInfo&
+RenderFrameHostImpl::GetIsolationInfoForSubresources() {
+  DCHECK(!isolation_info_.IsEmpty());
+  return isolation_info_;
 }
 
 void RenderFrameHostImpl::GetCanonicalUrlForSharing(
@@ -2249,70 +2256,70 @@
 
 net::SiteForCookies RenderFrameHostImpl::ComputeSiteForCookiesForNavigation(
     const GURL& destination) const {
-  // For top-level navigation, |site_for_cookies| will always be the destination
-  // URL.
-  if (frame_tree_node_->IsMainFrame())
-    return net::SiteForCookies::FromUrl(destination);
-
-  // Check if everything above the frame being navigated is consistent. It's OK
-  // to skip checking the frame itself since it will be validated against
-  // |site_for_cookies| anyway.
-  return ComputeSiteForCookiesInternal(parent_,
-                                       destination.SchemeIsCryptographic());
+  net::IsolationInfo::RedirectMode redirect_mode =
+      frame_tree_node_->IsMainFrame()
+          ? net::IsolationInfo::RedirectMode::kUpdateTopFrame
+          : net::IsolationInfo::RedirectMode::kUpdateFrameOnly;
+  return ComputeIsolationInfoInternal(url::Origin::Create(destination),
+                                      redirect_mode)
+      .site_for_cookies();
 }
 
 net::SiteForCookies RenderFrameHostImpl::ComputeSiteForCookies() {
-  return ComputeSiteForCookiesInternal(
-      this, GetLastCommittedURL().SchemeIsCryptographic());
+  return isolation_info_.site_for_cookies();
 }
 
-net::SiteForCookies RenderFrameHostImpl::ComputeSiteForCookiesInternal(
-    const RenderFrameHostImpl* render_frame_host,
-    bool is_origin_secure) const {
-#if defined(OS_ANDROID)
-  // On Android, a base URL can be set for the frame. If this the case, it is
-  // the URL to use for cookies.
-  NavigationEntry* last_committed_entry =
-      frame_tree_node_->navigator()->GetController()->GetLastCommittedEntry();
-  if (last_committed_entry &&
-      !last_committed_entry->GetBaseURLForDataURL().is_empty()) {
-    return net::SiteForCookies::FromUrl(
-        last_committed_entry->GetBaseURLForDataURL());
-  }
-#endif
+net::IsolationInfo RenderFrameHostImpl::ComputeIsolationInfoInternal(
+    const url::Origin& frame_origin,
+    net::IsolationInfo::RedirectMode redirect_mode) const {
+  url::Origin top_frame_origin = ComputeTopFrameOrigin(frame_origin);
 
-  const url::Origin& top_document_origin =
-      ComputeTopFrameOrigin(render_frame_host->last_committed_origin_);
-  net::SiteForCookies candidate =
-      net::SiteForCookies::FromOrigin(top_document_origin);
+  net::SiteForCookies candidate_site_for_cookies =
+      net::SiteForCookies::FromOrigin(top_frame_origin);
 
   if (GetContentClient()
           ->browser()
           ->ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(
-              top_document_origin.scheme(), is_origin_secure)) {
-    return candidate;
+              top_frame_origin.scheme(),
+              GURL::SchemeIsCryptographic(frame_origin.scheme()))) {
+    return net::IsolationInfo::Create(redirect_mode, top_frame_origin,
+                                      frame_origin, candidate_site_for_cookies);
   }
 
-  // Make sure every ancestors are same-domain with the main document. Otherwise
-  // this will be a 3rd party cookie.
-  for (const RenderFrameHostImpl* rfh = render_frame_host; rfh;
+  // Make sure all ancestors have origins consistent with the candidate
+  // SiteForCookies of the main document. Otherwise, SameSite cookies may not be
+  // used. For frame requests, it's OK to skip checking the frame itself since
+  // each request will be validated against |site_for_cookies| anyway.
+  for (const RenderFrameHostImpl* rfh = this->parent_; rfh;
        rfh = rfh->parent_) {
-    if (!candidate.IsEquivalent(
+    if (!candidate_site_for_cookies.IsEquivalent(
             net::SiteForCookies::FromOrigin(rfh->last_committed_origin_))) {
-      return net::SiteForCookies();
+      return net::IsolationInfo::Create(redirect_mode, top_frame_origin,
+                                        frame_origin, net::SiteForCookies());
     }
   }
 
-  return candidate;
+  // If |redirect_mode| is kUpdateNothing, then IsolationInfo is being computed
+  // for subresource requests. In that case, also need to check the
+  // SiteForCookies against the frame origin.
+  if (redirect_mode == net::IsolationInfo::RedirectMode::kUpdateNothing &&
+      !candidate_site_for_cookies.IsEquivalent(
+          net::SiteForCookies::FromOrigin(frame_origin))) {
+    return net::IsolationInfo::Create(redirect_mode, top_frame_origin,
+                                      frame_origin, net::SiteForCookies());
+  }
+
+  return net::IsolationInfo::Create(redirect_mode, top_frame_origin,
+                                    frame_origin, candidate_site_for_cookies);
 }
 
-void RenderFrameHostImpl::SetOriginAndNetworkIsolationKeyOfNewFrame(
+void RenderFrameHostImpl::SetOriginAndIsolationInfoOfNewFrame(
     const url::Origin& new_frame_creator) {
   // This method should only be called for *new* frames, that haven't committed
   // a navigation yet.
   DCHECK(!has_committed_any_navigation_);
   DCHECK(GetLastCommittedOrigin().opaque());
-  DCHECK(network_isolation_key_.IsEmpty());
+  DCHECK(isolation_info_.IsEmpty());
 
   // Calculate and set |new_frame_origin|.
   bool new_frame_should_be_sandboxed =
@@ -2322,8 +2329,8 @@
   url::Origin new_frame_origin = new_frame_should_be_sandboxed
                                      ? new_frame_creator.DeriveNewOpaqueOrigin()
                                      : new_frame_creator;
-  network_isolation_key_ = net::NetworkIsolationKey(
-      ComputeTopFrameOrigin(new_frame_origin), new_frame_origin);
+  isolation_info_ = ComputeIsolationInfoInternal(
+      new_frame_origin, net::IsolationInfo::RedirectMode::kUpdateNothing);
   SetLastCommittedOrigin(new_frame_origin);
 }
 
@@ -2346,10 +2353,9 @@
   frame_tree_node_->render_manager()->CreateProxiesForChildFrame(child.get());
 
   // When the child is added, it hasn't committed any navigation yet - its
-  // initial empty document should inherit the origin and network isolation key
-  // of its parent (the origin may change after the first commit). See also
-  // https://crbug.com/932067.
-  child->current_frame_host()->SetOriginAndNetworkIsolationKeyOfNewFrame(
+  // initial empty document should inherit the origin of its parent (the origin
+  // may change after the first commit). See also https://crbug.com/932067.
+  child->current_frame_host()->SetOriginAndIsolationInfoOfNewFrame(
       GetLastCommittedOrigin());
 
   children_.push_back(std::move(child));
@@ -4259,19 +4265,16 @@
 
 std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
 RenderFrameHostImpl::CreateCrossOriginPrefetchLoaderFactoryBundle() {
-  DCHECK(base::FeatureList::IsEnabled(
-      network::features::kPrefetchMainResourceNetworkIsolationKey));
-
   network::mojom::URLLoaderFactoryParamsPtr factory_params =
       URLLoaderFactoryParamsHelper::CreateForPrefetch(
           this, mojo::Clone(last_committed_client_security_state_));
 
   mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_default_factory;
   bool bypass_redirect_checks = false;
-  // Passing a nullopt NetworkIsolationKey ensures the factory is not
-  // initialized with a NetworkIsolationKey. This is necessary for a
-  // cross-origin prefetch factory because the factory must use the
-  // NetworkIsolationKey provided by requests going through it.
+  // Passing an empty IsolationInfo ensures the factory is not initialized with
+  // a IsolationInfo. This is necessary for a cross-origin prefetch factory
+  // because the factory must use the value provided by requests going through
+  // it.
   bypass_redirect_checks = CreateNetworkServiceDefaultFactoryAndObserve(
       std::move(factory_params),
       pending_default_factory.InitWithNewPipeAndPassReceiver());
@@ -4430,16 +4433,14 @@
   RenderFrameHostImpl* main_frame = new_window->GetMainFrame();
 
   // When the popup is created, it hasn't committed any navigation yet - its
-  // initial empty document should inherit the origin and network isolation key
-  // of its opener (the origin may change after the first commit). See also
-  // https://crbug.com/932067.
+  // initial empty document should inherit the origin of its opener (the origin
+  // may change after the first commit). See also https://crbug.com/932067.
   //
   // Note that that origin of the new frame might depend on sandbox flags.
   // Checking sandbox flags of the new frame should be safe at this point,
   // because the flags should be already inherited by the CreateNewWindow call
   // above.
-  main_frame->SetOriginAndNetworkIsolationKeyOfNewFrame(
-      GetLastCommittedOrigin());
+  main_frame->SetOriginAndIsolationInfoOfNewFrame(GetLastCommittedOrigin());
   main_frame->cross_origin_opener_policy_ = popup_coop;
   main_frame->cross_origin_embedder_policy_ = popup_coep;
 
@@ -5396,16 +5397,16 @@
   url::Origin main_world_origin_for_url_loader_factory =
       GetOriginForURLLoaderFactory(navigation_request);
 
-  // Network isolation key should be filled before the URLLoaderFactory for
+  // IsolationInfo should be filled before the URLLoaderFactory for
   // sub-resources is created. Only update for cross document navigations since
   // for opaque origin same document navigations, a new origin should not be
   // created as that would be different from the original.
   if (!is_same_document) {
-    network_isolation_key_ = net::NetworkIsolationKey(
-        ComputeTopFrameOrigin(main_world_origin_for_url_loader_factory),
-        main_world_origin_for_url_loader_factory);
+    isolation_info_ = ComputeIsolationInfoInternal(
+        main_world_origin_for_url_loader_factory,
+        net::IsolationInfo::RedirectMode::kUpdateNothing);
   }
-  DCHECK(network_isolation_key_.IsFullyPopulated());
+  DCHECK(!isolation_info_.IsEmpty());
 
   if (navigation_request && navigation_request->appcache_handle()) {
     // AppCache may create a subresource URLLoaderFactory later, so make sure it
@@ -5819,6 +5820,7 @@
   // TODO(lukasza): https://crbug.com/888079: Use this origin when committing
   // later on.
   url::Origin origin = url::Origin();
+  isolation_info_ = net::IsolationInfo::CreateTransient();
 
   std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
       subresource_loader_factories;
@@ -6777,7 +6779,7 @@
   mojo::MakeSelfOwnedReceiver(
       std::make_unique<WebSocketConnectorImpl>(
           GetProcess()->GetID(), routing_id_, last_committed_origin_,
-          network_isolation_key_),
+          isolation_info_.network_isolation_key()),
       std::move(receiver));
 }
 
@@ -6785,7 +6787,7 @@
     mojo::PendingReceiver<blink::mojom::QuicTransportConnector> receiver) {
   mojo::MakeSelfOwnedReceiver(std::make_unique<QuicTransportConnectorImpl>(
                                   GetProcess()->GetID(), last_committed_origin_,
-                                  network_isolation_key_),
+                                  isolation_info_.network_isolation_key()),
                               std::move(receiver));
 }
 
@@ -6951,7 +6953,7 @@
     mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver) {
   GetProcess()->GetStoragePartition()->CreateRestrictedCookieManager(
       network::mojom::RestrictedCookieManagerRole::SCRIPT,
-      GetLastCommittedOrigin(), ComputeSiteForCookies(),
+      GetLastCommittedOrigin(), isolation_info_.site_for_cookies(),
       ComputeTopFrameOrigin(GetLastCommittedOrigin()),
       /* is_service_worker = */ false, GetProcess()->GetID(), routing_id(),
       std::move(receiver));
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 31475215..78614f4 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -74,6 +74,7 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/data_pipe.h"
+#include "net/base/isolation_info.h"
 #include "net/base/network_isolation_key.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/http/http_response_headers.h"
@@ -283,6 +284,7 @@
   const GURL& GetLastCommittedURL() override;
   const url::Origin& GetLastCommittedOrigin() override;
   const net::NetworkIsolationKey& GetNetworkIsolationKey() override;
+  const net::IsolationInfo& GetIsolationInfoForSubresources() override;
   gfx::NativeView GetNativeView() override;
   void AddMessageToConsole(blink::mojom::ConsoleMessageLevel level,
                            const std::string& message) override;
@@ -1628,14 +1630,13 @@
   void OnFrameDidCallFocus();
   void OnSaveImageFromDataURL(const std::string& url_str);
 
-  // To be called by ComputeSiteForCookiesForNavigation() and
-  // ComputeSiteForCookies().
-  // Starts traversing the tree from |render_frame_host|.
-  // |is_origin_secure| is whether the origin of the destination of the
-  // navigation whose site_for_cookies is being calculated is secure.
-  net::SiteForCookies ComputeSiteForCookiesInternal(
-      const RenderFrameHostImpl* render_frame_host,
-      bool is_origin_secure) const;
+  // Computes the IsolationInfo for both navigations and subresources.
+  //
+  // For navigations, |frame_origin| is the origin being navigated to. For
+  // subresources, |frame_origin| is the value of |last_committed_origin_|.
+  net::IsolationInfo ComputeIsolationInfoInternal(
+      const url::Origin& frame_origin,
+      net::IsolationInfo::RedirectMode redirect_mode) const;
 
 #if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
   void OnShowPopup(const FrameHostMsg_ShowPopup_Params& params);
@@ -1942,11 +1943,11 @@
   // Update this frame's last committed origin.
   void SetLastCommittedOrigin(const url::Origin& origin);
 
-  // Set the |last_committed_origin_| and |network_isolation_key_| of |this|
-  // frame, inheriting the origin from |new_frame_creator| as appropriate
-  // (e.g. depending on whether |this| frame should be sandboxed / should have
-  // an opaque origin instead).
-  void SetOriginAndNetworkIsolationKeyOfNewFrame(
+  // Set the |last_committed_origin_| and |isolation_info_| of |this| frame,
+  // inheriting the origin from |new_frame_creator| as appropriate (e.g.
+  // depending on whether |this| frame should be sandboxed / should have an
+  // opaque origin instead).
+  void SetOriginAndIsolationInfoOfNewFrame(
       const url::Origin& new_frame_creator);
 
   // Called when a navigation commits succesfully to |url|. This will update
@@ -2701,12 +2702,13 @@
   scoped_refptr<PrefetchedSignedExchangeCache>
       prefetched_signed_exchange_cache_;
 
-  // Network isolation key to be used for subresources from the currently
-  // committed navigation. This is specific to a document and should be reset on
+  // Isolation information to be used for subresources from the currently
+  // committed navigation. Stores both the SiteForCookies and the
+  // NetworkIsolationKey. This is specific to a document and should be reset on
   // every cross-document commit. When a new frame is created, the new frame
-  // inherits the network isolation key from the creator frame, similarly to the
-  // last committed origin.
-  net::NetworkIsolationKey network_isolation_key_;
+  // inherits the IsolationInfo from the creator frame, similarly to the last
+  // committed origin.
+  net::IsolationInfo isolation_info_;
 
   // Hold onto hashes of the last |kMaxCookieSameSiteDeprecationUrls| cookie
   // URLs that we have seen since the last committed navigation, in order to
diff --git a/content/browser/loader/prefetch_browsertest.cc b/content/browser/loader/prefetch_browsertest.cc
index 9c4f9f4..5519a50 100644
--- a/content/browser/loader/prefetch_browsertest.cc
+++ b/content/browser/loader/prefetch_browsertest.cc
@@ -51,13 +51,9 @@
     if (split_cache_enabled_) {
       enable_features.push_back(
           net::features::kSplitCacheByNetworkIsolationKey);
-      enable_features.push_back(
-          network::features::kPrefetchMainResourceNetworkIsolationKey);
     } else {
       disabled_features.push_back(
           net::features::kSplitCacheByNetworkIsolationKey);
-      disabled_features.push_back(
-          network::features::kPrefetchMainResourceNetworkIsolationKey);
     }
 
     feature_list_.InitWithFeatures(enable_features, disabled_features);
@@ -639,7 +635,7 @@
   preload_waiter.Run();
   EXPECT_EQ(1, target_request_counter->GetRequestCount());
   EXPECT_EQ(1, preload_request_counter->GetRequestCount());
-  EXPECT_EQ(split_cache_enabled_ ? 2 : 1, GetPrefetchURLLoaderCallCount());
+  EXPECT_EQ(2, GetPrefetchURLLoaderCallCount());
 
   GURL cross_origin_preload_url =
       cross_origin_server_->GetURL("3p.example", preload_path);
@@ -828,7 +824,7 @@
   preload_waiter.Run();
   EXPECT_EQ(1, preload_request_counter->GetRequestCount());
 
-  EXPECT_EQ(split_cache_enabled_ ? 2 : 1, GetPrefetchURLLoaderCallCount());
+  EXPECT_EQ(2, GetPrefetchURLLoaderCallCount());
 
   WaitUntilLoaded(preload_url_in_sxg);
 
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc
index 4b34df0f..f2ccee4 100644
--- a/content/browser/loader/prefetch_url_loader.cc
+++ b/content/browser/loader/prefetch_url_loader.cc
@@ -60,7 +60,6 @@
           signed_exchange_utils::IsSignedExchangeHandlingEnabled(
               browser_context)) {
   DCHECK(network_loader_factory_);
-  RecordPrefetchRedirectHistogram(PrefetchRedirect::kPrefetchMade);
 
   if (is_signed_exchange_handling_enabled_) {
     // Set the SignedExchange accept header.
@@ -88,16 +87,6 @@
 
 PrefetchURLLoader::~PrefetchURLLoader() = default;
 
-void PrefetchURLLoader::RecordPrefetchRedirectHistogram(
-    PrefetchRedirect event) {
-  // We only want to record prefetch vs prefetch redirects when we're not
-  // experimenting with a request's redirect mode.
-  if (base::FeatureList::IsEnabled(blink::features::kPrefetchPrivacyChanges))
-    return;
-
-  base::UmaHistogramEnumeration("Prefetch.Redirect", event);
-}
-
 void PrefetchURLLoader::FollowRedirect(
     const std::vector<std::string>& removed_headers,
     const net::HttpRequestHeaders& modified_headers,
@@ -108,17 +97,12 @@
   DCHECK(!new_url) << "Redirect with modified URL was not "
                       "supported yet. crbug.com/845683";
   if (signed_exchange_prefetch_handler_) {
-    RecordPrefetchRedirectHistogram(
-        PrefetchRedirect::kPrefetchRedirectedSXGHandler);
-
     // Rebind |client_receiver_| and |loader_|.
     client_receiver_.Bind(signed_exchange_prefetch_handler_->FollowRedirect(
         loader_.BindNewPipeAndPassReceiver()));
     return;
   }
 
-  RecordPrefetchRedirectHistogram(PrefetchRedirect::kPrefetchRedirected);
-
   DCHECK(loader_);
   loader_->FollowRedirect(removed_headers,
                           net::HttpRequestHeaders() /* modified_headers */,
diff --git a/content/browser/loader/prefetch_url_loader.h b/content/browser/loader/prefetch_url_loader.h
index 11056a4..e4ed0e7 100644
--- a/content/browser/loader/prefetch_url_loader.h
+++ b/content/browser/loader/prefetch_url_loader.h
@@ -86,16 +86,6 @@
       const network::URLLoaderCompletionStatus& completion_status);
 
  private:
-  // This enum is used to record a histogram and should not be renumbered.
-  enum class PrefetchRedirect {
-    kPrefetchMade = 0,
-    kPrefetchRedirected = 1,
-    kPrefetchRedirectedSXGHandler = 2,
-    kMaxValue = kPrefetchRedirectedSXGHandler
-  };
-
-  void RecordPrefetchRedirectHistogram(PrefetchRedirect event);
-
   // network::mojom::URLLoader overrides:
   void FollowRedirect(const std::vector<std::string>& removed_headers,
                       const net::HttpRequestHeaders& modified_headers,
diff --git a/content/browser/loader/prefetch_url_loader_service.cc b/content/browser/loader/prefetch_url_loader_service.cc
index 4d19118..494d29c 100644
--- a/content/browser/loader/prefetch_url_loader_service.cc
+++ b/content/browser/loader/prefetch_url_loader_service.cc
@@ -283,8 +283,6 @@
 }
 
 void PrefetchURLLoaderService::EnsureCrossOriginFactory() {
-  DCHECK(base::FeatureList::IsEnabled(
-      network::features::kPrefetchMainResourceNetworkIsolationKey));
   BindContext& current_context = *current_bind_context();
   // If the factory has already been created, don't re-create it.
   if (current_context.cross_origin_factory)
diff --git a/content/browser/manifest/manifest_browsertest.cc b/content/browser/manifest/manifest_browsertest.cc
index 86fb190..6ea9c55 100644
--- a/content/browser/manifest/manifest_browsertest.cc
+++ b/content/browser/manifest/manifest_browsertest.cc
@@ -320,6 +320,22 @@
   EXPECT_EQ(0, GetConsoleErrorCount());
 }
 
+// This page has a manifest with only file handlers specified. Asking
+// for just the manifest should succeed with a non empty manifest.
+IN_PROC_BROWSER_TEST_F(ManifestBrowserTest, FileHandlerManifest) {
+  GURL test_url =
+      embedded_test_server()->GetURL("/manifest/file-handler-manifest.html");
+  ASSERT_TRUE(NavigateToURL(shell(), test_url));
+
+  GetManifestAndWait();
+  EXPECT_FALSE(manifest().IsEmpty());
+  EXPECT_FALSE(manifest_url().is_empty());
+  EXPECT_FALSE(manifest().file_handlers.empty());
+  EXPECT_EQ(0, GetConsoleErrorCount());
+  ASSERT_EQ(1u, reported_manifest_urls().size());
+  EXPECT_EQ(manifest_url(), reported_manifest_urls()[0]);
+}
+
 // If a page's manifest lives in a different origin, it should follow the CORS
 // rules and requesting the manifest should return an empty manifest (unless the
 // response contains CORS headers).
diff --git a/content/browser/renderer_host/input/scroll_latency_browsertest.cc b/content/browser/renderer_host/input/scroll_latency_browsertest.cc
index e7cb819f..024f1a12 100644
--- a/content/browser/renderer_host/input/scroll_latency_browsertest.cc
+++ b/content/browser/renderer_host/input/scroll_latency_browsertest.cc
@@ -306,6 +306,9 @@
   EXPECT_TRUE(VerifyRecordedSamplesForHistogram(
       1,
       "Graphics.Smoothness.PercentDroppedFrames.ScrollingThread.TouchScroll"));
+
+  RunUntilInputProcessed(GetWidgetHost());
+  FetchHistogramsFromChildProcesses();
   EXPECT_TRUE(VerifyRecordedSamplesForHistogram(
       1, "Event.Latency.ScrollBegin.Touch.BrowserNotifiedToBeforeGpuSwap2"));
 }
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 22a0c6d5..ba990b8 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -40,6 +40,8 @@
 #include "content/public/common/content_switches.h"
 #include "ipc/ipc_message.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "net/base/isolation_info.h"
+#include "net/cookies/site_for_cookies.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/loader/url_loader_factory_bundle.mojom.h"
 #include "third_party/blink/public/mojom/renderer_preference_watcher.mojom.h"
@@ -1191,7 +1193,10 @@
                                      .InitWithNewPipeAndPassReceiver();
   network::mojom::URLLoaderFactoryParamsPtr factory_params =
       URLLoaderFactoryParamsHelper::CreateForWorker(
-          rph, origin, net::NetworkIsolationKey(origin, origin),
+          rph, origin,
+          net::IsolationInfo::Create(
+              net::IsolationInfo::RedirectMode::kUpdateNothing, origin, origin,
+              net::SiteForCookies::FromOrigin(origin)),
           std::move(coep_reporter));
   bool bypass_redirect_checks = false;
 
diff --git a/content/browser/url_loader_factory_params_helper.cc b/content/browser/url_loader_factory_params_helper.cc
index 9f51bf6..b1c7192 100644
--- a/content/browser/url_loader_factory_params_helper.cc
+++ b/content/browser/url_loader_factory_params_helper.cc
@@ -16,6 +16,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/web_preferences.h"
+#include "net/base/isolation_info.h"
 #include "services/network/public/mojom/cross_origin_embedder_policy.mojom.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 
@@ -41,7 +42,7 @@
     const base::Optional<url::Origin>& top_frame_origin,
     bool is_trusted,
     const base::Optional<base::UnguessableToken>& top_frame_token,
-    const base::Optional<net::NetworkIsolationKey>& network_isolation_key,
+    const net::IsolationInfo& isolation_info,
     network::mojom::ClientSecurityStatePtr client_security_state,
     mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
         coep_reporter,
@@ -63,7 +64,7 @@
 
   params->is_trusted = is_trusted;
   params->top_frame_id = top_frame_token;
-  params->network_isolation_key = network_isolation_key;
+  params->isolation_info = isolation_info;
 
   params->disable_web_security =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -110,7 +111,7 @@
       // top_frame_origin
       frame->ComputeTopFrameOrigin(frame_origin),
       false,  // is_trusted
-      frame->GetTopFrameToken(), frame->GetNetworkIsolationKey(),
+      frame->GetTopFrameToken(), frame->GetIsolationInfoForSubresources(),
       std::move(client_security_state), std::move(coep_reporter),
       frame->GetRenderViewHost()
           ->GetWebkitPreferences()
@@ -131,7 +132,7 @@
                       base::nullopt,          // top_frame_origin
                       false,                  // is_trusted
                       frame->GetTopFrameToken(),
-                      frame->GetNetworkIsolationKey(),
+                      frame->GetIsolationInfoForSubresources(),
                       std::move(client_security_state),
                       mojo::NullRemote(),  // coep_reporter
                       frame->GetRenderViewHost()
@@ -155,7 +156,7 @@
                       frame->ComputeTopFrameOrigin(frame_origin),
                       true,  // is_trusted
                       frame->GetTopFrameToken(),
-                      base::nullopt,  // network_isolation_key
+                      net::IsolationInfo(),  // isolation_info
                       std::move(client_security_state),
                       mojo::NullRemote(),  // coep_reporter
                       frame->GetRenderViewHost()
@@ -169,7 +170,7 @@
 URLLoaderFactoryParamsHelper::CreateForWorker(
     RenderProcessHost* process,
     const url::Origin& request_initiator,
-    const net::NetworkIsolationKey& network_isolation_key,
+    const net::IsolationInfo& isolation_info,
     mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
         coep_reporter) {
   return CreateParams(process,
@@ -178,7 +179,7 @@
                       base::nullopt,      // top_frame_origin
                       false,              // is_trusted
                       base::nullopt,      // top_frame_token
-                      network_isolation_key,
+                      isolation_info,
                       nullptr,  // client_security_state
                       std::move(coep_reporter),
                       false,   // allow_universal_access_from_file_urls
@@ -199,13 +200,12 @@
   }
 
   // Since this function is about to get deprecated (crbug.com/891872), it
-  // should be fine to not add support for network isolation thus sending empty
-  // key.
+  // should be fine to not add support for isolation info thus using an empty
+  // NetworkIsolationKey.
   //
   // We may not be able to allow powerful APIs such as memory measurement APIs
   // (see https://crbug.com/887967) without removing this call.
-  base::Optional<net::NetworkIsolationKey> network_isolation_key =
-      base::nullopt;
+  net::IsolationInfo isolation_info;
   base::Optional<base::UnguessableToken> top_frame_token = base::nullopt;
 
   return CreateParams(
@@ -214,7 +214,7 @@
       request_initiator_site_lock,  // request_initiator_site_lock
       base::nullopt,                // top_frame_origin
       false,                        // is_trusted
-      top_frame_token, network_isolation_key,
+      top_frame_token, isolation_info,
       nullptr,             // client_security_state
       mojo::NullRemote(),  // coep_reporter
       false,               // allow_universal_access_from_file_urls
diff --git a/content/browser/url_loader_factory_params_helper.h b/content/browser/url_loader_factory_params_helper.h
index 5b94c02..a9cdaaf 100644
--- a/content/browser/url_loader_factory_params_helper.h
+++ b/content/browser/url_loader_factory_params_helper.h
@@ -6,13 +6,12 @@
 #define CONTENT_BROWSER_URL_LOADER_FACTORY_PARAMS_HELPER_H_
 
 #include "mojo/public/cpp/bindings/pending_remote.h"
-#include "net/base/network_isolation_key.h"
 #include "services/network/public/mojom/cross_origin_embedder_policy.mojom-forward.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "url/origin.h"
 
 namespace net {
-class NetworkIsolationKey;
+class IsolationInfo;
 }  // namespace net
 
 namespace content {
@@ -66,7 +65,7 @@
   static network::mojom::URLLoaderFactoryParamsPtr CreateForWorker(
       RenderProcessHost* process,
       const url::Origin& request_initiator,
-      const net::NetworkIsolationKey& network_isolation_key,
+      const net::IsolationInfo& isolation_info,
       mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
           coep_reporter);
 
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc
index e037c3e..f77943c 100644
--- a/content/browser/worker_host/dedicated_worker_host.cc
+++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -31,7 +31,6 @@
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "mojo/public/cpp/system/message_pipe.h"
-#include "net/base/network_isolation_key.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/loader/fetch_client_settings_object.mojom.h"
 #include "third_party/blink/public/mojom/usb/web_usb_service.mojom.h"
@@ -143,8 +142,8 @@
     return;
   }
 
-  network_isolation_key_ =
-      nearest_ancestor_render_frame_host->GetNetworkIsolationKey();
+  isolation_info_ =
+      nearest_ancestor_render_frame_host->GetIsolationInfoForSubresources();
 
   // Get a storage domain.
   SiteInstance* site_instance =
@@ -209,7 +208,7 @@
   WorkerScriptFetchInitiator::Start(
       worker_process_host_->GetID(), script_url, creator_render_frame_host,
       nearest_ancestor_render_frame_host->ComputeSiteForCookies(),
-      creator_origin_, network_isolation_key_, credentials_mode,
+      creator_origin_, isolation_info_, credentials_mode,
       std::move(outside_fetch_client_settings_object),
       blink::mojom::ResourceType::kWorker,
       storage_partition_impl->GetServiceWorkerContext(),
@@ -371,7 +370,7 @@
       std::make_unique<WebSocketConnectorImpl>(
           ancestor_render_frame_host_id_.child_id,
           ancestor_render_frame_host_id_.frame_routing_id, worker_origin_,
-          network_isolation_key_),
+          isolation_info_.network_isolation_key()),
       std::move(receiver));
 }
 
@@ -387,7 +386,7 @@
   }
   mojo::MakeSelfOwnedReceiver(std::make_unique<QuicTransportConnectorImpl>(
                                   worker_process_host_->GetID(), worker_origin_,
-                                  network_isolation_key_),
+                                  isolation_info_.network_isolation_key()),
                               std::move(receiver));
 }
 
diff --git a/content/browser/worker_host/dedicated_worker_host.h b/content/browser/worker_host/dedicated_worker_host.h
index 5261966..407d798 100644
--- a/content/browser/worker_host/dedicated_worker_host.h
+++ b/content/browser/worker_host/dedicated_worker_host.h
@@ -20,6 +20,7 @@
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "net/base/isolation_info.h"
 #include "services/network/public/cpp/cross_origin_embedder_policy.h"
 #include "third_party/blink/public/mojom/filesystem/file_system.mojom-forward.h"
 #include "third_party/blink/public/mojom/idle/idle_manager.mojom-forward.h"
@@ -206,9 +207,9 @@
   // https://html.spec.whatwg.org/C/#concept-settings-object-origin
   const url::Origin worker_origin_;
 
-  // The network isolation key to be used for both the worker script and the
-  // worker's subresources.
-  net::NetworkIsolationKey network_isolation_key_;
+  // The IsolationInfo to be used for both the worker script and the worker's
+  // subresources.
+  net::IsolationInfo isolation_info_;
 
   // The DedicatedWorker's Cross-Origin-Embedder-Policy(COEP). It is equals to
   // the nearest ancestor frame host's COEP:
diff --git a/content/browser/worker_host/shared_worker_host.cc b/content/browser/worker_host/shared_worker_host.cc
index 80b7e23..59f103d 100644
--- a/content/browser/worker_host/shared_worker_host.cc
+++ b/content/browser/worker_host/shared_worker_host.cc
@@ -30,7 +30,8 @@
 #include "content/public/browser/service_worker_context.h"
 #include "content/public/common/content_client.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
-#include "net/base/network_isolation_key.h"
+#include "net/base/isolation_info.h"
+#include "net/cookies/site_for_cookies.h"
 #include "third_party/blink/public/common/loader/url_loader_factory_bundle.h"
 #include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/mojom/appcache/appcache.mojom.h"
@@ -264,12 +265,15 @@
           pending_default_factory.InitWithNewPipeAndPassReceiver();
 
   const url::Origin& origin = instance_.constructor_origin();
+
   // TODO(https://crbug.com/1060832): Implement COEP reporter for shared
   // workers.
   network::mojom::URLLoaderFactoryParamsPtr factory_params =
       URLLoaderFactoryParamsHelper::CreateForWorker(
           worker_process_host_, origin,
-          net::NetworkIsolationKey(origin, origin),
+          net::IsolationInfo::Create(
+              net::IsolationInfo::RedirectMode::kUpdateNothing, origin, origin,
+              net::SiteForCookies::FromOrigin(origin)),
           /*coep_reporter=*/mojo::NullRemote());
   GetContentClient()->browser()->WillCreateURLLoaderFactory(
       worker_process_host_->GetBrowserContext(),
diff --git a/content/browser/worker_host/shared_worker_service_impl.cc b/content/browser/worker_host/shared_worker_service_impl.cc
index 31abecd..ba2aba9 100644
--- a/content/browser/worker_host/shared_worker_service_impl.cc
+++ b/content/browser/worker_host/shared_worker_service_impl.cc
@@ -35,6 +35,8 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "net/base/isolation_info.h"
+#include "net/cookies/site_for_cookies.h"
 #include "services/network/public/mojom/fetch_api.mojom.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/messaging/message_port_channel.h"
@@ -333,8 +335,10 @@
       worker_process_host->GetID(), host->instance().url(),
       creator_render_frame_host, net::SiteForCookies::FromOrigin(worker_origin),
       host->instance().constructor_origin(),
-      net::NetworkIsolationKey(worker_origin, worker_origin), credentials_mode,
-      std::move(outside_fetch_client_settings_object),
+      net::IsolationInfo::Create(
+          net::IsolationInfo::RedirectMode::kUpdateNothing, worker_origin,
+          worker_origin, net::SiteForCookies::FromOrigin(worker_origin)),
+      credentials_mode, std::move(outside_fetch_client_settings_object),
       blink::mojom::ResourceType::kSharedWorker, service_worker_context_,
       service_worker_handle_raw, std::move(appcache_host),
       std::move(blob_url_loader_factory), url_loader_factory_override_,
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc
index 6534c66..db8e304 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.cc
+++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -42,8 +42,8 @@
 #include "content/public/common/referrer.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "net/base/isolation_info.h"
 #include "net/base/load_flags.h"
-#include "net/base/network_isolation_key.h"
 #include "net/http/http_request_headers.h"
 #include "services/network/public/cpp/constants.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -67,7 +67,7 @@
     RenderFrameHost* creator_render_frame_host,
     const net::SiteForCookies& site_for_cookies,
     const url::Origin& request_initiator,
-    const net::NetworkIsolationKey& trusted_network_isolation_key,
+    const net::IsolationInfo& trusted_isolation_info,
     network::mojom::CredentialsMode credentials_mode,
     blink::mojom::FetchClientSettingsObjectPtr
         outside_fetch_client_settings_object,
@@ -179,7 +179,7 @@
 
   CreateScriptLoader(
       worker_process_id, initial_request_url, creator_render_frame_host,
-      trusted_network_isolation_key, std::move(resource_request),
+      trusted_isolation_info, std::move(resource_request),
       std::move(factory_bundle_for_browser),
       std::move(subresource_loader_factories),
       std::move(service_worker_context), service_worker_handle,
@@ -284,7 +284,7 @@
     int worker_process_id,
     const GURL& initial_request_url,
     RenderFrameHost* creator_render_frame_host,
-    const net::NetworkIsolationKey& trusted_network_isolation_key,
+    const net::IsolationInfo& trusted_isolation_info,
     std::unique_ptr<network::ResourceRequest> resource_request,
     std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
         factory_bundle_for_browser_info,
@@ -324,7 +324,7 @@
     // to the COEP reporter in DedicatedWorkerHost.
     network::mojom::URLLoaderFactoryParamsPtr factory_params =
         URLLoaderFactoryParamsHelper::CreateForWorker(
-            factory_process, request_initiator, trusted_network_isolation_key,
+            factory_process, request_initiator, trusted_isolation_info,
             /*coep_reporter=*/mojo::NullRemote());
 
     mojo::PendingReceiver<network::mojom::URLLoaderFactory>
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.h b/content/browser/worker_host/worker_script_fetch_initiator.h
index 900e754..31304c23a 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.h
+++ b/content/browser/worker_host/worker_script_fetch_initiator.h
@@ -70,7 +70,7 @@
       RenderFrameHost* creator_render_frame_host,
       const net::SiteForCookies& site_for_cookies,
       const url::Origin& request_initiator,
-      const net::NetworkIsolationKey& trusted_network_isolation_key,
+      const net::IsolationInfo& trusted_isolation_info,
       network::mojom::CredentialsMode credentials_mode,
       blink::mojom::FetchClientSettingsObjectPtr
           outside_fetch_client_settings_object,
@@ -111,7 +111,7 @@
       int worker_process_id,
       const GURL& initial_request_url,
       RenderFrameHost* creator_render_frame_host,
-      const net::NetworkIsolationKey& trusted_network_isolation_key,
+      const net::IsolationInfo& trusted_isolation_info,
       std::unique_ptr<network::ResourceRequest> resource_request,
       std::unique_ptr<blink::PendingURLLoaderFactoryBundle>
           factory_bundle_for_browser_info,
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeInputActionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeInputActionTest.java
index 7e2bcec..d0040527 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeInputActionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeInputActionTest.java
@@ -13,7 +13,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner;
 import org.chromium.ui.base.ime.TextInputAction;
@@ -23,7 +22,6 @@
  * IME (input method editor) and text input tests for enterkeyhint attribute.
  */
 @RunWith(ContentJUnit4ClassRunner.class)
-@CommandLineFlags.Add({"enable-experimental-web-platform-features"})
 public class ImeInputActionTest {
     @Rule
     public ImeActivityTestRule mRule = new ImeActivityTestRule();
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeInputModeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeInputModeTest.java
index 4116dbc..18492eb 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeInputModeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeInputModeTest.java
@@ -13,7 +13,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.blink_public.web.WebTextInputMode;
 import org.chromium.content_public.browser.test.ContentJUnit4ClassRunner;
@@ -23,7 +22,6 @@
  * IME (input method editor) and text input tests for input-mode attribute.
  */
 @RunWith(ContentJUnit4ClassRunner.class)
-@CommandLineFlags.Add({"enable-experimental-web-platform-features"})
 public class ImeInputModeTest {
     @Rule
     public ImeActivityTestRule mRule = new ImeActivityTestRule();
diff --git a/content/public/browser/client_hints_controller_delegate.h b/content/public/browser/client_hints_controller_delegate.h
index 37ec695..0566506 100644
--- a/content/public/browser/client_hints_controller_delegate.h
+++ b/content/public/browser/client_hints_controller_delegate.h
@@ -43,8 +43,6 @@
 
   virtual bool IsJavaScriptAllowed(const GURL& url) = 0;
 
-  virtual std::string GetAcceptLanguageString() = 0;
-
   virtual blink::UserAgentMetadata GetUserAgentMetadata() = 0;
 
   virtual void Bind(
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index 742adab1..6552048 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -57,6 +57,7 @@
 }  // namespace features
 
 namespace net {
+class IsolationInfo;
 class NetworkIsolationKey;
 }
 
@@ -218,8 +219,15 @@
   // Returns the network isolation key used for subresources from the currently
   // committed navigation. It's set on commit and does not change until the next
   // navigation is committed.
+  //
+  // TODO(mmenke): Remove this in favor of GetIsolationInfoForSubresoruces().
   virtual const net::NetworkIsolationKey& GetNetworkIsolationKey() = 0;
 
+  // Returns the IsolationInfo used for subresources from the currently
+  // committed navigation. It's set on commit and does not change until the next
+  // navigation is committed.
+  virtual const net::IsolationInfo& GetIsolationInfoForSubresources() = 0;
+
   // Returns the associated widget's native view.
   virtual gfx::NativeView GetNativeView() = 0;
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index b5fa647..aa3efe3 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -856,7 +856,7 @@
 // TODO(crbug.com/955194): Remove this once chrome://oobe migrates off of
 // Polymer 1.
 const base::Feature kWebUIPolymer2Exceptions{"WebUIPolymer2Exceptions",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_CHROMEOS)
 
 #if defined(OS_MACOSX)
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index d7f88a8..f152546 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -3427,8 +3427,8 @@
   url_loader_factory_params->process_id = process_id;
   url_loader_factory_params->is_corb_enabled = false;
   url::Origin origin = url::Origin::Create(url);
-  url_loader_factory_params->network_isolation_key =
-      net::NetworkIsolationKey(origin, origin);
+  url_loader_factory_params->isolation_info =
+      net::IsolationInfo::CreateForInternalRequest(origin);
   network_context->CreateURLLoaderFactory(
       url_loader_factory.BindNewPipeAndPassReceiver(),
       std::move(url_loader_factory_params));
diff --git a/content/public/test/web_test_support_renderer.h b/content/public/test/web_test_support_renderer.h
index 429eb18..ded8d376 100644
--- a/content/public/test/web_test_support_renderer.h
+++ b/content/public/test/web_test_support_renderer.h
@@ -15,7 +15,6 @@
 namespace blink {
 struct Manifest;
 class WebInputEvent;
-class WebLocalFrame;
 struct WebSize;
 class WebURL;
 class WebView;
@@ -25,26 +24,16 @@
 class ColorSpace;
 }
 
-namespace test_runner {
+namespace content {
+class RenderFrame;
+class RenderView;
 class WebFrameTestProxy;
 class WebViewTestProxy;
 class WebWidgetTestProxy;
-}  // namespace test_runner
-
-namespace content {
-
-class RenderFrame;
-class RenderView;
 
 // Turn a renderer into web test mode.
 void EnableRendererWebTestMode();
 
-// Gets WebWidgetTestProxy associated with |frame| (either the view's widget
-// or the local root's frame widget).  Caller has to ensure that prior to
-// construction of |render_frame|, EnableWebTestProxyCreation was called.
-test_runner::WebWidgetTestProxy* GetWebWidgetTestProxy(
-    blink::WebLocalFrame* frame);
-
 // Enable injecting of a WebViewTestProxy between WebViews and RenderViews,
 // WebWidgetTestProxy between WebWidgets and RenderWidgets and WebFrameTestProxy
 // between WebFrames and RenderFrames.
@@ -74,7 +63,7 @@
 // transformation was necessary (e.g. for a keyboard event OR if widget requires
 // no scaling and has coordinates starting at (0,0)).
 std::unique_ptr<blink::WebInputEvent> TransformScreenToWidgetCoordinates(
-    test_runner::WebWidgetTestProxy* web_widget_test_proxy,
+    WebWidgetTestProxy* web_widget_test_proxy,
     const blink::WebInputEvent& event);
 
 // Get the color space for a given name string. This is not in the ColorSpace
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 069a4af1..09031343 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -679,7 +679,7 @@
 # See comment at the top of //content/BUILD.gn for how this works.
 group("for_content_tests") {
   visibility = [
-    "//content/shell/test_runner",
+    "//content/shell:web_test_renderer",
     "//content/test/*",
   ]
 
diff --git a/content/renderer/accessibility/render_accessibility_impl.cc b/content/renderer/accessibility/render_accessibility_impl.cc
index 9a7998f8..4d44047 100644
--- a/content/renderer/accessibility/render_accessibility_impl.cc
+++ b/content/renderer/accessibility/render_accessibility_impl.cc
@@ -802,6 +802,14 @@
     // parts of the code as well, so we need to ensure the object still exists.
     if (!obj.UpdateLayoutAndCheckValidity())
       continue;
+
+    // If the object in question is not included in the tree, get the
+    // nearest ancestor that is (ParentObject() will do this for us).
+    // Otherwise this can lead to the serializer doing extra work because
+    // the object won't be in |already_serialized_ids|.
+    if (!obj.AccessibilityIsIncludedInTree())
+      obj = obj.ParentObject();
+
     if (already_serialized_ids.find(obj.AxID()) != already_serialized_ids.end())
       continue;
 
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index ab0c83c..6c364d7 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -88,6 +88,14 @@
 
 static_library("web_test_renderer") {
   testonly = true
+
+  # This is to support our dependency on //content/renderer.
+  # See comment at the top of //content/BUILD.gn for why this is disabled in
+  # component builds.
+  if (is_component_build) {
+    check_includes = false
+  }
+
   sources = [
     "renderer/web_test/blink_test_helpers.cc",
     "renderer/web_test/blink_test_helpers.h",
@@ -101,19 +109,90 @@
     "renderer/web_test/web_test_render_frame_observer.h",
     "renderer/web_test/web_test_render_thread_observer.cc",
     "renderer/web_test/web_test_render_thread_observer.h",
+    "test_runner/accessibility_controller.cc",
+    "test_runner/accessibility_controller.h",
+    "test_runner/app_banner_service.cc",
+    "test_runner/app_banner_service.h",
+    "test_runner/event_sender.cc",
+    "test_runner/event_sender.h",
+    "test_runner/gamepad_controller.cc",
+    "test_runner/gamepad_controller.h",
+    "test_runner/gc_controller.cc",
+    "test_runner/gc_controller.h",
+    "test_runner/layout_dump.cc",
+    "test_runner/layout_dump.h",
+    "test_runner/mock_content_settings_client.cc",
+    "test_runner/mock_content_settings_client.h",
+    "test_runner/mock_grammar_check.cc",
+    "test_runner/mock_grammar_check.h",
+    "test_runner/mock_screen_orientation_client.cc",
+    "test_runner/mock_screen_orientation_client.h",
+    "test_runner/mock_spell_check.cc",
+    "test_runner/mock_spell_check.h",
+    "test_runner/mock_web_document_subresource_filter.cc",
+    "test_runner/mock_web_document_subresource_filter.h",
+    "test_runner/pixel_dump.cc",
+    "test_runner/pixel_dump.h",
+    "test_runner/spell_check_client.cc",
+    "test_runner/spell_check_client.h",
+    "test_runner/test_interfaces.cc",
+    "test_runner/test_interfaces.h",
+    "test_runner/test_plugin.cc",
+    "test_runner/test_plugin.h",
+    "test_runner/test_preferences.cc",
+    "test_runner/test_preferences.h",
+    "test_runner/test_runner.cc",
+    "test_runner/test_runner.h",
+    "test_runner/test_runner_for_specific_view.cc",
+    "test_runner/test_runner_for_specific_view.h",
+    "test_runner/text_input_controller.cc",
+    "test_runner/text_input_controller.h",
+    "test_runner/tracked_dictionary.cc",
+    "test_runner/tracked_dictionary.h",
+    "test_runner/web_ax_object_proxy.cc",
+    "test_runner/web_ax_object_proxy.h",
+    "test_runner/web_frame_test_client.cc",
+    "test_runner/web_frame_test_client.h",
+    "test_runner/web_frame_test_proxy.cc",
+    "test_runner/web_frame_test_proxy.h",
+    "test_runner/web_test_delegate.h",
+    "test_runner/web_test_runtime_flags.cc",
+    "test_runner/web_test_runtime_flags.h",
+    "test_runner/web_view_test_proxy.cc",
+    "test_runner/web_view_test_proxy.h",
+    "test_runner/web_widget_test_proxy.cc",
+    "test_runner/web_widget_test_proxy.h",
   ]
   deps = [
+    ":client_hints_util",
     ":content_shell_lib",
     ":web_test_common",
+    "//base",
+    "//cc",
+    "//cc/paint",
     "//components/plugins/renderer",
+    "//components/viz/common",
     "//components/web_cache/renderer",
-    "//content/shell/test_runner",
+    "//content/public/common",
+    "//content/public/renderer",  # For component builds.
+    "//content/renderer:for_content_tests",  # For non-component builds.
     "//content/test:web_test_support_renderer",
+    "//device/gamepad/public/cpp:shared_with_blink",
+    "//device/gamepad/public/mojom",
+    "//gin",
+    "//gpu",
+    "//gpu/command_buffer/client:gles2_interface",
     "//media/capture",
+    "//printing",
+    "//services/device/public/mojom",
     "//skia",
     "//skia:test_fonts",
     "//third_party/blink/public:blink_headers",
     "//third_party/blink/public:test_headers",
+    "//ui/display",
+    "//ui/events:dom_keycode_converter",
+    "//ui/events:events_base",
+    "//ui/events/blink",
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//v8",
@@ -349,7 +428,6 @@
     "//content/gpu",
     "//content/public/common",
     "//content/public/common:service_names",
-    "//content/shell/test_runner:test_runner",
     "//content/test:blink_test_browser_support",
     "//content/test:content_test_mojo_bindings",
     "//content/test:mojo_web_test_bindings",
diff --git a/content/shell/browser/web_test/mock_client_hints_controller_delegate.cc b/content/shell/browser/web_test/mock_client_hints_controller_delegate.cc
index cf677b6..d07f21b0 100644
--- a/content/shell/browser/web_test/mock_client_hints_controller_delegate.cc
+++ b/content/shell/browser/web_test/mock_client_hints_controller_delegate.cc
@@ -28,10 +28,6 @@
   return true;
 }
 
-std::string MockClientHintsControllerDelegate::GetAcceptLanguageString() {
-  return content::GetShellLanguage();
-}
-
 blink::UserAgentMetadata
 MockClientHintsControllerDelegate::GetUserAgentMetadata() {
   return content::GetShellUserAgentMetadata();
diff --git a/content/shell/browser/web_test/mock_client_hints_controller_delegate.h b/content/shell/browser/web_test/mock_client_hints_controller_delegate.h
index 1691f0a..af5bc5b 100644
--- a/content/shell/browser/web_test/mock_client_hints_controller_delegate.h
+++ b/content/shell/browser/web_test/mock_client_hints_controller_delegate.h
@@ -28,8 +28,6 @@
 
   bool IsJavaScriptAllowed(const GURL& url) override;
 
-  std::string GetAcceptLanguageString() override;
-
   blink::UserAgentMetadata GetUserAgentMetadata() override;
   // mojom::ClientHints implementation.
   void PersistClientHints(
diff --git a/content/shell/browser/web_test/web_test_content_browser_client.cc b/content/shell/browser/web_test/web_test_content_browser_client.cc
index ac5c7ec..a10476a 100644
--- a/content/shell/browser/web_test/web_test_content_browser_client.cc
+++ b/content/shell/browser/web_test/web_test_content_browser_client.cc
@@ -528,4 +528,9 @@
 }
 #endif  // OS_WIN
 
+std::string WebTestContentBrowserClient::GetAcceptLangs(
+    BrowserContext* context) {
+  return content::GetShellLanguage();
+}
+
 }  // namespace content
diff --git a/content/shell/browser/web_test/web_test_content_browser_client.h b/content/shell/browser/web_test/web_test_content_browser_client.h
index a9d2520..b59e7c2 100644
--- a/content/shell/browser/web_test/web_test_content_browser_client.h
+++ b/content/shell/browser/web_test/web_test_content_browser_client.h
@@ -103,6 +103,7 @@
   bool PreSpawnRenderer(sandbox::TargetPolicy* policy,
                         RendererSpawnFlags flags) override;
 #endif
+  std::string GetAcceptLangs(BrowserContext* context) override;
 
  private:
   // ShellContentBrowserClient overrides.
diff --git a/content/shell/renderer/web_test/blink_test_helpers.cc b/content/shell/renderer/web_test/blink_test_helpers.cc
index 0ae1911..288125c 100644
--- a/content/shell/renderer/web_test/blink_test_helpers.cc
+++ b/content/shell/renderer/web_test/blink_test_helpers.cc
@@ -69,7 +69,7 @@
 
 namespace content {
 
-void ExportWebTestSpecificPreferences(const test_runner::TestPreferences& from,
+void ExportWebTestSpecificPreferences(const TestPreferences& from,
                                       WebPreferences* to) {
   to->javascript_can_access_clipboard = from.java_script_can_access_clipboard;
   to->editing_behavior = static_cast<EditingBehavior>(from.editing_behavior);
diff --git a/content/shell/renderer/web_test/blink_test_helpers.h b/content/shell/renderer/web_test/blink_test_helpers.h
index 1e03a35..18a0dd7 100644
--- a/content/shell/renderer/web_test/blink_test_helpers.h
+++ b/content/shell/renderer/web_test/blink_test_helpers.h
@@ -7,17 +7,14 @@
 
 #include "third_party/blink/public/platform/web_url.h"
 
-namespace test_runner {
-struct TestPreferences;
-}
-
 namespace content {
+struct TestPreferences;
 struct WebPreferences;
 
 // The TestRunner library keeps its settings in a TestPreferences object.
 // The content_shell, however, uses WebPreferences. This method exports the
 // settings from the TestRunner library which are relevant for web tests.
-void ExportWebTestSpecificPreferences(const test_runner::TestPreferences& from,
+void ExportWebTestSpecificPreferences(const TestPreferences& from,
                                       WebPreferences* to);
 
 // Replaces file:///tmp/web_tests/ with the actual path to the
diff --git a/content/shell/renderer/web_test/blink_test_runner.cc b/content/shell/renderer/web_test/blink_test_runner.cc
index 45a2c15..af3db20 100644
--- a/content/shell/renderer/web_test/blink_test_runner.cc
+++ b/content/shell/renderer/web_test/blink_test_runner.cc
@@ -49,6 +49,7 @@
 #include "content/shell/test_runner/pixel_dump.h"
 #include "content/shell/test_runner/test_interfaces.h"
 #include "content/shell/test_runner/test_runner.h"
+#include "content/shell/test_runner/web_frame_test_proxy.h"
 #include "content/shell/test_runner/web_widget_test_proxy.h"
 #include "ipc/ipc_sync_channel.h"
 #include "media/base/audio_capturer_source.h"
@@ -232,7 +233,7 @@
   return content::RewriteWebTestsURL(utf8_url, is_wpt_mode);
 }
 
-test_runner::TestPreferences* BlinkTestRunner::Preferences() {
+TestPreferences* BlinkTestRunner::Preferences() {
   return &prefs_;
 }
 
@@ -310,17 +311,12 @@
 
 std::unique_ptr<blink::WebInputEvent>
 BlinkTestRunner::TransformScreenToWidgetCoordinates(
-    test_runner::WebWidgetTestProxy* web_widget_test_proxy,
+    WebWidgetTestProxy* web_widget_test_proxy,
     const blink::WebInputEvent& event) {
   return content::TransformScreenToWidgetCoordinates(web_widget_test_proxy,
                                                      event);
 }
 
-test_runner::WebWidgetTestProxy* BlinkTestRunner::GetWebWidgetTestProxy(
-    blink::WebLocalFrame* frame) {
-  return content::GetWebWidgetTestProxy(frame);
-}
-
 void BlinkTestRunner::EnableUseZoomForDSF() {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableUseZoomForDSF);
@@ -407,7 +403,7 @@
   // Ignore changes that happen before we got the initial, accumulated
   // web flag changes in either OnReplicateTestConfiguration or
   // OnSetTestConfiguration.
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
   if (!interfaces->TestIsRunning())
     return;
@@ -416,9 +412,9 @@
 }
 
 void BlinkTestRunner::TestFinished() {
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
-  test_runner::TestRunner* test_runner = interfaces->GetTestRunner();
+  TestRunner* test_runner = interfaces->GetTestRunner();
 
   // We might get multiple TestFinished calls, ensure to only process the dump
   // once.
@@ -490,7 +486,7 @@
 
 void BlinkTestRunner::CaptureLocalAudioDump() {
   TRACE_EVENT0("shell", "BlinkTestRunner::CaptureLocalAudioDump");
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
   dump_result_->audio.emplace();
   interfaces->GetTestRunner()->GetAudioData(&*dump_result_->audio);
@@ -498,9 +494,9 @@
 
 void BlinkTestRunner::CaptureLocalLayoutDump() {
   TRACE_EVENT0("shell", "BlinkTestRunner::CaptureLocalLayoutDump");
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
-  test_runner::TestRunner* test_runner = interfaces->GetTestRunner();
+  TestRunner* test_runner = interfaces->GetTestRunner();
   std::string layout;
   if (test_runner->HasCustomTextDump(&layout)) {
     dump_result_->layout.emplace(layout + "\n");
@@ -524,7 +520,7 @@
 
   waiting_for_pixels_dump_result_ = true;
 
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
   interfaces->GetTestRunner()->DumpPixelsAsync(
       render_view(), base::BindOnce(&BlinkTestRunner::OnPixelsDumpCompleted,
@@ -622,7 +618,7 @@
 void BlinkTestRunner::DispatchBeforeInstallPromptEvent(
     const std::vector<std::string>& event_platforms,
     base::OnceCallback<void(bool)> callback) {
-  app_banner_service_.reset(new test_runner::AppBannerService());
+  app_banner_service_.reset(new AppBannerService());
   render_view()->GetMainRenderFrame()->BindLocalInterface(
       blink::mojom::AppBannerController::Name_,
       app_banner_service_->controller()
@@ -674,20 +670,14 @@
   prefs_.Reset();
   waiting_for_reset_ = false;
 
-  WebFrame* main_frame = render_view()->GetWebView()->MainFrame();
+  // TODO(danakj): Does any of this need to happen when for_new_test = false?
+  // If not, move to WebViewTestProxy::Reset() and WebFrameTestProxy::Reset().
 
   render_view()->ClearEditCommands();
-  if (for_new_test) {
-    if (main_frame->IsWebLocalFrame()) {
-      WebLocalFrame* local_main_frame = main_frame->ToWebLocalFrame();
-      local_main_frame->SetName(WebString());
-      GetWebWidgetTestProxy(local_main_frame)->EndSyntheticGestures();
-    }
-    main_frame->ClearOpener();
-  }
 
   // Resetting the internals object also overrides the WebPreferences, so we
   // have to sync them to WebKit again.
+  WebFrame* main_frame = render_view()->GetWebView()->MainFrame();
   if (main_frame->IsWebLocalFrame()) {
     WebTestingSupport::ResetInternalsObject(main_frame->ToWebLocalFrame());
     render_view()->SetWebkitPreferences(render_view()->GetWebkitPreferences());
@@ -774,7 +764,7 @@
   // |!is_main_window_|.
   is_secondary_window_ = true;
 
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
   interfaces->SetTestIsRunning(true);
   ForceResizeRenderView(render_view(), WebSize(800, 600));
@@ -782,7 +772,7 @@
 
 void BlinkTestRunner::ApplyTestConfiguration(
     mojom::ShellTestConfigurationPtr params) {
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
 
   test_config_ = params.Clone();
@@ -808,9 +798,9 @@
                         WebSize(local_params->initial_size.width(),
                                 local_params->initial_size.height()));
 
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
-  test_runner::TestRunner* test_runner = interfaces->GetTestRunner();
+  TestRunner* test_runner = interfaces->GetTestRunner();
   test_runner->SetFocus(render_view()->GetWebView(), true);
 }
 
@@ -839,7 +829,7 @@
 
   // Avoid a situation where TestFinished is called twice, because
   // of a racey test finish in 2 secondary renderers.
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
   if (!interfaces->TestIsRunning())
     return;
diff --git a/content/shell/renderer/web_test/blink_test_runner.h b/content/shell/renderer/web_test/blink_test_runner.h
index 1b87634..2d206a6 100644
--- a/content/shell/renderer/web_test/blink_test_runner.h
+++ b/content/shell/renderer/web_test/blink_test_runner.h
@@ -36,18 +36,15 @@
 class WebView;
 }  // namespace blink
 
-namespace test_runner {
-class AppBannerService;
-}  // namespace test_runner
-
 namespace content {
+class AppBannerService;
 
 // This is the renderer side of the webkit test runner.
 // TODO(lukasza): Rename to WebTestRenderViewObserver for consistency with
 // WebTestRenderFrameObserver.
 class BlinkTestRunner : public RenderViewObserver,
                         public RenderViewObserverTracker<BlinkTestRunner>,
-                        public test_runner::WebTestDelegate {
+                        public WebTestDelegate {
  public:
   explicit BlinkTestRunner(RenderView* render_view);
   ~BlinkTestRunner() override;
@@ -70,7 +67,7 @@
       const std::string& utf8_path) override;
   blink::WebURL RewriteWebTestsURL(const std::string& utf8_url,
                                    bool is_wpt_mode) override;
-  test_runner::TestPreferences* Preferences() override;
+  TestPreferences* Preferences() override;
   void ApplyPreferences() override;
   void SetPopupBlockingEnabled(bool block_popups) override;
   void UseUnfortunateSynchronousResizeMode(bool enable) override;
@@ -92,10 +89,8 @@
   void SetDeviceScaleFactor(float factor) override;
   void SetDeviceColorSpace(const std::string& name) override;
   std::unique_ptr<blink::WebInputEvent> TransformScreenToWidgetCoordinates(
-      test_runner::WebWidgetTestProxy* web_widget_test_proxy,
+      WebWidgetTestProxy* web_widget_test_proxy,
       const blink::WebInputEvent& event) override;
-  test_runner::WebWidgetTestProxy* GetWebWidgetTestProxy(
-      blink::WebLocalFrame* frame) override;
   void EnableUseZoomForDSF() override;
   bool IsUseZoomForDSFEnabled() override;
   void SetBluetoothFakeAdapter(const std::string& adapter_name,
@@ -190,7 +185,7 @@
   mojo::AssociatedRemote<mojom::WebTestClient>& GetWebTestClientRemote();
   mojo::AssociatedRemote<mojom::WebTestClient> web_test_client_remote_;
 
-  test_runner::TestPreferences prefs_;
+  TestPreferences prefs_;
 
   mojom::ShellTestConfigurationPtr test_config_;
 
@@ -203,7 +198,7 @@
 
   bool waiting_for_reset_ = false;
 
-  std::unique_ptr<test_runner::AppBannerService> app_banner_service_;
+  std::unique_ptr<AppBannerService> app_banner_service_;
 
   mojom::BlinkTestControl::CaptureDumpCallback dump_callback_;
   mojom::BlinkTestDumpPtr dump_result_;
diff --git a/content/shell/renderer/web_test/web_test_render_frame_observer.cc b/content/shell/renderer/web_test/web_test_render_frame_observer.cc
index 4e1271d..7d1b969 100644
--- a/content/shell/renderer/web_test/web_test_render_frame_observer.cc
+++ b/content/shell/renderer/web_test/web_test_render_frame_observer.cc
@@ -25,10 +25,9 @@
 WebTestRenderFrameObserver::WebTestRenderFrameObserver(
     RenderFrame* render_frame)
     : RenderFrameObserver(render_frame) {
-  test_runner::TestRunner* test_runner =
-      WebTestRenderThreadObserver::GetInstance()
-          ->test_interfaces()
-          ->GetTestRunner();
+  TestRunner* test_runner = WebTestRenderThreadObserver::GetInstance()
+                                ->test_interfaces()
+                                ->GetTestRunner();
   render_frame->GetWebFrame()->SetContentSettingsClient(
       test_runner->GetWebContentSettings());
   render_frame->GetWebFrame()->SetTextCheckClient(
@@ -78,9 +77,9 @@
 
 void WebTestRenderFrameObserver::DumpFrameLayout(
     DumpFrameLayoutCallback callback) {
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
-  test_runner::TestRunner* test_runner = interfaces->GetTestRunner();
+  TestRunner* test_runner = interfaces->GetTestRunner();
   std::string dump = test_runner->DumpLayout(render_frame()->GetWebFrame());
   std::move(callback).Run(std::move(dump));
 }
diff --git a/content/shell/renderer/web_test/web_test_render_thread_observer.cc b/content/shell/renderer/web_test/web_test_render_thread_observer.cc
index 49b5533..d3dc66a3 100644
--- a/content/shell/renderer/web_test/web_test_render_thread_observer.cc
+++ b/content/shell/renderer/web_test/web_test_render_thread_observer.cc
@@ -32,7 +32,7 @@
   EnableRendererWebTestMode();
   blink::SetWebTestMode(true);
 
-  test_interfaces_ = std::make_unique<test_runner::TestInterfaces>();
+  test_interfaces_ = std::make_unique<TestInterfaces>();
   test_interfaces_->ResetAll();
 }
 
diff --git a/content/shell/renderer/web_test/web_test_render_thread_observer.h b/content/shell/renderer/web_test/web_test_render_thread_observer.h
index 3e58bfd5..66312321 100644
--- a/content/shell/renderer/web_test/web_test_render_thread_observer.h
+++ b/content/shell/renderer/web_test/web_test_render_thread_observer.h
@@ -13,11 +13,8 @@
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
 
-namespace test_runner {
-class TestInterfaces;
-}
-
 namespace content {
+class TestInterfaces;
 
 class WebTestRenderThreadObserver : public RenderThreadObserver,
                                     public mojom::WebTestControl {
@@ -27,9 +24,7 @@
   WebTestRenderThreadObserver();
   ~WebTestRenderThreadObserver() override;
 
-  test_runner::TestInterfaces* test_interfaces() const {
-    return test_interfaces_.get();
-  }
+  TestInterfaces* test_interfaces() const { return test_interfaces_.get(); }
 
   // content::RenderThreadObserver:
   void RegisterMojoInterfaces(
@@ -46,7 +41,7 @@
   void OnWebTestControlAssociatedRequest(
       mojo::PendingAssociatedReceiver<mojom::WebTestControl> receiver);
 
-  std::unique_ptr<test_runner::TestInterfaces> test_interfaces_;
+  std::unique_ptr<TestInterfaces> test_interfaces_;
 
   mojo::AssociatedReceiver<mojom::WebTestControl> receiver_{this};
 
diff --git a/content/shell/test_runner/BUILD.gn b/content/shell/test_runner/BUILD.gn
deleted file mode 100644
index 401e4e7..0000000
--- a/content/shell/test_runner/BUILD.gn
+++ /dev/null
@@ -1,123 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/features.gni")
-import("//build/config/jumbo.gni")
-import("//build/config/ui.gni")
-if (is_android) {
-  import("//build/config/android/config.gni")
-}
-
-jumbo_component("test_runner") {
-  testonly = true
-
-  # See comment at the top of //content/BUILD.gn for why this is disabled in
-  # component builds.
-  if (is_component_build) {
-    check_includes = false
-  }
-
-  defines = [ "TEST_RUNNER_IMPLEMENTATION" ]
-
-  sources = [
-    "accessibility_controller.cc",
-    "accessibility_controller.h",
-    "app_banner_service.cc",
-    "app_banner_service.h",
-    "event_sender.cc",
-    "event_sender.h",
-    "gamepad_controller.cc",
-    "gamepad_controller.h",
-    "gc_controller.cc",
-    "gc_controller.h",
-    "layout_dump.cc",
-    "layout_dump.h",
-    "mock_content_settings_client.cc",
-    "mock_content_settings_client.h",
-    "mock_grammar_check.cc",
-    "mock_grammar_check.h",
-    "mock_screen_orientation_client.cc",
-    "mock_screen_orientation_client.h",
-    "mock_spell_check.cc",
-    "mock_spell_check.h",
-    "mock_web_document_subresource_filter.cc",
-    "mock_web_document_subresource_filter.h",
-    "pixel_dump.cc",
-    "pixel_dump.h",
-    "spell_check_client.cc",
-    "spell_check_client.h",
-    "test_interfaces.cc",
-    "test_interfaces.h",
-    "test_plugin.cc",
-    "test_plugin.h",
-    "test_preferences.cc",
-    "test_preferences.h",
-    "test_runner.cc",
-    "test_runner.h",
-    "test_runner_export.h",
-    "test_runner_for_specific_view.cc",
-    "test_runner_for_specific_view.h",
-    "text_input_controller.cc",
-    "text_input_controller.h",
-    "tracked_dictionary.cc",
-    "tracked_dictionary.h",
-    "web_ax_object_proxy.cc",
-    "web_ax_object_proxy.h",
-    "web_frame_test_client.cc",
-    "web_frame_test_client.h",
-    "web_frame_test_proxy.cc",
-    "web_frame_test_proxy.h",
-    "web_test_delegate.h",
-    "web_test_runtime_flags.cc",
-    "web_test_runtime_flags.h",
-    "web_view_test_proxy.cc",
-    "web_view_test_proxy.h",
-    "web_widget_test_proxy.cc",
-    "web_widget_test_proxy.h",
-  ]
-
-  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
-  deps = [
-    "//base:base",
-    "//base:i18n",
-    "//cc",
-    "//cc/paint",
-    "//components/viz/common",
-    "//content/public/common",
-    "//content/public/common:client_hints_mojom",
-    "//content/public/common:service_names",
-    "//content/public/renderer",
-    "//content/renderer:for_content_tests",
-    "//content/shell:client_hints_util",
-    "//content/shell:web_test_common",
-    "//device/base/synchronization",
-    "//device/gamepad/public/cpp:shared_with_blink",
-    "//device/gamepad/public/mojom",
-    "//gin",
-    "//gpu",
-    "//gpu/command_buffer/client:gles2_interface",
-    "//media/midi:mojo",
-    "//net",
-    "//printing",
-    "//services/device/public/mojom",
-    "//skia",
-    "//third_party/blink/public:blink",
-    "//third_party/blink/public:test_support",
-    "//ui/display",
-    "//ui/events:dom_keycode_converter",
-    "//ui/events:events_base",
-    "//ui/events/blink",
-    "//ui/gfx",
-    "//ui/gfx:test_support",
-    "//ui/gfx/geometry",
-    "//url",
-    "//v8",
-  ]
-
-  if (is_mac) {
-    libs = [ "AppKit.framework" ]
-  }
-}
diff --git a/content/shell/test_runner/accessibility_controller.cc b/content/shell/test_runner/accessibility_controller.cc
index 6ad5b4b..bc355ca4 100644
--- a/content/shell/test_runner/accessibility_controller.cc
+++ b/content/shell/test_runner/accessibility_controller.cc
@@ -21,7 +21,7 @@
 #include "third_party/blink/public/web/web_settings.h"
 #include "third_party/blink/public/web/web_view.h"
 
-namespace test_runner {
+namespace content {
 
 class AccessibilityControllerBindings
     : public gin::Wrappable<AccessibilityControllerBindings> {
@@ -307,4 +307,4 @@
       web_view()->MainFrame()->ToWebLocalFrame()->GetDocument());
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/accessibility_controller.h b/content/shell/test_runner/accessibility_controller.h
index 45a8a80..4fbc9f23 100644
--- a/content/shell/test_runner/accessibility_controller.h
+++ b/content/shell/test_runner/accessibility_controller.h
@@ -9,7 +9,6 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "content/shell/test_runner/web_ax_object_proxy.h"
 #include "third_party/blink/public/web/web_ax_object.h"
 #include "v8/include/v8.h"
@@ -21,11 +20,11 @@
 class WebView;
 }
 
-namespace test_runner {
+namespace content {
 
 class WebViewTestProxy;
 
-class TEST_RUNNER_EXPORT AccessibilityController {
+class AccessibilityController {
  public:
   explicit AccessibilityController(WebViewTestProxy* web_view_test_proxy);
   ~AccessibilityController();
@@ -72,6 +71,6 @@
   DISALLOW_COPY_AND_ASSIGN(AccessibilityController);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_ACCESSIBILITY_CONTROLLER_H_
diff --git a/content/shell/test_runner/app_banner_service.cc b/content/shell/test_runner/app_banner_service.cc
index 21c8696..b787180 100644
--- a/content/shell/test_runner/app_banner_service.cc
+++ b/content/shell/test_runner/app_banner_service.cc
@@ -5,7 +5,7 @@
 #include "content/shell/test_runner/app_banner_service.h"
 #include "base/bind.h"
 
-namespace test_runner {
+namespace content {
 
 AppBannerService::AppBannerService() = default;
 
@@ -44,4 +44,4 @@
   std::move(callback).Run(reply == blink::mojom::AppBannerPromptReply::CANCEL);
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/app_banner_service.h b/content/shell/test_runner/app_banner_service.h
index 5f39667b..084df15 100644
--- a/content/shell/test_runner/app_banner_service.h
+++ b/content/shell/test_runner/app_banner_service.h
@@ -10,17 +10,15 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/public/mojom/app_banner/app_banner.mojom.h"
 
-namespace test_runner {
+namespace content {
 
 // Test app banner service that is registered as a Mojo service for
 // BeforeInstallPromptEvents to look up when the test runner is executed.
-class TEST_RUNNER_EXPORT AppBannerService
-    : public blink::mojom::AppBannerService {
+class AppBannerService : public blink::mojom::AppBannerService {
  public:
   AppBannerService();
   ~AppBannerService() override;
@@ -46,6 +44,6 @@
   DISALLOW_COPY_AND_ASSIGN(AppBannerService);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_APP_BANNER_SERVICE_H_
diff --git a/content/shell/test_runner/event_sender.cc b/content/shell/test_runner/event_sender.cc
index 25ccc5e..521ccc4e 100644
--- a/content/shell/test_runner/event_sender.cc
+++ b/content/shell/test_runner/event_sender.cc
@@ -76,7 +76,7 @@
 using blink::WebVector;
 using blink::WebView;
 
-namespace test_runner {
+namespace content {
 
 namespace {
 
@@ -2886,4 +2886,4 @@
                             blink::DocumentUpdateReason::kTest);
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/event_sender.h b/content/shell/test_runner/event_sender.h
index 566b9ca..b345459 100644
--- a/content/shell/test_runner/event_sender.h
+++ b/content/shell/test_runner/event_sender.h
@@ -17,7 +17,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
 #include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
 #include "third_party/blink/public/common/input/web_touch_point.h"
@@ -38,7 +37,7 @@
 class Arguments;
 }  // namespace gin
 
-namespace test_runner {
+namespace content {
 
 class TestInterfaces;
 class WebWidgetTestProxy;
@@ -53,7 +52,7 @@
   DOMKeyLocationNumpad = 0x03
 };
 
-class TEST_RUNNER_EXPORT EventSender {
+class EventSender {
  public:
   explicit EventSender(WebWidgetTestProxy*);
   virtual ~EventSender();
@@ -328,6 +327,6 @@
   DISALLOW_COPY_AND_ASSIGN(EventSender);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_EVENT_SENDER_H_
diff --git a/content/shell/test_runner/gamepad_controller.cc b/content/shell/test_runner/gamepad_controller.cc
index 0e3999d..cb50990 100644
--- a/content/shell/test_runner/gamepad_controller.cc
+++ b/content/shell/test_runner/gamepad_controller.cc
@@ -25,7 +25,7 @@
 using device::Gamepad;
 using device::Gamepads;
 
-namespace test_runner {
+namespace content {
 
 namespace {
 
@@ -414,4 +414,4 @@
   gamepads_->seqlock.WriteEnd();
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/gamepad_controller.h b/content/shell/test_runner/gamepad_controller.h
index 1efdcbda..3b76aab 100644
--- a/content/shell/test_runner/gamepad_controller.h
+++ b/content/shell/test_runner/gamepad_controller.h
@@ -13,7 +13,6 @@
 #include "base/macros.h"
 #include "base/memory/read_only_shared_memory_region.h"
 #include "base/memory/weak_ptr.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "device/gamepad/public/cpp/gamepads.h"
 #include "device/gamepad/public/mojom/gamepad.mojom.h"
 #include "device/gamepad/public/mojom/gamepad_hardware_buffer.h"
@@ -25,10 +24,9 @@
 class WebLocalFrame;
 }
 
-namespace test_runner {
+namespace content {
 
-class TEST_RUNNER_EXPORT GamepadController
-    : public base::SupportsWeakPtr<GamepadController> {
+class GamepadController : public base::SupportsWeakPtr<GamepadController> {
  public:
   GamepadController();
   ~GamepadController();
@@ -104,6 +102,6 @@
   DISALLOW_COPY_AND_ASSIGN(GamepadController);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_GAMEPAD_CONTROLLER_H_
diff --git a/content/shell/test_runner/gc_controller.cc b/content/shell/test_runner/gc_controller.cc
index ec6d4030..9224725a 100644
--- a/content/shell/test_runner/gc_controller.cc
+++ b/content/shell/test_runner/gc_controller.cc
@@ -14,7 +14,7 @@
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "v8/include/v8.h"
 
-namespace test_runner {
+namespace content {
 
 gin::WrapperInfo GCController::kWrapperInfo = {gin::kEmbedderNativeGin};
 
@@ -110,4 +110,4 @@
       v8::Isolate::kMinorGarbageCollection);
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/gc_controller.h b/content/shell/test_runner/gc_controller.h
index 4185ef4..d4ce9677 100644
--- a/content/shell/test_runner/gc_controller.h
+++ b/content/shell/test_runner/gc_controller.h
@@ -16,7 +16,7 @@
 class Arguments;
 }
 
-namespace test_runner {
+namespace content {
 
 class TestInterfaces;
 
@@ -54,6 +54,6 @@
   DISALLOW_COPY_AND_ASSIGN(GCController);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_GC_CONTROLLER_H_
diff --git a/content/shell/test_runner/layout_dump.cc b/content/shell/test_runner/layout_dump.cc
index ce571a4..5a1b6507 100644
--- a/content/shell/test_runner/layout_dump.cc
+++ b/content/shell/test_runner/layout_dump.cc
@@ -15,7 +15,7 @@
 #include "third_party/blink/public/web/web_frame_content_dumper.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 
-namespace test_runner {
+namespace content {
 
 using blink::WebFrame;
 using blink::WebFrameContentDumper;
@@ -56,7 +56,8 @@
 
 }  // namespace
 
-std::string DumpLayout(WebLocalFrame* frame, const WebTestRuntimeFlags& flags) {
+std::string DumpLayoutAsString(WebLocalFrame* frame,
+                               const WebTestRuntimeFlags& flags) {
   DCHECK(frame);
   std::string result;
 
@@ -85,4 +86,4 @@
   return result;
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/layout_dump.h b/content/shell/test_runner/layout_dump.h
index 06c820a..0ecafe99 100644
--- a/content/shell/test_runner/layout_dump.h
+++ b/content/shell/test_runner/layout_dump.h
@@ -7,20 +7,19 @@
 
 #include <string>
 
-#include "content/shell/test_runner/test_runner_export.h"
 #include "content/shell/test_runner/web_test_runtime_flags.h"
 
 namespace blink {
 class WebLocalFrame;
 }  // namespace blink
 
-namespace test_runner {
+namespace content {
 
 // Dumps textual representation of |frame| contents.  Exact dump mode depends
 // on |flags| (i.e. dump_as_text VS dump_as_markup and/or is_printing).
-TEST_RUNNER_EXPORT std::string DumpLayout(blink::WebLocalFrame* frame,
-                                          const WebTestRuntimeFlags& flags);
+std::string DumpLayoutAsString(blink::WebLocalFrame* frame,
+                               const WebTestRuntimeFlags& flags);
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_LAYOUT_DUMP_H_
diff --git a/content/shell/test_runner/mock_content_settings_client.cc b/content/shell/test_runner/mock_content_settings_client.cc
index 2a82675..2c59651a 100644
--- a/content/shell/test_runner/mock_content_settings_client.cc
+++ b/content/shell/test_runner/mock_content_settings_client.cc
@@ -13,7 +13,7 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_url.h"
 
-namespace test_runner {
+namespace content {
 
 MockContentSettingsClient::MockContentSettingsClient(
     WebTestRuntimeFlags* web_test_runtime_flags)
@@ -126,4 +126,4 @@
   client_hints_map_.clear();
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/mock_content_settings_client.h b/content/shell/test_runner/mock_content_settings_client.h
index a014ae4..5d12490 100644
--- a/content/shell/test_runner/mock_content_settings_client.h
+++ b/content/shell/test_runner/mock_content_settings_client.h
@@ -16,7 +16,7 @@
 #include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "url/origin.h"
 
-namespace test_runner {
+namespace content {
 
 class WebTestDelegate;
 class WebTestRuntimeFlags;
@@ -61,6 +61,6 @@
   DISALLOW_COPY_AND_ASSIGN(MockContentSettingsClient);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_MOCK_CONTENT_SETTINGS_CLIENT_H_
diff --git a/content/shell/test_runner/mock_grammar_check.cc b/content/shell/test_runner/mock_grammar_check.cc
index 04e1fe9d..140bb52 100644
--- a/content/shell/test_runner/mock_grammar_check.cc
+++ b/content/shell/test_runner/mock_grammar_check.cc
@@ -22,7 +22,7 @@
 
 }  // namespace
 
-namespace test_runner {
+namespace content {
 
 bool MockGrammarCheck::CheckGrammarOfString(
     const blink::WebString& text,
@@ -69,4 +69,4 @@
   return false;
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/mock_grammar_check.h b/content/shell/test_runner/mock_grammar_check.h
index 4e80de7..38f86280 100644
--- a/content/shell/test_runner/mock_grammar_check.h
+++ b/content/shell/test_runner/mock_grammar_check.h
@@ -12,7 +12,7 @@
 struct WebTextCheckingResult;
 }
 
-namespace test_runner {
+namespace content {
 
 // A mock implementation of a grammar-checker used for WebKit tests. This class
 // only implements the minimal functionarities required by WebKit tests, i.e.
@@ -25,6 +25,6 @@
                                    std::vector<blink::WebTextCheckingResult>*);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_MOCK_GRAMMAR_CHECK_H_
diff --git a/content/shell/test_runner/mock_screen_orientation_client.cc b/content/shell/test_runner/mock_screen_orientation_client.cc
index ae8e261..1db1629 100644
--- a/content/shell/test_runner/mock_screen_orientation_client.cc
+++ b/content/shell/test_runner/mock_screen_orientation_client.cc
@@ -15,7 +15,7 @@
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 
-namespace test_runner {
+namespace content {
 
 MockScreenOrientationClient::MockScreenOrientationClient()
     : main_frame_(nullptr),
@@ -195,4 +195,4 @@
   }
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/mock_screen_orientation_client.h b/content/shell/test_runner/mock_screen_orientation_client.h
index 0569eb92..a9e1b909 100644
--- a/content/shell/test_runner/mock_screen_orientation_client.h
+++ b/content/shell/test_runner/mock_screen_orientation_client.h
@@ -9,7 +9,6 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "mojo/public/cpp/bindings/associated_receiver_set.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 #include "services/device/public/mojom/screen_orientation.mojom.h"
@@ -20,10 +19,9 @@
 class WebLocalFrame;
 }
 
-namespace test_runner {
+namespace content {
 
-class TEST_RUNNER_EXPORT MockScreenOrientationClient
-    : public device::mojom::ScreenOrientation {
+class MockScreenOrientationClient : public device::mojom::ScreenOrientation {
  public:
   explicit MockScreenOrientationClient();
   ~MockScreenOrientationClient() override;
@@ -65,6 +63,6 @@
   DISALLOW_COPY_AND_ASSIGN(MockScreenOrientationClient);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_MOCK_SCREEN_ORIENTATION_CLIENT_H_
diff --git a/content/shell/test_runner/mock_spell_check.cc b/content/shell/test_runner/mock_spell_check.cc
index 350ab29..cf43c94 100644
--- a/content/shell/test_runner/mock_spell_check.cc
+++ b/content/shell/test_runner/mock_spell_check.cc
@@ -12,7 +12,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 
-namespace test_runner {
+namespace content {
 
 namespace {
 
@@ -179,4 +179,4 @@
   return false;
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/mock_spell_check.h b/content/shell/test_runner/mock_spell_check.h
index 3bf8dadf..05d5036 100644
--- a/content/shell/test_runner/mock_spell_check.h
+++ b/content/shell/test_runner/mock_spell_check.h
@@ -12,7 +12,7 @@
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/public/web/web_text_checking_result.h"
 
-namespace test_runner {
+namespace content {
 
 // A mock implementation of a spell-checker used for WebKit tests.
 // This class only implements the minimal functionalities required by WebKit
@@ -70,6 +70,6 @@
   DISALLOW_COPY_AND_ASSIGN(MockSpellCheck);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_MOCK_SPELL_CHECK_H_
diff --git a/content/shell/test_runner/mock_web_document_subresource_filter.cc b/content/shell/test_runner/mock_web_document_subresource_filter.cc
index 30a304ef..4362230 100644
--- a/content/shell/test_runner/mock_web_document_subresource_filter.cc
+++ b/content/shell/test_runner/mock_web_document_subresource_filter.cc
@@ -10,7 +10,7 @@
 #include "third_party/blink/public/platform/web_url.h"
 #include "url/gurl.h"
 
-namespace test_runner {
+namespace content {
 
 MockWebDocumentSubresourceFilter::MockWebDocumentSubresourceFilter(
     const std::vector<std::string>& disallowed_path_suffixes,
@@ -52,4 +52,4 @@
   return true;
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/mock_web_document_subresource_filter.h b/content/shell/test_runner/mock_web_document_subresource_filter.h
index fb419de3..a64b1ea7 100644
--- a/content/shell/test_runner/mock_web_document_subresource_filter.h
+++ b/content/shell/test_runner/mock_web_document_subresource_filter.h
@@ -16,7 +16,7 @@
 class WebURL;
 }  // namespace blink
 
-namespace test_runner {
+namespace content {
 
 class MockWebDocumentSubresourceFilter
     : public blink::WebDocumentSubresourceFilter {
@@ -42,6 +42,6 @@
   DISALLOW_COPY_AND_ASSIGN(MockWebDocumentSubresourceFilter);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_MOCK_WEB_DOCUMENT_SUBRESOURCE_FILTER_H_
diff --git a/content/shell/test_runner/pixel_dump.cc b/content/shell/test_runner/pixel_dump.cc
index bc72738..1aec94b 100644
--- a/content/shell/test_runner/pixel_dump.cc
+++ b/content/shell/test_runner/pixel_dump.cc
@@ -38,7 +38,7 @@
 #include "third_party/blink/public/web/web_widget.h"
 #include "ui/gfx/geometry/point.h"
 
-namespace test_runner {
+namespace content {
 
 namespace {
 
@@ -112,4 +112,4 @@
   std::move(callback).Run(bitmap);
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/pixel_dump.h b/content/shell/test_runner/pixel_dump.h
index 3df6b52f7..5c7ff7b 100644
--- a/content/shell/test_runner/pixel_dump.h
+++ b/content/shell/test_runner/pixel_dump.h
@@ -13,7 +13,7 @@
 class WebLocalFrame;
 }  // namespace blink
 
-namespace test_runner {
+namespace content {
 
 // Asks |web_frame| to print itself and calls |callback| with the result.
 void PrintFrameAsync(blink::WebLocalFrame* web_frame,
@@ -27,6 +27,6 @@
     int y,
     base::OnceCallback<void(const SkBitmap&)> callback);
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_PIXEL_DUMP_H_
diff --git a/content/shell/test_runner/spell_check_client.cc b/content/shell/test_runner/spell_check_client.cc
index d6b3b81..c834b06d 100644
--- a/content/shell/test_runner/spell_check_client.cc
+++ b/content/shell/test_runner/spell_check_client.cc
@@ -18,7 +18,7 @@
 #include "third_party/blink/public/web/web_text_checking_completion.h"
 #include "third_party/blink/public/web/web_text_checking_result.h"
 
-namespace test_runner {
+namespace content {
 
 SpellCheckClient::SpellCheckClient(TestRunner* test_runner)
     : last_requested_text_checking_completion_(nullptr),
@@ -158,4 +158,4 @@
       context->Global(), 0, nullptr);
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/spell_check_client.h b/content/shell/test_runner/spell_check_client.h
index 3935b82..37ac0c2 100644
--- a/content/shell/test_runner/spell_check_client.h
+++ b/content/shell/test_runner/spell_check_client.h
@@ -19,7 +19,7 @@
 class WebTextCheckingCompletion;
 }  // namespace blink
 
-namespace test_runner {
+namespace content {
 
 class TestRunner;
 class WebTestDelegate;
@@ -77,6 +77,6 @@
   DISALLOW_COPY_AND_ASSIGN(SpellCheckClient);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_SPELL_CHECK_CLIENT_H_
diff --git a/content/shell/test_runner/test_interfaces.cc b/content/shell/test_runner/test_interfaces.cc
index d169ad8c..65e1d40 100644
--- a/content/shell/test_runner/test_interfaces.cc
+++ b/content/shell/test_runner/test_interfaces.cc
@@ -23,7 +23,7 @@
 #include "third_party/blink/public/web/blink.h"
 #include "third_party/blink/public/web/web_view.h"
 
-namespace test_runner {
+namespace content {
 
 TestInterfaces::TestInterfaces()
     : gamepad_controller_(new GamepadController()),
@@ -160,4 +160,4 @@
   return window_list_;
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/test_interfaces.h b/content/shell/test_runner/test_interfaces.h
index 4e79d499..d674b770b 100644
--- a/content/shell/test_runner/test_interfaces.h
+++ b/content/shell/test_runner/test_interfaces.h
@@ -10,7 +10,6 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "content/shell/test_runner/test_runner_export.h"
 
 namespace blink {
 class WebLocalFrame;
@@ -18,13 +17,13 @@
 class WebView;
 }
 
-namespace test_runner {
+namespace content {
 class GamepadController;
 class TestRunner;
 class WebTestDelegate;
 class WebViewTestProxy;
 
-class TEST_RUNNER_EXPORT TestInterfaces {
+class TestInterfaces {
  public:
   TestInterfaces();
   ~TestInterfaces();
@@ -64,6 +63,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestInterfaces);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_TEST_INTERFACES_H_
diff --git a/content/shell/test_runner/test_plugin.cc b/content/shell/test_runner/test_plugin.cc
index 397ab5c..60a572a 100644
--- a/content/shell/test_runner/test_plugin.cc
+++ b/content/shell/test_runner/test_plugin.cc
@@ -43,7 +43,7 @@
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/core/SkPath.h"
 
-namespace test_runner {
+namespace content {
 
 namespace {
 
@@ -647,4 +647,4 @@
          mime_type == PluginPersistsMimeType();
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/test_plugin.h b/content/shell/test_runner/test_plugin.h
index 1525b6d..b177330 100644
--- a/content/shell/test_runner/test_plugin.h
+++ b/content/shell/test_runner/test_plugin.h
@@ -42,7 +42,7 @@
 struct TransferableResource;
 }
 
-namespace test_runner {
+namespace content {
 
 class TestInterfaces;
 
@@ -198,6 +198,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestPlugin);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_TEST_PLUGIN_H_
diff --git a/content/shell/test_runner/test_preferences.cc b/content/shell/test_runner/test_preferences.cc
index 5729fa3..9c63240e 100644
--- a/content/shell/test_runner/test_preferences.cc
+++ b/content/shell/test_runner/test_preferences.cc
@@ -9,7 +9,7 @@
 using blink::WebSettings;
 using blink::WebString;
 
-namespace test_runner {
+namespace content {
 
 TestPreferences::TestPreferences() {
   Reset();
@@ -47,4 +47,4 @@
   spatial_navigation_enabled = false;
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/test_preferences.h b/content/shell/test_runner/test_preferences.h
index 318f5566..9603a6b8 100644
--- a/content/shell/test_runner/test_preferences.h
+++ b/content/shell/test_runner/test_preferences.h
@@ -5,14 +5,13 @@
 #ifndef CONTENT_SHELL_TEST_RUNNER_TEST_PREFERENCES_H_
 #define CONTENT_SHELL_TEST_RUNNER_TEST_PREFERENCES_H_
 
-#include "content/shell/test_runner/test_runner_export.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/web/web_settings.h"
 
-namespace test_runner {
+namespace content {
 
-struct TEST_RUNNER_EXPORT TestPreferences {
+struct TestPreferences {
   int default_font_size;
   int minimum_font_size;
   bool allow_file_access_from_file_urls;
@@ -40,6 +39,6 @@
   TestPreferences();
   void Reset();
 };
-}
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_TEST_PREFERENCES_H_
diff --git a/content/shell/test_runner/test_runner.cc b/content/shell/test_runner/test_runner.cc
index 93c83de7..ff84d5f 100644
--- a/content/shell/test_runner/test_runner.cc
+++ b/content/shell/test_runner/test_runner.cc
@@ -66,7 +66,7 @@
 #include "third_party/blink/public/platform/web_font_render_style.h"
 #endif
 
-namespace test_runner {
+namespace content {
 
 namespace {
 
@@ -1656,7 +1656,7 @@
 
 std::string TestRunner::DumpLayout(blink::WebLocalFrame* frame) {
   CheckResponseMimeType();
-  return ::test_runner::DumpLayout(frame, web_test_runtime_flags_);
+  return DumpLayoutAsString(frame, web_test_runtime_flags_);
 }
 
 bool TestRunner::CanDumpPixelsFromRenderer() const {
@@ -1695,7 +1695,7 @@
     if (frame_to_print && frame_to_print->IsWebLocalFrame())
       target_frame = frame_to_print->ToWebLocalFrame();
   }
-  test_runner::PrintFrameAsync(target_frame, std::move(callback));
+  PrintFrameAsync(target_frame, std::move(callback));
 }
 
 void TestRunner::ReplicateWebTestRuntimeFlagsChanges(
@@ -2615,4 +2615,4 @@
   OnWebTestRuntimeFlagsChanged();
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/test_runner.h b/content/shell/test_runner/test_runner.h
index 27dfe7a..40cfe63 100644
--- a/content/shell/test_runner/test_runner.h
+++ b/content/shell/test_runner/test_runner.h
@@ -20,7 +20,6 @@
 #include "base/optional.h"
 #include "base/strings/string16.h"
 #include "content/shell/test_runner/mock_screen_orientation_client.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "content/shell/test_runner/web_test_runtime_flags.h"
 #include "third_party/blink/public/platform/web_effective_connection_type.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -51,7 +50,7 @@
 class Arguments;
 }
 
-namespace test_runner {
+namespace content {
 class MockContentSettingsClient;
 class MockScreenOrientationClient;
 class SpellCheckClient;
@@ -72,7 +71,7 @@
 //    - Tracking topLoadingFrame that can finish the test when it loads.
 //    - WorkQueue holding load requests from the TestInterfaces
 //    - WebTestRuntimeFlags
-class TEST_RUNNER_EXPORT TestRunner {
+class TestRunner {
  public:
   explicit TestRunner(TestInterfaces*);
   virtual ~TestRunner();
@@ -671,6 +670,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestRunner);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_TEST_RUNNER_H_
diff --git a/content/shell/test_runner/test_runner_export.h b/content/shell/test_runner/test_runner_export.h
deleted file mode 100644
index 3f7336f2..0000000
--- a/content/shell/test_runner/test_runner_export.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_SHELL_TEST_RUNNER_TEST_RUNNER_EXPORT_H_
-#define CONTENT_SHELL_TEST_RUNNER_TEST_RUNNER_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(TEST_RUNNER_IMPLEMENTATION)
-#define TEST_RUNNER_EXPORT __declspec(dllexport)
-#else
-#define TEST_RUNNER_EXPORT __declspec(dllimport)
-#endif  // defined(TEST_RUNNER_IMPLEMENTATION)
-
-#else  // defined(WIN32)
-#if defined(TEST_RUNNER_IMPLEMENTATION)
-#define TEST_RUNNER_EXPORT __attribute__((visibility("default")))
-#else
-#define TEST_RUNNER_EXPORT
-#endif
-#endif
-
-#else  // defined(COMPONENT_BUILD)
-#define TEST_RUNNER_EXPORT
-#endif
-
-#endif  // CONTENT_SHELL_TEST_RUNNER_TEST_RUNNER_EXPORT_H_
diff --git a/content/shell/test_runner/test_runner_for_specific_view.cc b/content/shell/test_runner/test_runner_for_specific_view.cc
index 9594246..c37a7140 100644
--- a/content/shell/test_runner/test_runner_for_specific_view.cc
+++ b/content/shell/test_runner/test_runner_for_specific_view.cc
@@ -63,7 +63,7 @@
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/switches.h"
 
-namespace test_runner {
+namespace content {
 
 TestRunnerForSpecificView::TestRunnerForSpecificView(
     WebViewTestProxy* web_view_test_proxy)
@@ -229,8 +229,7 @@
       << "Web tests harness doesn't currently support running "
       << "testRuner.capturePixelsAsyncThen from an OOPIF";
 
-  test_runner::TestInterfaces* interfaces =
-      web_view_test_proxy_->test_interfaces();
+  TestInterfaces* interfaces = web_view_test_proxy_->test_interfaces();
 
   if (interfaces->GetTestRunner()->CanDumpPixelsFromRenderer()) {
     // If we're grabbing pixels from printing, we do that in the renderer, and
@@ -736,4 +735,4 @@
   return web_view_test_proxy_->delegate();
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/test_runner_for_specific_view.h b/content/shell/test_runner/test_runner_for_specific_view.h
index db6c20f..6abe2d5 100644
--- a/content/shell/test_runner/test_runner_for_specific_view.h
+++ b/content/shell/test_runner/test_runner_for_specific_view.h
@@ -13,7 +13,6 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "v8/include/v8.h"
 
 class SkBitmap;
@@ -33,7 +32,7 @@
 class Arguments;
 }
 
-namespace test_runner {
+namespace content {
 class WebTestDelegate;
 class WebWidgetTestProxy;
 class WebViewTestProxy;
@@ -43,7 +42,7 @@
 // - testRunner.capturePixelsAsyncThen
 // - testRunner.setPageVisibility
 // Note that "global" bindings are handled by TestRunner class.
-class TEST_RUNNER_EXPORT TestRunnerForSpecificView {
+class TestRunnerForSpecificView {
  public:
   explicit TestRunnerForSpecificView(WebViewTestProxy* web_view_test_proxy);
   ~TestRunnerForSpecificView();
@@ -238,6 +237,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestRunnerForSpecificView);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_TEST_RUNNER_FOR_SPECIFIC_VIEW_H_
diff --git a/content/shell/test_runner/text_input_controller.cc b/content/shell/test_runner/text_input_controller.cc
index 21025fb..3ea36ae6 100644
--- a/content/shell/test_runner/text_input_controller.cc
+++ b/content/shell/test_runner/text_input_controller.cc
@@ -25,7 +25,7 @@
 #include "ui/events/base_event_utils.h"
 #include "v8/include/v8.h"
 
-namespace test_runner {
+namespace content {
 
 class TextInputControllerBindings
     : public gin::Wrappable<TextInputControllerBindings> {
@@ -427,4 +427,4 @@
       ->GetActiveWebInputMethodController();
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/text_input_controller.h b/content/shell/test_runner/text_input_controller.h
index 47adca1..b7eb21e 100644
--- a/content/shell/test_runner/text_input_controller.h
+++ b/content/shell/test_runner/text_input_controller.h
@@ -10,7 +10,6 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "content/shell/test_runner/test_runner_export.h"
 
 namespace blink {
 class WebInputMethodController;
@@ -18,14 +17,14 @@
 class WebView;
 }
 
-namespace test_runner {
+namespace content {
 
 class WebViewTestProxy;
 
 // TextInputController is bound to window.textInputController in Javascript
 // when content_shell is running. Web tests use it to exercise various
 // corners of text input.
-class TEST_RUNNER_EXPORT TextInputController {
+class TextInputController {
  public:
   explicit TextInputController(WebViewTestProxy* web_view_test_proxy);
   ~TextInputController();
@@ -63,6 +62,6 @@
   DISALLOW_COPY_AND_ASSIGN(TextInputController);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_TEXT_INPUT_CONTROLLER_H_
diff --git a/content/shell/test_runner/tracked_dictionary.cc b/content/shell/test_runner/tracked_dictionary.cc
index e88c890..3321b43 100644
--- a/content/shell/test_runner/tracked_dictionary.cc
+++ b/content/shell/test_runner/tracked_dictionary.cc
@@ -6,8 +6,7 @@
 
 #include <utility>
 
-
-namespace test_runner {
+namespace content {
 
 TrackedDictionary::TrackedDictionary() {}
 
@@ -47,4 +46,4 @@
   Set(path, std::make_unique<base::Value>(new_value));
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/tracked_dictionary.h b/content/shell/test_runner/tracked_dictionary.h
index 73c5791f..ed3c1755 100644
--- a/content/shell/test_runner/tracked_dictionary.h
+++ b/content/shell/test_runner/tracked_dictionary.h
@@ -10,14 +10,13 @@
 
 #include "base/macros.h"
 #include "base/values.h"
-#include "content/shell/test_runner/test_runner_export.h"
 
-namespace test_runner {
+namespace content {
 
 // TrackedDictionary wraps base::DictionaryValue, but forces all mutations to go
 // through TrackedDictionary's Set methods.  This allows tracking of changes
 // accumulated since the last call to ResetChangeTracking.
-class TEST_RUNNER_EXPORT TrackedDictionary {
+class TrackedDictionary {
  public:
   TrackedDictionary();
 
@@ -53,6 +52,6 @@
   DISALLOW_COPY_AND_ASSIGN(TrackedDictionary);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_TRACKED_DICTIONARY_H_
diff --git a/content/shell/test_runner/web_ax_object_proxy.cc b/content/shell/test_runner/web_ax_object_proxy.cc
index 52e83bc..5ab57a1 100644
--- a/content/shell/test_runner/web_ax_object_proxy.cc
+++ b/content/shell/test_runner/web_ax_object_proxy.cc
@@ -19,7 +19,7 @@
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/transform.h"
 
-namespace test_runner {
+namespace content {
 
 namespace {
 
@@ -2159,4 +2159,4 @@
   return handle;
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/web_ax_object_proxy.h b/content/shell/test_runner/web_ax_object_proxy.h
index 5d34e3b..5e125d21 100644
--- a/content/shell/test_runner/web_ax_object_proxy.h
+++ b/content/shell/test_runner/web_ax_object_proxy.h
@@ -20,7 +20,7 @@
 class WebLocalFrame;
 }
 
-namespace test_runner {
+namespace content {
 
 class WebAXObjectProxy : public gin::Wrappable<WebAXObjectProxy> {
  public:
@@ -257,6 +257,6 @@
   ElementList elements_;
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_WEB_AX_OBJECT_PROXY_H_
diff --git a/content/shell/test_runner/web_frame_test_client.cc b/content/shell/test_runner/web_frame_test_client.cc
index 02a8aae..c91c429 100644
--- a/content/shell/test_runner/web_frame_test_client.cc
+++ b/content/shell/test_runner/web_frame_test_client.cc
@@ -40,7 +40,7 @@
 #include "url/gurl.h"
 #include "url/url_constants.h"
 
-namespace test_runner {
+namespace content {
 
 namespace {
 
@@ -309,8 +309,7 @@
 
 void WebFrameTestClient::ShowContextMenu(
     const blink::WebContextMenuData& context_menu_data) {
-  delegate()
-      ->GetWebWidgetTestProxy(web_frame_test_proxy_->GetWebFrame())
+  web_frame_test_proxy_->GetLocalRootWebWidgetTestProxy()
       ->event_sender()
       ->SetContextMenuData(context_menu_data);
 }
@@ -500,10 +499,14 @@
 }
 
 void WebFrameTestClient::DidClearWindowObject() {
+  TestInterfaces* interfaces = web_view_test_proxy_->test_interfaces();
+  WebWidgetTestProxy* web_widget_test_proxy =
+      web_frame_test_proxy_->GetLocalRootWebWidgetTestProxy();
+
   blink::WebLocalFrame* frame = web_frame_test_proxy_->GetWebFrame();
-  web_view_test_proxy_->test_interfaces()->BindTo(frame);
+  interfaces->BindTo(frame);
   web_view_test_proxy_->BindTo(frame);
-  delegate()->GetWebWidgetTestProxy(frame)->BindTo(frame);
+  web_widget_test_proxy->BindTo(frame);
 }
 
 blink::WebEffectiveConnectionType
@@ -519,4 +522,4 @@
   return web_view_test_proxy_->test_interfaces()->GetTestRunner();
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/web_frame_test_client.h b/content/shell/test_runner/web_frame_test_client.h
index d0decc8..7579782a 100644
--- a/content/shell/test_runner/web_frame_test_client.h
+++ b/content/shell/test_runner/web_frame_test_client.h
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "third_party/blink/public/web/web_local_frame_client.h"
 
-namespace test_runner {
+namespace content {
 
 class TestRunner;
 class WebFrameTestProxy;
@@ -75,6 +75,6 @@
   DISALLOW_COPY_AND_ASSIGN(WebFrameTestClient);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_WEB_FRAME_TEST_CLIENT_H_
diff --git a/content/shell/test_runner/web_frame_test_proxy.cc b/content/shell/test_runner/web_frame_test_proxy.cc
index 4df9b4f9..cf014f0 100644
--- a/content/shell/test_runner/web_frame_test_proxy.cc
+++ b/content/shell/test_runner/web_frame_test_proxy.cc
@@ -13,7 +13,7 @@
 #include "content/shell/test_runner/web_view_test_proxy.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 
-namespace test_runner {
+namespace content {
 
 namespace {
 
@@ -132,6 +132,17 @@
   new TestRenderFrameObserver(this, view_proxy_for_frame);  // deletes itself.
 }
 
+void WebFrameTestProxy::Reset() {
+  if (IsMainFrame()) {
+    GetWebFrame()->SetName(blink::WebString());
+    GetWebFrame()->ClearOpener();
+  }
+  if (IsLocalRoot()) {
+    GetLocalRootWebWidgetTestProxy()->Reset();
+    GetLocalRootWebWidgetTestProxy()->EndSyntheticGestures();
+  }
+}
+
 std::string WebFrameTestProxy::GetFrameNameForWebTests() {
   return content::UniqueNameHelper::ExtractStableNameForTesting(unique_name());
 }
@@ -252,4 +263,8 @@
   RenderFrameImpl::DidClearWindowObject();
 }
 
-}  // namespace test_runner
+WebWidgetTestProxy* WebFrameTestProxy::GetLocalRootWebWidgetTestProxy() {
+  return static_cast<WebWidgetTestProxy*>(GetLocalRootRenderWidget());
+}
+
+}  // namespace content
diff --git a/content/shell/test_runner/web_frame_test_proxy.h b/content/shell/test_runner/web_frame_test_proxy.h
index 4d09979..dc3edd1 100644
--- a/content/shell/test_runner/web_frame_test_proxy.h
+++ b/content/shell/test_runner/web_frame_test_proxy.h
@@ -11,7 +11,6 @@
 
 #include "base/macros.h"
 #include "content/renderer/render_frame_impl.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "content/shell/test_runner/web_frame_test_client.h"
 #include "third_party/blink/public/platform/web_effective_connection_type.h"
 #include "third_party/blink/public/platform/web_string.h"
@@ -22,12 +21,13 @@
 class RenderViewImpl;
 }  // namespace content
 
-namespace test_runner {
+namespace content {
+class WebWidgetTestProxy;
 
 // WebFrameTestProxy is used during running web tests instead of a
 // RenderFrameImpl to inject test-only behaviour by overriding methods in the
 // base class.
-class TEST_RUNNER_EXPORT WebFrameTestProxy : public content::RenderFrameImpl {
+class WebFrameTestProxy : public content::RenderFrameImpl {
  public:
   template <typename... Args>
   explicit WebFrameTestProxy(Args&&... args)
@@ -36,10 +36,16 @@
 
   void Initialize(content::RenderViewImpl* render_view_for_frame);
 
+  // Reset state between tests.
+  void Reset();
+
   // Returns a frame name that can be used in the output of web tests
   // (the name is derived from the frame's unique name).
   std::string GetFrameNameForWebTests();
 
+  // Returns the test-subclass of RenderWidget for the local root of this frame.
+  WebWidgetTestProxy* GetLocalRootWebWidgetTestProxy();
+
   // RenderFrameImpl overrides.
   void UpdateAllLifecyclePhasesAndCompositeForTesting() override;
 
@@ -75,6 +81,6 @@
   DISALLOW_COPY_AND_ASSIGN(WebFrameTestProxy);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_WEB_FRAME_TEST_PROXY_H_
diff --git a/content/shell/test_runner/web_test_delegate.h b/content/shell/test_runner/web_test_delegate.h
index 750aa70..dd3d1b6 100644
--- a/content/shell/test_runner/web_test_delegate.h
+++ b/content/shell/test_runner/web_test_delegate.h
@@ -35,7 +35,7 @@
 class WebView;
 }  // namespace blink
 
-namespace test_runner {
+namespace content {
 
 class WebWidgetTestProxy;
 struct TestPreferences;
@@ -125,20 +125,14 @@
   // Controls the device scale factor of the main WebView for hidpi tests.
   virtual void SetDeviceScaleFactor(float factor) = 0;
 
-  // Converts |event| from screen coordinates used by test_runner::EventSender
+  // Converts |event| from screen coordinates used by EventSender
   // into coordinates that are understood by the widget associated with
   // |web_widget_test_proxy|.  Returns nullptr if no transformation was
   // necessary (e.g. for a keyboard event OR if widget requires no scaling
   // and has coordinates starting at (0,0)).
   virtual std::unique_ptr<blink::WebInputEvent>
-  TransformScreenToWidgetCoordinates(
-      test_runner::WebWidgetTestProxy* web_widget_test_proxy,
-      const blink::WebInputEvent& event) = 0;
-
-  // Gets WebWidgetTestProxy associated with |frame| (associated with either
-  // a RenderView or a RenderWidget for the local root).
-  virtual test_runner::WebWidgetTestProxy* GetWebWidgetTestProxy(
-      blink::WebLocalFrame* frame) = 0;
+  TransformScreenToWidgetCoordinates(WebWidgetTestProxy* web_widget_test_proxy,
+                                     const blink::WebInputEvent& event) = 0;
 
   // Enable zoom-for-dsf option.
   virtual void EnableUseZoomForDSF() = 0;
@@ -263,6 +257,6 @@
   virtual void SetScreenOrientationChanged() = 0;
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_WEB_TEST_DELEGATE_H_
diff --git a/content/shell/test_runner/web_test_runtime_flags.cc b/content/shell/test_runner/web_test_runtime_flags.cc
index 164f3f2..38fcddf 100644
--- a/content/shell/test_runner/web_test_runtime_flags.cc
+++ b/content/shell/test_runner/web_test_runtime_flags.cc
@@ -4,7 +4,7 @@
 
 #include "content/shell/test_runner/web_test_runtime_flags.h"
 
-namespace test_runner {
+namespace content {
 
 WebTestRuntimeFlags::WebTestRuntimeFlags() {
   Reset();
@@ -67,4 +67,4 @@
   tracked_dictionary().ResetChangeTracking();
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/web_test_runtime_flags.h b/content/shell/test_runner/web_test_runtime_flags.h
index 2526210..9a02f25 100644
--- a/content/shell/test_runner/web_test_runtime_flags.h
+++ b/content/shell/test_runner/web_test_runtime_flags.h
@@ -10,15 +10,14 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/values.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "content/shell/test_runner/tracked_dictionary.h"
 
-namespace test_runner {
+namespace content {
 
 // WebTestRuntimeFlags stores flags controlled by web tests at runtime
 // (i.e. by calling testRunner.dumpAsText() or testRunner.waitUntilDone()).
 // Changes to the flags are tracked (to help replicate them across renderers).
-class TEST_RUNNER_EXPORT WebTestRuntimeFlags {
+class WebTestRuntimeFlags {
  public:
   // Creates default flags (see also the Reset method).
   WebTestRuntimeFlags();
@@ -184,6 +183,6 @@
   DISALLOW_COPY_AND_ASSIGN(WebTestRuntimeFlags);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_WEB_TEST_RUNTIME_FLAGS_H_
diff --git a/content/shell/test_runner/web_view_test_proxy.cc b/content/shell/test_runner/web_view_test_proxy.cc
index de5a51b2..1d4b9a9 100644
--- a/content/shell/test_runner/web_view_test_proxy.cc
+++ b/content/shell/test_runner/web_view_test_proxy.cc
@@ -11,15 +11,15 @@
 #include "content/shell/test_runner/mock_screen_orientation_client.h"
 #include "content/shell/test_runner/test_interfaces.h"
 #include "content/shell/test_runner/test_runner.h"
+#include "content/shell/test_runner/web_frame_test_proxy.h"
 #include "content/shell/test_runner/web_test_delegate.h"
-#include "content/shell/test_runner/web_widget_test_proxy.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/web/web_frame.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_print_params.h"
 #include "third_party/blink/public/web/web_view.h"
 
-namespace test_runner {
+namespace content {
 
 void WebViewTestProxy::Initialize(TestInterfaces* interfaces,
                                   std::unique_ptr<WebTestDelegate> delegate) {
@@ -82,16 +82,15 @@
   accessibility_controller_.Reset();
   // |text_input_controller_| doesn't have any state to reset.
   view_test_runner_.Reset();
-  if (GetMainRenderFrame()) {
-    auto* widget_proxy = static_cast<WebWidgetTestProxy*>(
-        GetMainRenderFrame()->GetLocalRootRenderWidget());
-    widget_proxy->Reset();
-  }
 
   for (blink::WebFrame* frame = GetWebView()->MainFrame(); frame;
        frame = frame->TraverseNext()) {
-    if (frame->IsWebLocalFrame())
-      delegate_->GetWebWidgetTestProxy(frame->ToWebLocalFrame())->Reset();
+    if (frame->IsWebLocalFrame()) {
+      RenderFrame* render_frame =
+          RenderFrame::FromWebFrame(frame->ToWebLocalFrame());
+      auto* frame_proxy = static_cast<WebFrameTestProxy*>(render_frame);
+      frame_proxy->Reset();
+    }
   }
 }
 
@@ -109,4 +108,4 @@
   return test_interfaces()->GetTestRunner();
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/web_view_test_proxy.h b/content/shell/test_runner/web_view_test_proxy.h
index 6d1f4104..a505db43 100644
--- a/content/shell/test_runner/web_view_test_proxy.h
+++ b/content/shell/test_runner/web_view_test_proxy.h
@@ -14,7 +14,6 @@
 #include "build/build_config.h"
 #include "content/renderer/render_view_impl.h"
 #include "content/shell/test_runner/accessibility_controller.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "content/shell/test_runner/test_runner_for_specific_view.h"
 #include "content/shell/test_runner/text_input_controller.h"
 #include "content/shell/test_runner/web_widget_test_proxy.h"
@@ -35,7 +34,7 @@
 struct WebWindowFeatures;
 }
 
-namespace test_runner {
+namespace content {
 class AccessibilityController;
 class TestInterfaces;
 class TestRunnerForSpecificView;
@@ -59,7 +58,7 @@
 // Historically, the overridden functionality has been small enough to not
 // cause too much trouble. If that changes, then this entire testing
 // architecture should be revisited.
-class TEST_RUNNER_EXPORT WebViewTestProxy : public content::RenderViewImpl {
+class WebViewTestProxy : public content::RenderViewImpl {
  public:
   template <typename... Args>
   explicit WebViewTestProxy(Args&&... args)
@@ -110,6 +109,6 @@
   DISALLOW_COPY_AND_ASSIGN(WebViewTestProxy);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_WEB_VIEW_TEST_PROXY_H_
diff --git a/content/shell/test_runner/web_widget_test_proxy.cc b/content/shell/test_runner/web_widget_test_proxy.cc
index c46df7f..a0d970eb 100644
--- a/content/shell/test_runner/web_widget_test_proxy.cc
+++ b/content/shell/test_runner/web_widget_test_proxy.cc
@@ -17,7 +17,7 @@
 #include "third_party/blink/public/web/web_view.h"
 #include "third_party/blink/public/web/web_widget.h"
 
-namespace test_runner {
+namespace content {
 
 WebWidgetTestProxy::~WebWidgetTestProxy() = default;
 
@@ -240,4 +240,4 @@
   SynchronouslyComposite(do_raster);
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/content/shell/test_runner/web_widget_test_proxy.h b/content/shell/test_runner/web_widget_test_proxy.h
index 273a2937..b3e9c5f 100644
--- a/content/shell/test_runner/web_widget_test_proxy.h
+++ b/content/shell/test_runner/web_widget_test_proxy.h
@@ -13,7 +13,6 @@
 #include "base/memory/weak_ptr.h"
 #include "content/renderer/render_widget.h"
 #include "content/shell/test_runner/event_sender.h"
-#include "content/shell/test_runner/test_runner_export.h"
 #include "third_party/blink/public/web/web_widget_client.h"
 
 namespace blink {
@@ -25,7 +24,7 @@
 class RenderViewImpl;
 }
 
-namespace test_runner {
+namespace content {
 
 class TestRunner;
 class TestRunnerForSpecificView;
@@ -51,7 +50,7 @@
 // Historically, the overridden functionality has been small enough to not
 // cause too much trouble. If that changes, then this entire testing
 // architecture should be revisited.
-class TEST_RUNNER_EXPORT WebWidgetTestProxy : public content::RenderWidget {
+class WebWidgetTestProxy : public content::RenderWidget {
  public:
   template <typename... Args>
   explicit WebWidgetTestProxy(Args&&... args)
@@ -130,6 +129,6 @@
   DISALLOW_COPY_AND_ASSIGN(WebWidgetTestProxy);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
 #endif  // CONTENT_SHELL_TEST_RUNNER_WEB_WIDGET_TEST_PROXY_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index ea8d950..e9f692c 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -784,7 +784,6 @@
     "//content/public/common",
     "//content/public/renderer",
     "//content/renderer:for_content_tests",
-    "//content/shell/test_runner:test_runner",
     "//ui/events/blink",
     "//ui/gfx:test_support",
     "//ui/gfx/geometry",
diff --git a/content/test/data/accessibility/regression/hidden-table-expected-blink.txt b/content/test/data/accessibility/regression/hidden-table-expected-blink.txt
new file mode 100644
index 0000000..59d1cc2
--- /dev/null
+++ b/content/test/data/accessibility/regression/hidden-table-expected-blink.txt
@@ -0,0 +1,14 @@
+rootWebArea
+++genericContainer ignored
+++++genericContainer ignored
+++++++table
+++++++++row
+++++++++++columnHeader name='Header 1'
+++++++++++++staticText name='Header 1'
+++++++++++++++inlineTextBox name='Header 1'
+++++++++++columnHeader name='Header 2'
+++++++++++++staticText name='Header 2'
+++++++++++++++inlineTextBox name='Header 2'
+++++++genericContainer
+++++++++staticText name='Done'
+++++++++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/regression/hidden-table.html b/content/test/data/accessibility/regression/hidden-table.html
new file mode 100644
index 0000000..b9a12f4
--- /dev/null
+++ b/content/test/data/accessibility/regression/hidden-table.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<!--
+@WAIT-FOR:Done
+-->
+<body>
+  <table>
+    <thead>
+      <tr>
+        <th>Header 1</th>
+        <th>Header 2</th>
+      </tr>
+    </thead>
+    <tbody hidden>
+    </tbody>
+    <tfoot>
+    </tfoot>
+  </table>
+
+  <script>
+    function addRow(container) {
+        let row = document.createElement('tr');
+        container.appendChild(row);
+        for (let j = 0; j < 100; j++) {
+            let cell = document.createElement('td');
+            cell.innerHTML = Math.random();
+            row.appendChild(cell);
+            cell.tabIndex = -1;
+        }
+    }
+
+    setTimeout(() => {
+        // Now add a bunch of rows to the tbody, which is hidden.
+        // Every one of those added cells changes its tabIndex, which
+        // triggers a call to MarkAXObjectDirty on a node that's not
+        // included in the accessibility tree. That caused a bug where
+        // all of the real nodes of the table keep getting re-serialized.
+        // This is now caught by a DCHECK in BrowserAccessibilityManager
+        // that an AXTreeUpdate shouldn't be larger than the resulting tree.
+        for (let i = 0; i < 10; i++) {
+            addRow(document.querySelector('tbody'));
+        }
+
+        // Finally, clear out all of those extra rows and finish
+        // the test.
+        setTimeout(() => {
+            document.querySelector('tbody').innerHTML = '';
+            let done = document.createElement('div');
+            done.innerHTML = 'Done';
+            document.body.appendChild(done);
+        }, 10);
+    }, 10);
+  </script>
+</body>
diff --git a/content/test/data/manifest/file-handler-manifest.html b/content/test/data/manifest/file-handler-manifest.html
new file mode 100644
index 0000000..9008559
--- /dev/null
+++ b/content/test/data/manifest/file-handler-manifest.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <link rel='manifest' href='file-handler-manifest.json'>
+</head>
+<body>
+</body>
+</html>
diff --git a/content/test/data/manifest/file-handler-manifest.json b/content/test/data/manifest/file-handler-manifest.json
new file mode 100644
index 0000000..ed6b64c
--- /dev/null
+++ b/content/test/data/manifest/file-handler-manifest.json
@@ -0,0 +1,11 @@
+{
+  "file_handlers": [
+    {
+      "name": "name",
+      "action": "/files",
+      "accept": {
+        "image/png": ".png"
+      }
+    }
+  ]
+}
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index 5363314b..4846bc91 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -124,6 +124,7 @@
 
 # Flakes on Nexus 5X.
 crbug.com/883500 [ android-chromium no-use-gl no-use-vulkan qualcomm-adreno-(tm)-418 ] Pixel_BackgroundImage [ RetryOnFailure ]
+crbug.com/1068620 [ android-chromium no-use-gl no-use-vulkan qualcomm-adreno-(tm)-418 ] Pixel_OffscreenCanvasWebGLPaintAfterResize [ RetryOnFailure ]
 
 # We do not have software H.264 decoding on Android, so it can't survive a
 # context loss which results in hardware decoder loss.
diff --git a/content/test/web_test_support_renderer.cc b/content/test/web_test_support_renderer.cc
index 179921b..5344842 100644
--- a/content/test/web_test_support_renderer.cc
+++ b/content/test/web_test_support_renderer.cc
@@ -43,11 +43,10 @@
 
 RenderViewImpl* CreateWebViewTestProxy(CompositorDependencies* compositor_deps,
                                        const mojom::CreateViewParams& params) {
-  test_runner::TestInterfaces* interfaces =
+  TestInterfaces* interfaces =
       WebTestRenderThreadObserver::GetInstance()->test_interfaces();
 
-  auto* render_view_proxy =
-      new test_runner::WebViewTestProxy(compositor_deps, params);
+  auto* render_view_proxy = new WebViewTestProxy(compositor_deps, params);
 
   auto blink_test_runner = std::make_unique<BlinkTestRunner>(render_view_proxy);
   // TODO(lukasza): Using the first BlinkTestRunner as the main delegate is
@@ -68,7 +67,7 @@
     blink::mojom::DisplayMode display_mode,
     bool never_composited,
     mojo::PendingReceiver<mojom::Widget> widget_receiver) {
-  return std::make_unique<test_runner::WebWidgetTestProxy>(
+  return std::make_unique<WebWidgetTestProxy>(
       routing_id, compositor_deps, display_mode,
       /*hidden=*/true, never_composited, std::move(widget_receiver));
 }
@@ -77,25 +76,13 @@
   // RenderFrameImpl always has a RenderViewImpl for it.
   RenderViewImpl* render_view_impl = params.render_view;
 
-  auto* render_frame_proxy =
-      new test_runner::WebFrameTestProxy(std::move(params));
+  auto* render_frame_proxy = new WebFrameTestProxy(std::move(params));
   render_frame_proxy->Initialize(render_view_impl);
   return render_frame_proxy;
 }
 
 }  // namespace
 
-test_runner::WebWidgetTestProxy* GetWebWidgetTestProxy(
-    blink::WebLocalFrame* frame) {
-  DCHECK(frame);
-  RenderFrame* local_root = RenderFrame::FromWebFrame(frame->LocalRoot());
-  RenderFrameImpl* local_root_impl = static_cast<RenderFrameImpl*>(local_root);
-  DCHECK(local_root);
-
-  return static_cast<test_runner::WebWidgetTestProxy*>(
-      local_root_impl->GetLocalRootRenderWidget());
-}
-
 void EnableWebTestProxyCreation() {
   RenderViewImpl::InstallCreateHook(CreateWebViewTestProxy);
   RenderWidget::InstallCreateForFrameHook(CreateRenderWidgetForFrame);
@@ -151,20 +138,17 @@
 }
 
 std::unique_ptr<blink::WebInputEvent> TransformScreenToWidgetCoordinates(
-    test_runner::WebWidgetTestProxy* web_widget_test_proxy,
+    WebWidgetTestProxy* web_widget_test_proxy,
     const blink::WebInputEvent& event) {
   DCHECK(web_widget_test_proxy);
 
-  RenderWidget* render_widget =
-      static_cast<RenderWidget*>(web_widget_test_proxy);
-
   // Compute the scale from window (dsf-independent) to blink (dsf-dependent
   // under UseZoomForDSF).
   blink::WebFloatRect rect(0, 0, 1.0f, 0.0);
-  render_widget->ConvertWindowToViewport(&rect);
+  web_widget_test_proxy->ConvertWindowToViewport(&rect);
   float scale = rect.width;
 
-  blink::WebRect view_rect = render_widget->ViewRect();
+  blink::WebRect view_rect = web_widget_test_proxy->ViewRect();
   gfx::Vector2d delta(-view_rect.x, -view_rect.y);
 
   // The coordinates are given in terms of the root widget, so adjust for the
@@ -172,11 +156,15 @@
   // TODO(sgilhuly): This doesn't work for events sent to OOPIFs because the
   // main frame is remote, and doesn't have a corresponding RenderWidget.
   // Currently none of those tests are run out of headless mode.
-  blink::WebFrame* frame =
-      web_widget_test_proxy->GetWebViewTestProxy()->GetWebView()->MainFrame();
-  if (frame->IsWebLocalFrame()) {
-    test_runner::WebWidgetTestProxy* root_widget =
-        GetWebWidgetTestProxy(frame->ToWebLocalFrame());
+  // TODO(danakj): In a frame, the ViewRect is the same in every local root
+  // and this would just remove and add it back, so this should be fine in
+  // OOPIFs, we should only do the ViewRect() translation for popup widgets,
+  // just as RenderWidget does.
+  RenderFrameImpl* main_frame =
+      web_widget_test_proxy->GetWebViewTestProxy()->GetMainRenderFrame();
+  if (main_frame) {
+    RenderWidget* root_widget = main_frame->GetLocalRootRenderWidget();
+
     blink::WebRect root_rect = root_widget->ViewRect();
     gfx::Vector2d root_delta(root_rect.x, root_rect.y);
     delta.Add(root_delta);
diff --git a/device/bluetooth/chromeos/bluetooth_utils.cc b/device/bluetooth/chromeos/bluetooth_utils.cc
index e825270..9a6e393 100644
--- a/device/bluetooth/chromeos/bluetooth_utils.cc
+++ b/device/bluetooth/chromeos/bluetooth_utils.cc
@@ -195,14 +195,11 @@
   return GetLimitedNumDevices(max_devices, filtered_devices);
 }
 
-void RecordPairingResult(bool success,
+void RecordPairingResult(base::Optional<ConnectionFailureReason> failure_reason,
                          BluetoothTransport transport,
                          base::TimeDelta duration) {
   RecordPairingTransport(transport);
 
-  std::string result_histogram_name_prefix =
-      "Bluetooth.ChromeOS.Pairing.Result";
-
   std::string transport_histogram_name;
   switch (transport) {
     case BluetoothTransport::BLUETOOTH_TRANSPORT_CLASSIC:
@@ -220,6 +217,10 @@
       return;
   }
 
+  bool success = !failure_reason.has_value();
+  std::string result_histogram_name_prefix =
+      "Bluetooth.ChromeOS.Pairing.Result";
+
   base::UmaHistogramBoolean(result_histogram_name_prefix, success);
   base::UmaHistogramBoolean(
       result_histogram_name_prefix + "." + transport_histogram_name, success);
@@ -233,17 +234,37 @@
   RecordPairingDuration(base_histogram_name, duration);
   RecordPairingDuration(base_histogram_name + "." + transport_histogram_name,
                         duration);
+
+  if (!success) {
+    base::UmaHistogramEnumeration(
+        result_histogram_name_prefix + ".FailureReason", *failure_reason);
+    base::UmaHistogramEnumeration(result_histogram_name_prefix +
+                                      ".FailureReason." +
+                                      transport_histogram_name,
+                                  *failure_reason);
+  }
 }
 
-void RecordUserInitiatedReconnectionAttemptResult(bool success,
-                                                  BluetoothUiSurface surface) {
+void RecordUserInitiatedReconnectionAttemptResult(
+    base::Optional<ConnectionFailureReason> failure_reason,
+    BluetoothUiSurface surface) {
+  bool success = !failure_reason.has_value();
   std::string base_histogram_name =
       "Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result";
+
   base::UmaHistogramBoolean(base_histogram_name, success);
 
   std::string surface_name =
       (surface == BluetoothUiSurface::kSettings ? "Settings" : "SystemTray");
   base::UmaHistogramBoolean(base_histogram_name + "." + surface_name, success);
+
+  if (!success) {
+    base::UmaHistogramEnumeration(base_histogram_name + ".FailureReason",
+                                  *failure_reason);
+    base::UmaHistogramEnumeration(
+        base_histogram_name + ".FailureReason." + surface_name,
+        *failure_reason);
+  }
 }
 
 void RecordDeviceSelectionDuration(base::TimeDelta duration,
diff --git a/device/bluetooth/chromeos/bluetooth_utils.h b/device/bluetooth/chromeos/bluetooth_utils.h
index a8c1556..ddd35da2 100644
--- a/device/bluetooth/chromeos/bluetooth_utils.h
+++ b/device/bluetooth/chromeos/bluetooth_utils.h
@@ -5,6 +5,7 @@
 #ifndef DEVICE_BLUETOOTH_CHROMEOS_BLUETOOTH_UTILS_H_
 #define DEVICE_BLUETOOTH_CHROMEOS_BLUETOOTH_UTILS_H_
 
+#include "base/optional.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_export.h"
 
@@ -29,6 +30,21 @@
   kSystemTray,
 };
 
+// This enum is tied directly to a UMA enum defined in
+// //tools/metrics/histograms/enums.xml, and should always reflect it (do not
+// change one without changing the other).
+enum class ConnectionFailureReason {
+  kUnknownError = 0,
+  kSystemError = 1,
+  kAuthFailed = 2,
+  kAuthTimeout = 3,
+  kFailed = 4,
+  kUnknownConnectionError = 5,
+  kUnsupportedDevice = 6,
+  kNotConnectable = 7,
+  kMaxValue = kNotConnectable
+};
+
 // Return filtered devices based on the filter type and max number of devices.
 DEVICE_BLUETOOTH_EXPORT device::BluetoothAdapter::DeviceList
 FilterBluetoothDeviceList(const BluetoothAdapter::DeviceList& devices,
@@ -36,13 +52,14 @@
                           int max_devices);
 
 // Record outcome of user attempting to pair to a device.
-DEVICE_BLUETOOTH_EXPORT void RecordPairingResult(bool success,
-                                                 BluetoothTransport transport,
-                                                 base::TimeDelta duration);
+DEVICE_BLUETOOTH_EXPORT void RecordPairingResult(
+    base::Optional<ConnectionFailureReason> failure_reason,
+    BluetoothTransport transport,
+    base::TimeDelta duration);
 
 // Record outcome of user attempting to reconnect to a previously paired device.
 DEVICE_BLUETOOTH_EXPORT void RecordUserInitiatedReconnectionAttemptResult(
-    bool success,
+    base::Optional<ConnectionFailureReason> failure_reason,
     BluetoothUiSurface surface);
 
 // Record how long it took for a user to find and select the device they wished
diff --git a/extensions/browser/api/bluetooth/bluetooth_private_api.cc b/extensions/browser/api/bluetooth/bluetooth_private_api.cc
index 644c17f..3c108c2 100644
--- a/extensions/browser/api/bluetooth/bluetooth_private_api.cc
+++ b/extensions/browser/api/bluetooth/bluetooth_private_api.cc
@@ -69,6 +69,28 @@
       return true;
   }
 }
+
+base::Optional<device::ConnectionFailureReason> GetConnectionFailureReason(
+    bt_private::ConnectResultType result) {
+  DCHECK(IsActualConnectionFailure(result));
+
+  switch (result) {
+    case bt_private::CONNECT_RESULT_TYPE_NONE:
+      return device::ConnectionFailureReason::kSystemError;
+    case bt_private::CONNECT_RESULT_TYPE_AUTHFAILED:
+      return device::ConnectionFailureReason::kAuthFailed;
+    case bt_private::CONNECT_RESULT_TYPE_AUTHTIMEOUT:
+      return device::ConnectionFailureReason::kAuthTimeout;
+    case bt_private::CONNECT_RESULT_TYPE_FAILED:
+      return device::ConnectionFailureReason::kFailed;
+    case bt_private::CONNECT_RESULT_TYPE_UNKNOWNERROR:
+      return device::ConnectionFailureReason::kUnknownConnectionError;
+    case bt_private::CONNECT_RESULT_TYPE_UNSUPPORTEDDEVICE:
+      return device::ConnectionFailureReason::kUnsupportedDevice;
+    default:
+      return device::ConnectionFailureReason::kUnknownError;
+  }
+}
 #endif  // defined(OS_CHROMEOS)
 
 std::string GetListenerId(const EventListenerInfo& details) {
@@ -654,7 +676,8 @@
   // Only emit metrics if this is a success or a true connection failure.
   if (success || IsActualConnectionFailure(result)) {
     device::RecordPairingResult(
-        success, GetBluetoothTransport(params_->transport),
+        success ? base::nullopt : GetConnectionFailureReason(result),
+        GetBluetoothTransport(params_->transport),
         base::TimeDelta::FromMilliseconds(params_->pairing_duration_ms));
   }
 #endif  // defined(OS_CHROMEOS)
@@ -684,7 +707,8 @@
   // Only emit metrics if this is a success or a true connection failure.
   if (success || IsActualConnectionFailure(result)) {
     device::RecordUserInitiatedReconnectionAttemptResult(
-        success, device::BluetoothUiSurface::kSettings);
+        success ? base::nullopt : GetConnectionFailureReason(result),
+        device::BluetoothUiSurface::kSettings);
   }
 #endif  // defined(OS_CHROMEOS)
 
diff --git a/extensions/browser/api/declarative_net_request/index_helper.cc b/extensions/browser/api/declarative_net_request/index_helper.cc
index fabc31c..a9f689f 100644
--- a/extensions/browser/api/declarative_net_request/index_helper.cc
+++ b/extensions/browser/api/declarative_net_request/index_helper.cc
@@ -4,27 +4,113 @@
 
 #include "extensions/browser/api/declarative_net_request/index_helper.h"
 
+#include <iterator>
 #include <utility>
 
 #include "base/barrier_closure.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "extensions/browser/api/declarative_net_request/constants.h"
+#include "extensions/common/api/declarative_net_request.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 namespace declarative_net_request {
 
+namespace {
+namespace dnr_api = api::declarative_net_request;
+
+// Combines indexing results from multiple RulesetSources into a single
+// IndexHelper::Result.
+IndexHelper::Result CombineResults(
+    std::vector<std::pair<const RulesetSource*,
+                          IndexAndPersistJSONRulesetResult>> results,
+    bool log_histograms) {
+  IndexHelper::Result total_result;
+  total_result.ruleset_checksums.reserve(results.size());
+  size_t total_rules_count = 0;
+  base::TimeDelta total_index_and_persist_time;
+
+  // TODO(crbug.com/754526): Impose a limit on the total number of rules across
+  // all the rulesets for an extension. Also, limit the number of install
+  // warnings across all rulesets.
+
+  // Note |results| may be empty.
+  for (auto& result_pair : results) {
+    IndexAndPersistJSONRulesetResult& index_result = result_pair.second;
+    const RulesetSource* source = result_pair.first;
+
+    if (!index_result.success) {
+      total_result.error = std::move(index_result.error);
+      return total_result;
+    }
+
+    total_result.ruleset_checksums.emplace_back(
+        source->id(), std::move(index_result.ruleset_checksum));
+
+    total_result.warnings.insert(
+        total_result.warnings.end(),
+        std::make_move_iterator(index_result.warnings.begin()),
+        std::make_move_iterator(index_result.warnings.end()));
+
+    total_index_and_persist_time += index_result.index_and_persist_time;
+    total_rules_count += index_result.rules_count;
+  }
+
+  if (log_histograms) {
+    UMA_HISTOGRAM_TIMES(
+        declarative_net_request::kIndexAndPersistRulesTimeHistogram,
+        total_index_and_persist_time);
+
+    // TODO(karandeepb): Increase the maximum sample size for this histogram
+    // since we anticipate increasing the rules limit.
+    UMA_HISTOGRAM_COUNTS_100000(
+        declarative_net_request::kManifestRulesCountHistogram,
+        total_rules_count);
+  }
+
+  return total_result;
+}
+
+}  // namespace
+
+IndexHelper::Result::Result() = default;
+IndexHelper::Result::~Result() = default;
+IndexHelper::Result::Result(Result&&) = default;
+IndexHelper::Result& IndexHelper::Result::operator=(Result&&) = default;
+
 // static
-void IndexHelper::Start(std::vector<RulesetSource> sources,
-                        IndexCallback callback) {
+void IndexHelper::IndexStaticRulesets(const Extension& extension,
+                                      IndexCallback callback) {
   // Note we use ref-counting instead of manual memory management since there
   // are some subtle cases:
   //  - Zero rulesets to index.
   //  - All individual callbacks return synchronously.
   // In these cases there's a potential for a use-after-free with manual memory
   // management.
-  auto index_helper = base::WrapRefCounted(
-      new IndexHelper(std::move(sources), std::move(callback)));
+  auto index_helper = base::WrapRefCounted(new IndexHelper(
+      RulesetSource::CreateStatic(extension), std::move(callback)));
   index_helper->Start();
 }
 
+// static
+IndexHelper::Result IndexHelper::IndexStaticRulesetsUnsafe(
+    const Extension& extension) {
+  std::vector<RulesetSource> sources = RulesetSource::CreateStatic(extension);
+
+  IndexResults results;
+  results.reserve(sources.size());
+  for (const RulesetSource& source : sources)
+    results.emplace_back(&source, source.IndexAndPersistJSONRulesetUnsafe());
+
+  // Don't log histograms for unpacked extensions so that the histograms reflect
+  // real world usage.
+  DCHECK(Manifest::IsUnpackedLocation(extension.location()));
+  const bool log_histograms = false;
+  return CombineResults(std::move(results), log_histograms);
+}
+
 IndexHelper::IndexHelper(std::vector<RulesetSource> sources,
                          IndexCallback callback)
     : sources_(std::move(sources)), callback_(std::move(callback)) {}
@@ -39,24 +125,26 @@
   base::RepeatingClosure barrier_closure =
       base::BarrierClosure(sources_.size(), std::move(all_done_closure));
 
-  for (const RulesetSource& source : sources_) {
-    auto callback =
-        base::BindOnce(&IndexHelper::OnRulesetIndexed, this, barrier_closure);
-    source.IndexAndPersistJSONRuleset(&decoder_, std::move(callback));
+  for (size_t i = 0; i < sources_.size(); ++i) {
+    // Since |sources_| is const, |sources_[i]| is guaranteed to remain valid.
+    auto callback = base::BindOnce(&IndexHelper::OnRulesetIndexed, this,
+                                   barrier_closure, i);
+    sources_[i].IndexAndPersistJSONRuleset(&decoder_, std::move(callback));
   }
 }
 
 void IndexHelper::OnAllRulesetsIndexed() {
   DCHECK_EQ(sources_.size(), results_.size());
 
-  // Our job is done.
-  std::move(callback_).Run(std::move(results_));
+  bool log_histograms = !sources_.empty();
+  std::move(callback_).Run(CombineResults(std::move(results_), log_histograms));
 }
 
 // Callback invoked when indexing of a single ruleset is completed.
 void IndexHelper::OnRulesetIndexed(base::OnceClosure ruleset_done_closure,
+                                   size_t source_index,
                                    IndexAndPersistJSONRulesetResult result) {
-  results_.push_back(std::move(result));
+  results_.emplace_back(&sources_[source_index], std::move(result));
   std::move(ruleset_done_closure).Run();
 }
 
diff --git a/extensions/browser/api/declarative_net_request/index_helper.h b/extensions/browser/api/declarative_net_request/index_helper.h
index ff91662..ee1ad961 100644
--- a/extensions/browser/api/declarative_net_request/index_helper.h
+++ b/extensions/browser/api/declarative_net_request/index_helper.h
@@ -5,28 +5,56 @@
 #ifndef EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_INDEX_HELPER_H_
 #define EXTENSIONS_BROWSER_API_DECLARATIVE_NET_REQUEST_INDEX_HELPER_H_
 
+#include <string>
+#include <utility>
 #include <vector>
 
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
+#include "base/optional.h"
+#include "extensions/browser/api/declarative_net_request/ruleset_checksum.h"
 #include "extensions/browser/api/declarative_net_request/ruleset_source.h"
+#include "extensions/common/install_warning.h"
 #include "services/data_decoder/public/cpp/data_decoder.h"
 
 namespace extensions {
+class Extension;
 namespace declarative_net_request {
 
 // A class to help in indexing multiple rulesets.
 class IndexHelper : public base::RefCountedThreadSafe<IndexHelper> {
  public:
+  struct Result {
+    Result();
+    ~Result();
+    Result(Result&&);
+    Result& operator=(Result&&);
+
+    // Non-empty on failure.
+    base::Optional<std::string> error;
+
+    // Valid if |error| is base::nullopt. Clients should not use these fields in
+    // case of a failure since these may be partially populated.
+    std::vector<InstallWarning> warnings;
+    std::vector<RulesetChecksum> ruleset_checksums;
+  };
+
   // Starts indexing rulesets. Must be called on a sequence which supports file
-  // IO. The |callback| will be dispatched to the same sequence on which Start()
-  // is called.
-  using Results = std::vector<IndexAndPersistJSONRulesetResult>;
-  using IndexCallback = base::OnceCallback<void(Results)>;
-  static void Start(std::vector<RulesetSource> sources, IndexCallback callback);
+  // IO. The |callback| will be dispatched to the same sequence on which
+  // IndexStaticRulesets() is called.
+  using IndexCallback = base::OnceCallback<void(Result result)>;
+  static void IndexStaticRulesets(const Extension& extension,
+                                  IndexCallback callback);
+
+  // Synchronously indexes the static rulesets for an extension. Must be called
+  // on a sequence which supports file IO. This is potentially unsafe since this
+  // parses JSON in-process.
+  static Result IndexStaticRulesetsUnsafe(const Extension& extension);
 
  private:
   friend class base::RefCountedThreadSafe<IndexHelper>;
+  using IndexResults = std::vector<
+      std::pair<const RulesetSource*, IndexAndPersistJSONRulesetResult>>;
 
   IndexHelper(std::vector<RulesetSource> sources, IndexCallback callback);
   ~IndexHelper();
@@ -38,12 +66,16 @@
   void OnAllRulesetsIndexed();
 
   // Callback invoked when indexing of a single ruleset is completed.
+  // |source_index| is the index of the RulesetSource within |sources_|.
   void OnRulesetIndexed(base::OnceClosure ruleset_done_closure,
+                        size_t source_index,
                         IndexAndPersistJSONRulesetResult result);
 
-  std::vector<RulesetSource> sources_;
+  const std::vector<RulesetSource> sources_;
   IndexCallback callback_;
-  Results results_;
+
+  // Stores the result for each RulesetSource in |sources_|.
+  IndexResults results_;
 
   // We use a single shared Data Decoder service instance to process all of the
   // rulesets for this IndexHelper.
diff --git a/extensions/browser/api/declarative_net_request/ruleset_source.cc b/extensions/browser/api/declarative_net_request/ruleset_source.cc
index 6aa6738..0f585e5 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_source.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_source.cc
@@ -197,7 +197,6 @@
     const base::ElapsedTimer& timer) {
   if (read_result.status != Status::kSuccess) {
     return IndexAndPersistJSONRulesetResult::CreateErrorResult(
-        source.id(),
         GetErrorWithFilename(source.json_path(), read_result.error));
   }
 
@@ -209,7 +208,7 @@
   if (info.has_error()) {
     std::string error = GetErrorWithFilename(source.json_path(), info.error());
     return IndexAndPersistJSONRulesetResult::CreateErrorResult(
-        source.id(), std::move(error));
+        std::move(error));
   }
 
   // Don't cause a hard error if the regex failed compilation due to
@@ -225,8 +224,7 @@
   rules_count -= info.regex_limit_exceeded_rules().size();
 
   return IndexAndPersistJSONRulesetResult::CreateSuccessResult(
-      source.id(), ruleset_checksum, std::move(warnings), rules_count,
-      timer.Elapsed());
+      ruleset_checksum, std::move(warnings), rules_count, timer.Elapsed());
 }
 
 void OnSafeJSONParse(const base::FilePath& json_path,
@@ -235,7 +233,7 @@
                      data_decoder::DataDecoder::ValueOrError result) {
   if (!result.value) {
     std::move(callback).Run(IndexAndPersistJSONRulesetResult::CreateErrorResult(
-        source.id(), GetErrorWithFilename(json_path, *result.error)));
+        GetErrorWithFilename(json_path, *result.error)));
     return;
   }
 
@@ -252,13 +250,11 @@
 // static
 IndexAndPersistJSONRulesetResult
 IndexAndPersistJSONRulesetResult::CreateSuccessResult(
-    int ruleset_id,
     int ruleset_checksum,
     std::vector<InstallWarning> warnings,
     size_t rules_count,
     base::TimeDelta index_and_persist_time) {
   IndexAndPersistJSONRulesetResult result;
-  result.ruleset_id = ruleset_id;
   result.success = true;
   result.ruleset_checksum = ruleset_checksum;
   result.warnings = std::move(warnings);
@@ -269,10 +265,8 @@
 
 // static
 IndexAndPersistJSONRulesetResult
-IndexAndPersistJSONRulesetResult::CreateErrorResult(int ruleset_id,
-                                                    std::string error) {
+IndexAndPersistJSONRulesetResult::CreateErrorResult(std::string error) {
   IndexAndPersistJSONRulesetResult result;
-  result.ruleset_id = ruleset_id;
   result.success = false;
   result.error = std::move(error);
   return result;
@@ -376,14 +370,14 @@
 
   if (!base::PathExists(json_path_)) {
     std::move(callback).Run(IndexAndPersistJSONRulesetResult::CreateErrorResult(
-        id(), GetErrorWithFilename(json_path_, kFileDoesNotExistError)));
+        GetErrorWithFilename(json_path_, kFileDoesNotExistError)));
     return;
   }
 
   std::string json_contents;
   if (!base::ReadFileToString(json_path_, &json_contents)) {
     std::move(callback).Run(IndexAndPersistJSONRulesetResult::CreateErrorResult(
-        id(), GetErrorWithFilename(json_path_, kFileReadError)));
+        GetErrorWithFilename(json_path_, kFileReadError)));
     return;
   }
 
diff --git a/extensions/browser/api/declarative_net_request/ruleset_source.h b/extensions/browser/api/declarative_net_request/ruleset_source.h
index 2be060ad..8b02887 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_source.h
+++ b/extensions/browser/api/declarative_net_request/ruleset_source.h
@@ -40,13 +40,11 @@
 struct IndexAndPersistJSONRulesetResult {
  public:
   static IndexAndPersistJSONRulesetResult CreateSuccessResult(
-      int ruleset_id,
       int ruleset_checksum,
       std::vector<InstallWarning> warnings,
       size_t rules_count,
       base::TimeDelta index_and_persist_time);
-  static IndexAndPersistJSONRulesetResult CreateErrorResult(int ruleset_id,
-                                                            std::string error);
+  static IndexAndPersistJSONRulesetResult CreateErrorResult(std::string error);
   ~IndexAndPersistJSONRulesetResult();
   IndexAndPersistJSONRulesetResult(IndexAndPersistJSONRulesetResult&&);
   IndexAndPersistJSONRulesetResult& operator=(
@@ -55,9 +53,6 @@
   // Whether IndexAndPersistRules succeeded.
   bool success = false;
 
-  // ID for the ruleset.
-  int ruleset_id = kInvalidRulesetID;
-
   // Checksum of the persisted indexed ruleset file. Valid if |success| if true.
   // Note: there's no sane default value for this, any integer value is a valid
   // checksum value.
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
index 054bca8..a8e70ca 100644
--- a/extensions/browser/sandboxed_unpacker.cc
+++ b/extensions/browser/sandboxed_unpacker.cc
@@ -29,9 +29,7 @@
 #include "components/crx_file/crx_verifier.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "extensions/browser/api/declarative_net_request/constants.h"
 #include "extensions/browser/api/declarative_net_request/index_helper.h"
-#include "extensions/browser/api/declarative_net_request/ruleset_source.h"
 #include "extensions/browser/computed_hashes.h"
 #include "extensions/browser/extension_file_task_runner.h"
 #include "extensions/browser/install/crx_install_error.h"
@@ -692,48 +690,25 @@
   DCHECK(unpacker_io_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(extension_);
 
-  declarative_net_request::IndexHelper::Start(
-      declarative_net_request::RulesetSource::CreateStatic(*extension_),
+  declarative_net_request::IndexHelper::IndexStaticRulesets(
+      *extension_,
       base::BindOnce(&SandboxedUnpacker::OnJSONRulesetsIndexed, this));
 }
 
 void SandboxedUnpacker::OnJSONRulesetsIndexed(
-    std::vector<declarative_net_request::IndexAndPersistJSONRulesetResult>
-        results) {
-  // Early return if there were no rulesets to index originally.
-  if (results.empty()) {
-    CheckComputeHashes();
+    declarative_net_request::IndexHelper::Result result) {
+  if (result.error) {
+    ReportFailure(
+        SandboxedUnpackerFailureReason::ERROR_INDEXING_DNR_RULESET,
+        l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE,
+                                   base::UTF8ToUTF16(*result.error)));
     return;
   }
 
-  base::TimeDelta total_index_and_persist_time;
-  size_t total_rules_count = 0;
+  if (!result.warnings.empty())
+    extension_->AddInstallWarnings(std::move(result.warnings));
 
-  // TODO(crbug.com/754526): Impose a limit on the total number of rules across
-  // all the rulesets for an extension. Also, limit the number of install
-  // warnings across all rulesets.
-  for (auto& result : results) {
-    if (!result.success) {
-      ReportFailure(
-          SandboxedUnpackerFailureReason::ERROR_INDEXING_DNR_RULESET,
-          l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE,
-                                     base::UTF8ToUTF16(result.error)));
-      return;
-    }
-
-    if (!result.warnings.empty())
-      extension_->AddInstallWarnings(std::move(result.warnings));
-
-    total_index_and_persist_time += result.index_and_persist_time;
-    total_rules_count += result.rules_count;
-    ruleset_checksums_.emplace_back(result.ruleset_id, result.ruleset_checksum);
-  }
-
-  UMA_HISTOGRAM_TIMES(
-      declarative_net_request::kIndexAndPersistRulesTimeHistogram,
-      total_index_and_persist_time);
-  UMA_HISTOGRAM_COUNTS_100000(
-      declarative_net_request::kManifestRulesCountHistogram, total_rules_count);
+  ruleset_checksums_ = std::move(result.ruleset_checksums);
 
   CheckComputeHashes();
 }
diff --git a/extensions/browser/sandboxed_unpacker.h b/extensions/browser/sandboxed_unpacker.h
index 48411dd..d8c4295 100644
--- a/extensions/browser/sandboxed_unpacker.h
+++ b/extensions/browser/sandboxed_unpacker.h
@@ -18,6 +18,7 @@
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "extensions/browser/api/declarative_net_request/index_helper.h"
 #include "extensions/browser/api/declarative_net_request/ruleset_checksum.h"
 #include "extensions/browser/crx_file_info.h"
 #include "extensions/browser/image_sanitizer.h"
@@ -223,8 +224,7 @@
   void IndexAndPersistJSONRulesetsIfNeeded();
 
   void OnJSONRulesetsIndexed(
-      std::vector<declarative_net_request::IndexAndPersistJSONRulesetResult>
-          results);
+      declarative_net_request::IndexHelper::Result result);
 
   // Computed hashes: if requested (via ShouldComputeHashes callback in
   // SandbloxedUnpackerClient), calculate hashes of all extensions' resources
diff --git a/fuchsia/runners/cast/cast_runner.cmx b/fuchsia/runners/cast/cast_runner.cmx
index 43e4234..987ad94 100644
--- a/fuchsia/runners/cast/cast_runner.cmx
+++ b/fuchsia/runners/cast/cast_runner.cmx
@@ -3,6 +3,7 @@
     "features": [
       "config-data"
     ],
+    "$comment": "Not all services are passed to WebEngine, see cast_runner.cc",
     "services": [
       "chromium.cast.ApplicationConfigManager",
       "fuchsia.accessibility.semantics.SemanticsManager",
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc
index 0a79105..8c96e516 100644
--- a/gpu/command_buffer/service/shared_context_state.cc
+++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -13,6 +13,7 @@
 #include "gpu/command_buffer/service/gl_context_virtual.h"
 #include "gpu/command_buffer/service/service_transfer_cache.h"
 #include "gpu/command_buffer/service/service_utils.h"
+#include "gpu/command_buffer/service/skia_utils.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "gpu/config/skia_limits.h"
 #include "gpu/vulkan/buildflags.h"
@@ -222,14 +223,9 @@
     // affect text rendering, make sure to match the capabilities initialized
     // in GetCapabilities and ensuring these are also used by the
     // PaintOpBufferSerializer.
-    GrContextOptions options;
-    if (GrContextIsMetal()) {
-      options.fRuntimeProgramCacheSize = 1024;
-    }
+    GrContextOptions options = GetDefaultGrContextOptions(GrContextType::kGL);
     options.fDriverBugWorkarounds =
         GrDriverBugWorkarounds(workarounds.ToIntSet());
-    options.fDisableCoverageCountingPaths = true;
-    options.fGlyphCacheTextureMaximumBytes = glyph_cache_max_texture_bytes;
     options.fPersistentCache = cache;
     options.fAvoidStencilBuffers = workarounds.avoid_stencil_buffers;
     if (workarounds.disable_program_disk_cache) {
@@ -239,9 +235,6 @@
     options.fShaderErrorHandler = this;
     if (gpu_preferences.force_max_texture_size)
       options.fMaxTextureSizeOverride = gpu_preferences.force_max_texture_size;
-    // TODO(csmartdalton): enable internal multisampling after the related Skia
-    // rolls are in.
-    options.fInternalMultisampleCount = 0;
     owned_gr_context_ = GrContext::MakeGL(std::move(interface), options);
     gr_context_ = owned_gr_context_.get();
   }
diff --git a/gpu/command_buffer/service/skia_utils.cc b/gpu/command_buffer/service/skia_utils.cc
index b79adbb..977b55c0 100644
--- a/gpu/command_buffer/service/skia_utils.cc
+++ b/gpu/command_buffer/service/skia_utils.cc
@@ -9,6 +9,7 @@
 #include "components/viz/common/resources/resource_format_utils.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/config/skia_limits.h"
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/gl/GrGLTypes.h"
 #include "ui/gfx/geometry/size.h"
@@ -63,6 +64,26 @@
 
 }  // namespace
 
+GrContextOptions GetDefaultGrContextOptions(GrContextType type) {
+  // If you make any changes to the GrContext::Options here that could affect
+  // text rendering, make sure to match the capabilities initialized in
+  // GetCapabilities and ensuring these are also used by the
+  // PaintOpBufferSerializer.
+  GrContextOptions options;
+  size_t max_resource_cache_bytes;
+  size_t glyph_cache_max_texture_bytes;
+  DetermineGrCacheLimitsFromAvailableMemory(&max_resource_cache_bytes,
+                                            &glyph_cache_max_texture_bytes);
+  options.fDisableCoverageCountingPaths = true;
+  options.fGlyphCacheTextureMaximumBytes = glyph_cache_max_texture_bytes;
+  // TODO(csmartdalton): enable internal multisampling after the related Skia
+  // rolls are in.
+  options.fInternalMultisampleCount = 0;
+  if (type == GrContextType::kMetal)
+    options.fRuntimeProgramCacheSize = 1024;
+  return options;
+}
+
 GLuint GetGrGLBackendTextureFormat(const gles2::FeatureInfo* feature_info,
                                    viz::ResourceFormat resource_format) {
   const gl::GLVersionInfo* version_info = &feature_info->gl_version_info();
diff --git a/gpu/command_buffer/service/skia_utils.h b/gpu/command_buffer/service/skia_utils.h
index 0208f72b..e5661a0 100644
--- a/gpu/command_buffer/service/skia_utils.h
+++ b/gpu/command_buffer/service/skia_utils.h
@@ -8,10 +8,12 @@
 #include "base/callback_forward.h"
 #include "base/optional.h"
 #include "components/viz/common/resources/resource_format.h"
+#include "gpu/config/gpu_preferences.h"
 #include "gpu/gpu_gles2_export.h"
 #include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/vulkan/buildflags.h"
 #include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrContextOptions.h"
 #include "third_party/skia/include/gpu/GrTypes.h"
 #include "third_party/skia/include/gpu/vk/GrVkTypes.h"
 
@@ -42,6 +44,10 @@
 
 class SharedContextState;
 
+// Returns default GrContextOptions.
+GPU_GLES2_EXPORT GrContextOptions
+GetDefaultGrContextOptions(GrContextType type);
+
 // Returns internal gl format of texture for Skia
 GPU_GLES2_EXPORT GLuint
 GetGrGLBackendTextureFormat(const gles2::FeatureInfo* feature_info,
diff --git a/gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.cc b/gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.cc
index 8c67295..1fd21b6 100644
--- a/gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.cc
+++ b/gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.cc
@@ -39,6 +39,12 @@
     case gfx::BufferFormat::BGR_565:
       desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
       break;
+    case gfx::BufferFormat::RGBA_F16:
+      desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
+      break;
+    case gfx::BufferFormat::RGBA_1010102:
+      desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
+      break;
     default:
       NOTREACHED();
   }
diff --git a/gpu/vulkan/BUILD.gn b/gpu/vulkan/BUILD.gn
index f4fac365..926ab26 100644
--- a/gpu/vulkan/BUILD.gn
+++ b/gpu/vulkan/BUILD.gn
@@ -174,6 +174,7 @@
         "//base:base",
         "//base/test:test_support",
         "//components/viz/common:vulkan_context_provider",
+        "//gpu/ipc/service",
         "//gpu/vulkan/init",
         "//testing/gmock",
         "//testing/gtest",
@@ -184,6 +185,10 @@
         "//ui/gfx/geometry",
       ]
 
+      if (is_android) {
+        deps += [ "//ui/android:ui_java_test_support" ]
+      }
+
       if (use_x11) {
         deps += [ "//ui/events/platform/x11" ]
       }
diff --git a/gpu/vulkan/vulkan_image_unittest.cc b/gpu/vulkan/vulkan_image_unittest.cc
index 48051aa5..121faf8 100644
--- a/gpu/vulkan/vulkan_image_unittest.cc
+++ b/gpu/vulkan/vulkan_image_unittest.cc
@@ -5,11 +5,16 @@
 #include "gpu/vulkan/vulkan_image.h"
 
 #include "build/build_config.h"
+#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
 #include "gpu/vulkan/tests/basic_vulkan_test.h"
 #include "gpu/vulkan/vulkan_device_queue.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
 #include "ui/gfx/geometry/rect.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/android_hardware_buffer_compat.h"
+#endif
+
 namespace gpu {
 
 namespace {
@@ -113,6 +118,64 @@
   }
 }
 
-// TODO(penghuang): Add test for creating from GpuMemoryBufferHandle
+#if defined(OS_ANDROID)
+TEST_F(VulkanImageTest, CreateFromGpuMemoryBufferHandle) {
+  if (!base::AndroidHardwareBufferCompat::IsSupportAvailable()) {
+    LOG(ERROR) << "AndroidHardwareBuffer is not supported";
+    return;
+  }
+
+  auto* device_queue = GetDeviceQueue();
+  if (!gfx::HasExtension(
+          device_queue->enabled_extensions(),
+          VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME)) {
+    LOG(ERROR) << "Vulkan extension "
+                  "VK_ANDROID_external_memory_android_hardware_buffer is not "
+                  "supported";
+    return;
+  }
+
+  auto factory = GpuMemoryBufferFactory::CreateNativeType(
+      /*viz::VulkanContextProvider=*/nullptr);
+  EXPECT_TRUE(factory);
+  constexpr gfx::Size size(100, 100);
+  constexpr VkImageUsageFlags usage =
+      VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+      VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+  const struct {
+    gfx::BufferFormat buffer;
+    VkFormat vk;
+  } formats[] = {
+      {gfx::BufferFormat::RGBA_8888, VK_FORMAT_R8G8B8A8_UNORM},
+      {gfx::BufferFormat::BGR_565, VK_FORMAT_R5G6B5_UNORM_PACK16},
+      {gfx::BufferFormat::RGBA_F16, VK_FORMAT_R16G16B16A16_SFLOAT},
+      {gfx::BufferFormat::RGBX_8888, VK_FORMAT_R8G8B8A8_UNORM},
+      {gfx::BufferFormat::RGBA_1010102, VK_FORMAT_A2B10G10R10_UNORM_PACK32},
+  };
+  for (const auto format : formats) {
+    gfx::GpuMemoryBufferId id(1);
+    gfx::BufferUsage buffer_usage = gfx::BufferUsage::SCANOUT;
+    int client_id = 1;
+    auto gmb_handle = factory->CreateGpuMemoryBuffer(
+        id, size, format.buffer, buffer_usage, client_id, kNullSurfaceHandle);
+    EXPECT_TRUE(!gmb_handle.is_null());
+    EXPECT_EQ(gmb_handle.type,
+              gfx::GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER);
+    auto image = VulkanImage::CreateFromGpuMemoryBufferHandle(
+        device_queue, std::move(gmb_handle), size, format.vk, usage);
+    EXPECT_TRUE(image);
+    EXPECT_EQ(image->size(), size);
+    EXPECT_EQ(image->format(), format.vk);
+    EXPECT_GT(image->device_size(), 0u);
+    EXPECT_EQ(image->image_tiling(), VK_IMAGE_TILING_OPTIMAL);
+    EXPECT_EQ(image->image_layout(), VK_IMAGE_LAYOUT_UNDEFINED);
+    EXPECT_NE(image->image(), static_cast<VkImage>(VK_NULL_HANDLE));
+    EXPECT_NE(image->device_memory(),
+              static_cast<VkDeviceMemory>(VK_NULL_HANDLE));
+    image->Destroy();
+    factory->DestroyGpuMemoryBuffer(id, client_id);
+  }
+}
+#endif
 
 }  // namespace gpu
diff --git a/gpu/vulkan/vulkan_surface.cc b/gpu/vulkan/vulkan_surface.cc
index 00c2020..3571fb0 100644
--- a/gpu/vulkan/vulkan_surface.cc
+++ b/gpu/vulkan/vulkan_surface.cc
@@ -201,8 +201,8 @@
   VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
       device_queue_->GetVulkanPhysicalDevice(), surface_, &surface_caps);
   if (VK_SUCCESS != result) {
-    DLOG(ERROR) << "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() failed: "
-                << result;
+    LOG(FATAL) << "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() failed: "
+               << result;
     return false;
   }
 
diff --git a/gpu/vulkan/vulkan_swap_chain.cc b/gpu/vulkan/vulkan_swap_chain.cc
index b80989b..2e9c7db 100644
--- a/gpu/vulkan/vulkan_swap_chain.cc
+++ b/gpu/vulkan/vulkan_swap_chain.cc
@@ -125,7 +125,7 @@
 
   result = vkQueuePresentKHR(queue, &present_info);
   if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
-    DLOG(ERROR) << "vkQueuePresentKHR() failed: " << result;
+    LOG(FATAL) << "vkQueuePresentKHR() failed: " << result;
     return gfx::SwapResult::SWAP_FAILED;
   }
   DLOG_IF(ERROR, result == VK_SUBOPTIMAL_KHR) << "Swapchian is suboptimal.";
@@ -158,6 +158,7 @@
     VkSurfaceTransformFlagBitsKHR pre_transform,
     bool use_protected_memory,
     std::unique_ptr<VulkanSwapChain> old_swap_chain) {
+  DCHECK(!acquired_image_);
   VkDevice device = device_queue_->GetVulkanDevice();
   VkResult result = VK_SUCCESS;
 
@@ -192,7 +193,7 @@
   }
 
   if (VK_SUCCESS != result) {
-    DLOG(ERROR) << "vkCreateSwapchainKHR() failed: " << result;
+    LOG(FATAL) << "vkCreateSwapchainKHR() failed: " << result;
     return false;
   }
 
@@ -219,7 +220,7 @@
   uint32_t image_count = 0;
   result = vkGetSwapchainImagesKHR(device, swap_chain_, &image_count, nullptr);
   if (VK_SUCCESS != result) {
-    DLOG(ERROR) << "vkGetSwapchainImagesKHR(NULL) failed: " << result;
+    LOG(FATAL) << "vkGetSwapchainImagesKHR(nullptr) failed: " << result;
     return false;
   }
 
@@ -227,7 +228,7 @@
   result =
       vkGetSwapchainImagesKHR(device, swap_chain_, &image_count, images.data());
   if (VK_SUCCESS != result) {
-    DLOG(ERROR) << "vkGetSwapchainImagesKHR(images) failed: " << result;
+    LOG(FATAL) << "vkGetSwapchainImagesKHR(images) failed: " << result;
     return false;
   }
 
@@ -352,7 +353,7 @@
                               VK_NULL_HANDLE, &next_image);
     if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
       vkDestroySemaphore(device, vk_semaphore, nullptr /* pAllocator */);
-      DLOG(ERROR) << "vkAcquireNextImageKHR() failed: " << result;
+      LOG(FATAL) << "vkAcquireNextImageKHR() failed: " << result;
       return false;
     }
 
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index bb7c613..4baa899 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -144,6 +144,7 @@
         location_regexp: ".+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+"
         location_regexp: ".+/[+]/chrome/android/javatests/src/org/chromium/chrome/browser/vr/.+"
         location_regexp: ".+/[+]/chrome/browser/vr/.+"
+        location_regexp: ".+/[+]/content/browser/xr/.+"
         location_regexp: ".+/[+]/third_party/gvr-android-sdk/.+"
         location_regexp: ".+/[+]/third_party/arcore-android-sdk/.+"
         location_regexp: ".+/[+]/third_party/arcore-android-sdk-client/.+"
@@ -230,6 +231,7 @@
         name: "chromium/try/android_compile_x64_dbg"
         location_regexp: ".+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+"
         location_regexp: ".+/[+]/chrome/browser/vr/.+"
+        location_regexp: ".+/[+]/content/browser/xr/.+"
         location_regexp: ".+/[+]/sandbox/linux/seccomp-bpf/.+"
         location_regexp: ".+/[+]/sandbox/linux/seccomp-bpf-helpers/.+"
         location_regexp: ".+/[+]/sandbox/linux/system_headers/.+"
@@ -240,6 +242,7 @@
         name: "chromium/try/android_compile_x86_dbg"
         location_regexp: ".+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+"
         location_regexp: ".+/[+]/chrome/browser/vr/.+"
+        location_regexp: ".+/[+]/content/browser/xr/.+"
         location_regexp: ".+/[+]/sandbox/linux/seccomp-bpf/.+"
         location_regexp: ".+/[+]/sandbox/linux/seccomp-bpf-helpers/.+"
         location_regexp: ".+/[+]/sandbox/linux/system_headers/.+"
@@ -265,6 +268,7 @@
         name: "chromium/try/android_optional_gpu_tests_rel"
         location_regexp: ".+/[+]/cc/.+"
         location_regexp: ".+/[+]/chrome/browser/vr/.+"
+        location_regexp: ".+/[+]/content/browser/xr/.+"
         location_regexp: ".+/[+]/components/viz/.+"
         location_regexp: ".+/[+]/content/test/gpu/.+"
         location_regexp: ".+/[+]/gpu/.+"
@@ -931,6 +935,7 @@
       builders: <
         name: "chromium/try/linux_optional_gpu_tests_rel"
         location_regexp: ".+/[+]/chrome/browser/vr/.+"
+        location_regexp: ".+/[+]/content/browser/xr/.+"
         location_regexp: ".+/[+]/content/test/gpu/.+"
         location_regexp: ".+/[+]/gpu/.+"
         location_regexp: ".+/[+]/media/audio/.+"
@@ -950,6 +955,7 @@
       builders: <
         name: "chromium/try/linux_vr"
         location_regexp: ".+/[+]/chrome/browser/vr/.+"
+        location_regexp: ".+/[+]/content/browser/xr/.+"
       >
       builders: <
         name: "chromium/try/mac-angle-rel"
@@ -1044,6 +1050,7 @@
       builders: <
         name: "chromium/try/mac_optional_gpu_tests_rel"
         location_regexp: ".+/[+]/chrome/browser/vr/.+"
+        location_regexp: ".+/[+]/content/browser/xr/.+"
         location_regexp: ".+/[+]/content/test/gpu/.+"
         location_regexp: ".+/[+]/gpu/.+"
         location_regexp: ".+/[+]/media/audio/.+"
@@ -1185,6 +1192,7 @@
       builders: <
         name: "chromium/try/win_optional_gpu_tests_rel"
         location_regexp: ".+/[+]/chrome/browser/vr/.+"
+        location_regexp: ".+/[+]/content/browser/xr/.+"
         location_regexp: ".+/[+]/content/test/gpu/.+"
         location_regexp: ".+/[+]/device/vr/.+"
         location_regexp: ".+/[+]/gpu/.+"
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index 07b2df1..c474ee10 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -94,6 +94,7 @@
   * [`//chrome/android/java/src/org/chromium/chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/vr/)
   * [`//chrome/android/javatests/src/org/chromium/chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/android/javatests/src/org/chromium/chrome/browser/vr/)
   * [`//chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/browser/vr/)
+  * [`//content/browser/xr/.+`](https://cs.chromium.org/chromium/src/content/browser/xr/)
   * [`//third_party/gvr-android-sdk/.+`](https://cs.chromium.org/chromium/src/third_party/gvr-android-sdk/)
   * [`//third_party/arcore-android-sdk/.+`](https://cs.chromium.org/chromium/src/third_party/arcore-android-sdk/)
   * [`//third_party/arcore-android-sdk-client/.+`](https://cs.chromium.org/chromium/src/third_party/arcore-android-sdk-client/)
@@ -103,6 +104,7 @@
   Path regular expressions:
   * [`//chrome/android/java/src/org/chromium/chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/vr/)
   * [`//chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/browser/vr/)
+  * [`//content/browser/xr/.+`](https://cs.chromium.org/chromium/src/content/browser/xr/)
   * [`//sandbox/linux/seccomp-bpf/.+`](https://cs.chromium.org/chromium/src/sandbox/linux/seccomp-bpf/)
   * [`//sandbox/linux/seccomp-bpf-helpers/.+`](https://cs.chromium.org/chromium/src/sandbox/linux/seccomp-bpf-helpers/)
   * [`//sandbox/linux/system_headers/.+`](https://cs.chromium.org/chromium/src/sandbox/linux/system_headers/)
@@ -114,6 +116,7 @@
   Path regular expressions:
   * [`//chrome/android/java/src/org/chromium/chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/vr/)
   * [`//chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/browser/vr/)
+  * [`//content/browser/xr/.+`](https://cs.chromium.org/chromium/src/content/browser/xr/)
   * [`//sandbox/linux/seccomp-bpf/.+`](https://cs.chromium.org/chromium/src/sandbox/linux/seccomp-bpf/)
   * [`//sandbox/linux/seccomp-bpf-helpers/.+`](https://cs.chromium.org/chromium/src/sandbox/linux/seccomp-bpf-helpers/)
   * [`//sandbox/linux/system_headers/.+`](https://cs.chromium.org/chromium/src/sandbox/linux/system_headers/)
@@ -125,6 +128,7 @@
   Path regular expressions:
   * [`//cc/.+`](https://cs.chromium.org/chromium/src/cc/)
   * [`//chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/browser/vr/)
+  * [`//content/browser/xr/.+`](https://cs.chromium.org/chromium/src/content/browser/xr/)
   * [`//components/viz/.+`](https://cs.chromium.org/chromium/src/components/viz/)
   * [`//content/test/gpu/.+`](https://cs.chromium.org/chromium/src/content/test/gpu/)
   * [`//gpu/.+`](https://cs.chromium.org/chromium/src/gpu/)
@@ -269,6 +273,7 @@
 
   Path regular expressions:
   * [`//chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/browser/vr/)
+  * [`//content/browser/xr/.+`](https://cs.chromium.org/chromium/src/content/browser/xr/)
   * [`//content/test/gpu/.+`](https://cs.chromium.org/chromium/src/content/test/gpu/)
   * [`//gpu/.+`](https://cs.chromium.org/chromium/src/gpu/)
   * [`//media/audio/.+`](https://cs.chromium.org/chromium/src/media/audio/)
@@ -285,11 +290,13 @@
 
   Path regular expressions:
   * [`//chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/browser/vr/)
+  * [`//content/browser/xr/.+`](https://cs.chromium.org/chromium/src/content/browser/xr/)
 
 * [mac_optional_gpu_tests_rel](https://ci.chromium.org/p/chromium/builders/try/mac_optional_gpu_tests_rel) ([definition](https://cs.chromium.org/search?q=package:%5Echromium$+file:/cq.star$+-file:/beta/+-file:/stable/+mac_optional_gpu_tests_rel)) ([matching builders](https://cs.chromium.org/search?q=+file:trybots.py+mac_optional_gpu_tests_rel))
 
   Path regular expressions:
   * [`//chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/browser/vr/)
+  * [`//content/browser/xr/.+`](https://cs.chromium.org/chromium/src/content/browser/xr/)
   * [`//content/test/gpu/.+`](https://cs.chromium.org/chromium/src/content/test/gpu/)
   * [`//gpu/.+`](https://cs.chromium.org/chromium/src/gpu/)
   * [`//media/audio/.+`](https://cs.chromium.org/chromium/src/media/audio/)
@@ -307,6 +314,7 @@
 
   Path regular expressions:
   * [`//chrome/browser/vr/.+`](https://cs.chromium.org/chromium/src/chrome/browser/vr/)
+  * [`//content/browser/xr/.+`](https://cs.chromium.org/chromium/src/content/browser/xr/)
   * [`//content/test/gpu/.+`](https://cs.chromium.org/chromium/src/content/test/gpu/)
   * [`//device/vr/.+`](https://cs.chromium.org/chromium/src/device/vr/)
   * [`//gpu/.+`](https://cs.chromium.org/chromium/src/gpu/)
diff --git a/infra/config/versioned/trunk/buckets/try.star b/infra/config/versioned/trunk/buckets/try.star
index eb17e95c..916541a7 100644
--- a/infra/config/versioned/trunk/buckets/try.star
+++ b/infra/config/versioned/trunk/buckets/try.star
@@ -119,6 +119,7 @@
             '.+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+',
             '.+/[+]/chrome/android/javatests/src/org/chromium/chrome/browser/vr/.+',
             '.+/[+]/chrome/browser/vr/.+',
+            '.+/[+]/content/browser/xr/.+',
             '.+/[+]/third_party/gvr-android-sdk/.+',
             '.+/[+]/third_party/arcore-android-sdk/.+',
             '.+/[+]/third_party/arcore-android-sdk-client/.+',
@@ -146,6 +147,7 @@
         location_regexp = [
             '.+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+',
             '.+/[+]/chrome/browser/vr/.+',
+            '.+/[+]/content/browser/xr/.+',
             '.+/[+]/sandbox/linux/seccomp-bpf/.+',
             '.+/[+]/sandbox/linux/seccomp-bpf-helpers/.+',
             '.+/[+]/sandbox/linux/system_headers/.+',
@@ -161,6 +163,7 @@
         location_regexp = [
             '.+/[+]/chrome/android/java/src/org/chromium/chrome/browser/vr/.+',
             '.+/[+]/chrome/browser/vr/.+',
+            '.+/[+]/content/browser/xr/.+',
             '.+/[+]/sandbox/linux/seccomp-bpf/.+',
             '.+/[+]/sandbox/linux/seccomp-bpf-helpers/.+',
             '.+/[+]/sandbox/linux/system_headers/.+',
@@ -451,6 +454,7 @@
     tryjob = try_.job(
         location_regexp = [
             '.+/[+]/chrome/browser/vr/.+',
+            '.+/[+]/content/browser/xr/.+',
         ],
     ),
 )
@@ -535,6 +539,7 @@
         location_regexp = [
             '.+/[+]/cc/.+',
             '.+/[+]/chrome/browser/vr/.+',
+            '.+/[+]/content/browser/xr/.+',
             '.+/[+]/components/viz/.+',
             '.+/[+]/content/test/gpu/.+',
             '.+/[+]/gpu/.+',
@@ -557,6 +562,7 @@
     tryjob = try_.job(
         location_regexp = [
             '.+/[+]/chrome/browser/vr/.+',
+            '.+/[+]/content/browser/xr/.+',
             '.+/[+]/content/test/gpu/.+',
             '.+/[+]/gpu/.+',
             '.+/[+]/media/audio/.+',
@@ -578,6 +584,7 @@
     tryjob = try_.job(
         location_regexp = [
             '.+/[+]/chrome/browser/vr/.+',
+            '.+/[+]/content/browser/xr/.+',
             '.+/[+]/content/test/gpu/.+',
             '.+/[+]/gpu/.+',
             '.+/[+]/media/audio/.+',
@@ -602,6 +609,7 @@
     tryjob = try_.job(
         location_regexp = [
             '.+/[+]/chrome/browser/vr/.+',
+            '.+/[+]/content/browser/xr/.+',
             '.+/[+]/content/test/gpu/.+',
             '.+/[+]/device/vr/.+',
             '.+/[+]/gpu/.+',
diff --git a/ios/third_party/webkit/run-clusterfuzz.sh b/ios/third_party/webkit/run-clusterfuzz.sh
new file mode 100755
index 0000000..fd5de418
--- /dev/null
+++ b/ios/third_party/webkit/run-clusterfuzz.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# This script is used to launch WebKitTestRunner on ClusterFuzz bots.
+
+BASEDIR=$(dirname "$0")
+LIBDIR=$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/10.0.1/lib/darwin
+DYLD_FRAMEWORK_PATH=$BASEDIR DYLD_LIBRARY_PATH=$LIBDIR ./WebKitTestRunner $@
diff --git a/media/filters/BUILD.gn b/media/filters/BUILD.gn
index 9b97365..5faaf0c4 100644
--- a/media/filters/BUILD.gn
+++ b/media/filters/BUILD.gn
@@ -187,6 +187,13 @@
         "ffmpeg_video_decoder.h",
       ]
     }
+
+    if (is_android) {
+      sources += [
+        "android/video_frame_extractor.cc",
+        "android/video_frame_extractor.h",
+      ]
+    }
   }
 
   if (is_android) {
@@ -199,8 +206,6 @@
     sources += [
       "android/media_codec_audio_decoder.cc",
       "android/media_codec_audio_decoder.h",
-      "android/video_frame_extractor.cc",
-      "android/video_frame_extractor.h",
     ]
     deps += [ "//media/base/android" ]
   }
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc
index 298ecc1..d89177c 100644
--- a/media/renderers/paint_canvas_video_renderer.cc
+++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -36,6 +36,7 @@
 #include "third_party/libyuv/include/libyuv.h"
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkImageGenerator.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
 #include "third_party/skia/include/gpu/GrBackendSurface.h"
 #include "third_party/skia/include/gpu/GrContext.h"
 #include "third_party/skia/include/gpu/gl/GrGLTypes.h"
@@ -47,12 +48,14 @@
 // shown here to indicate where ideal conversions are currently missing.
 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
     SK_A32_SHIFT == 24
+#define LIBYUV_I400_TO_ARGB libyuv::I400ToARGB
 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
 #define LIBYUV_I444_TO_ARGB libyuv::I444ToARGB
 
 #define LIBYUV_I420ALPHA_TO_ARGB libyuv::I420AlphaToARGB
 
+#define LIBYUV_J400_TO_ARGB libyuv::J400ToARGB
 #define LIBYUV_J420_TO_ARGB libyuv::J420ToARGB
 #define LIBYUV_J422_TO_ARGB libyuv::J422ToARGB
 #define LIBYUV_J444_TO_ARGB libyuv::J444ToARGB
@@ -84,12 +87,14 @@
 #define LIBYUV_NV12_TO_ARGB libyuv::NV12ToARGB
 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
     SK_A32_SHIFT == 24
+#define LIBYUV_I400_TO_ARGB libyuv::I400ToARGB
 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
 #define LIBYUV_I444_TO_ARGB libyuv::I444ToABGR
 
 #define LIBYUV_I420ALPHA_TO_ARGB libyuv::I420AlphaToABGR
 
+#define LIBYUV_J400_TO_ARGB libyuv::J400ToARGB
 #define LIBYUV_J420_TO_ARGB libyuv::J420ToABGR
 #define LIBYUV_J422_TO_ARGB libyuv::J422ToABGR
 #define LIBYUV_J444_TO_ARGB libyuv::J444ToABGR
@@ -424,6 +429,18 @@
   SkYUVColorSpace color_space = kRec601_SkYUVColorSpace;
   video_frame->ColorSpace().ToSkYUVColorSpace(&color_space);
 
+  if (!video_frame->data(VideoFrame::kUPlane) &&
+      !video_frame->data(VideoFrame::kVPlane)) {
+    DCHECK_EQ(video_frame->format(), PIXEL_FORMAT_I420);
+    auto func = (color_space == kJPEG_SkYUVColorSpace) ? LIBYUV_J400_TO_ARGB
+                                                       : LIBYUV_I400_TO_ARGB;
+    func(plane_meta[VideoFrame::kYPlane].data,
+         plane_meta[VideoFrame::kYPlane].stride, pixels, row_bytes, width,
+         rows);
+    done->Run();
+    return;
+  }
+
   auto convert_yuv = [&](auto&& func) {
     func(plane_meta[VideoFrame::kYPlane].data,
          plane_meta[VideoFrame::kYPlane].stride,
@@ -903,6 +920,7 @@
   VideoPixelFormat format;
   switch (video_frame->format()) {
     case PIXEL_FORMAT_YUV420P12:
+    case PIXEL_FORMAT_YUV420P10:
     case PIXEL_FORMAT_YUV420P9:
       format = PIXEL_FORMAT_I420;
       break;
@@ -938,6 +956,13 @@
     const uint16_t* src =
         reinterpret_cast<const uint16_t*>(video_frame->data(plane));
     uint8_t* dst = ret->data(plane);
+    if (!src) {
+      // An AV1 monochrome (grayscale) frame has no U and V planes. Set all U
+      // and V samples to the neutral value (128).
+      DCHECK_NE(plane, VideoFrame::kYPlane);
+      memset(dst, 128, ret->rows(plane) * ret->stride(plane));
+      continue;
+    }
     for (int row = 0; row < video_frame->rows(plane); row++) {
       for (int x = 0; x < width; x++) {
         dst[x] = src[x] >> shift;
@@ -1100,6 +1125,17 @@
       temporary_frame = DownShiftHighbitVideoFrame(video_frame);
       video_frame = temporary_frame.get();
       break;
+    case PIXEL_FORMAT_YUV420P10:
+      // In AV1, a monochrome (grayscale) frame is represented as a YUV 4:2:0
+      // frame with no U and V planes. Since there are no 10-bit versions of
+      // libyuv::I400ToARGB() and libyuv::J400ToARGB(), convert the frame to an
+      // 8-bit YUV 4:2:0 frame with U and V planes.
+      if (!video_frame->data(VideoFrame::kUPlane) &&
+          !video_frame->data(VideoFrame::kVPlane)) {
+        temporary_frame = DownShiftHighbitVideoFrame(video_frame);
+        video_frame = temporary_frame.get();
+      }
+      break;
     case PIXEL_FORMAT_Y16:
       // Since it is grayscale conversion, we disregard
       // SK_PMCOLOR_BYTE_ORDER and always use GL_RGBA.
diff --git a/pdf/pdf_features.cc b/pdf/pdf_features.cc
index 3e6aca0..a1dacfa 100644
--- a/pdf/pdf_features.cc
+++ b/pdf/pdf_features.cc
@@ -11,7 +11,7 @@
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kAccessiblePDFHighlight = {
-    "AccessiblePDFHighlight", base::FEATURE_DISABLED_BY_DEFAULT};
+    "AccessiblePDFHighlight", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kPDFAnnotations = {"PDFAnnotations",
 #if defined(OS_CHROMEOS)
diff --git a/remoting/host/file_transfer/BUILD.gn b/remoting/host/file_transfer/BUILD.gn
index 22e913b..c15699d8 100644
--- a/remoting/host/file_transfer/BUILD.gn
+++ b/remoting/host/file_transfer/BUILD.gn
@@ -23,6 +23,7 @@
   deps = [
     "//base",
     "//remoting/protocol",
+    "//remoting/resources",
   ]
 
   if (is_mac) {
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 067d4c4..ca6c8703 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -55,6 +55,7 @@
 #include "net/base/host_port_pair.h"
 #include "net/base/http_user_agent_settings.h"
 #include "net/base/ip_endpoint.h"
+#include "net/base/isolation_info.h"
 #include "net/base/net_errors.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/network_isolation_key.h"
@@ -218,14 +219,13 @@
   // If |site_for_cookies| is null, any non-empty NIK is fine. Otherwise, the
   // NIK must be consistent with |site_for_cookies|.
   if (request.site_for_cookies.IsNull()) {
-    params->network_isolation_key =
-        net::NetworkIsolationKey(url::Origin::Create(GURL("https://abc.com")),
-                                 url::Origin::Create(GURL("https://xyz.com")));
+    params->isolation_info = net::IsolationInfo::Create(
+        net::IsolationInfo::RedirectMode::kUpdateNothing,
+        url::Origin::Create(GURL("https://abc.com")),
+        url::Origin::Create(GURL("https://xyz.com")), request.site_for_cookies);
   } else {
-    url::Origin first_party_origin =
-        url::Origin::Create(request.site_for_cookies.RepresentativeUrl());
-    params->network_isolation_key =
-        net::NetworkIsolationKey(first_party_origin, first_party_origin);
+    params->isolation_info = net::IsolationInfo::CreateForInternalRequest(
+        url::Origin::Create(request.site_for_cookies.RepresentativeUrl()));
   }
 
   network_context->CreateURLLoaderFactory(
@@ -6250,16 +6250,11 @@
 
   net::EmbeddedTestServer* test_server() { return &test_server_; }
 
-  void LoadAndVerifyCached(
-      const GURL& url,
-      const net::NetworkIsolationKey& key,
-      bool was_cached,
-      bool is_navigation,
-      mojom::UpdateNetworkIsolationKeyOnRedirect
-          update_network_isolation_key_on_redirect =
-              mojom::UpdateNetworkIsolationKeyOnRedirect::kDoNotUpdate,
-      bool expect_redirect = false,
-      base::Optional<GURL> new_url = base::nullopt) {
+  void LoadAndVerifyCached(const GURL& url,
+                           const net::IsolationInfo& isolation_info,
+                           bool was_cached,
+                           bool expect_redirect = false,
+                           base::Optional<GURL> new_url = base::nullopt) {
     ResourceRequest request = CreateResourceRequest("GET", url);
     request.load_flags |= net::LOAD_SKIP_CACHE_VALIDATION;
 
@@ -6267,19 +6262,24 @@
     auto params = mojom::URLLoaderFactoryParams::New();
     params->process_id = mojom::kBrowserProcessId;
     params->is_corb_enabled = false;
-    if (is_navigation) {
-      request.trusted_params = ResourceRequest::TrustedParams();
-      request.trusted_params->network_isolation_key = key;
-      request.trusted_params->update_network_isolation_key_on_redirect =
-          update_network_isolation_key_on_redirect;
-      params->is_trusted = true;
+    if (isolation_info.redirect_mode() ==
+        net::IsolationInfo::RedirectMode::kUpdateNothing) {
+      params->isolation_info = isolation_info;
     } else {
-      // Different |update_network_isolation_key_on_redirect| values may only be
-      // set for navigations.
-      DCHECK_EQ(mojom::UpdateNetworkIsolationKeyOnRedirect::kDoNotUpdate,
-                update_network_isolation_key_on_redirect);
-      params->network_isolation_key = key;
+      request.trusted_params = ResourceRequest::TrustedParams();
+      request.trusted_params->network_isolation_key =
+          isolation_info.network_isolation_key();
+      request.trusted_params->update_network_isolation_key_on_redirect =
+          isolation_info.redirect_mode() ==
+                  net::IsolationInfo::RedirectMode::kUpdateTopFrame
+              ? mojom::UpdateNetworkIsolationKeyOnRedirect::
+                    kUpdateTopFrameAndFrameOrigin
+              : mojom::UpdateNetworkIsolationKeyOnRedirect::kUpdateFrameOrigin;
+      params->is_trusted = true;
     }
+
+    request.site_for_cookies = isolation_info.site_for_cookies();
+
     network_context_->CreateURLLoaderFactory(
         loader_factory.BindNewPipeAndPassReceiver(), std::move(params));
     auto client = std::make_unique<TestURLLoaderClient>();
@@ -6317,41 +6317,41 @@
 TEST_F(NetworkContextSplitCacheTest, CachedUsingNetworkIsolationKey) {
   GURL url = test_server()->GetURL("/resource");
   url::Origin origin_a = url::Origin::Create(GURL("http://a.test/"));
-  net::NetworkIsolationKey key_a(origin_a, origin_a);
-  LoadAndVerifyCached(url, key_a, false /* was_cached */,
-                      false /* is_navigation */);
+  net::IsolationInfo info_a =
+      net::IsolationInfo::CreateForInternalRequest(origin_a);
+  LoadAndVerifyCached(url, info_a, false /* was_cached */);
 
   // Load again with a different isolation key. The cached entry should not be
   // loaded.
   url::Origin origin_b = url::Origin::Create(GURL("http://b.test/"));
-  net::NetworkIsolationKey key_b(origin_b, origin_b);
-  LoadAndVerifyCached(url, key_b, false /* was_cached */,
-                      false /* is_navigation */);
+  net::IsolationInfo info_b =
+      net::IsolationInfo::CreateForInternalRequest(origin_b);
+  LoadAndVerifyCached(url, info_b, false /* was_cached */);
 
   // Load again with the same isolation key. The cached entry should be loaded.
-  LoadAndVerifyCached(url, key_b, true /* was_cached */,
-                      false /* is_navigation */);
+  LoadAndVerifyCached(url, info_b, true /* was_cached */);
 }
 
 TEST_F(NetworkContextSplitCacheTest,
        NavigationResourceCachedUsingNetworkIsolationKey) {
   GURL url = test_server()->GetURL("othersite.test", "/main.html");
   url::Origin origin_a = url::Origin::Create(url);
-  net::NetworkIsolationKey key_a(origin_a, origin_a);
-  LoadAndVerifyCached(url, key_a, false /* was_cached */,
-                      true /* is_navigation */);
+  net::IsolationInfo info_a = net::IsolationInfo::Create(
+      net::IsolationInfo::RedirectMode::kUpdateFrameOnly, origin_a, origin_a,
+      net::SiteForCookies());
+  LoadAndVerifyCached(url, info_a, false /* was_cached */);
 
   // Load again with a different isolation key. The cached entry should not be
   // loaded.
   GURL url_b = test_server()->GetURL("/main.html");
   url::Origin origin_b = url::Origin::Create(url_b);
-  net::NetworkIsolationKey key_b(origin_b, origin_b);
-  LoadAndVerifyCached(url_b, key_b, false /* was_cached */,
-                      true /* is_navigation */);
+  net::IsolationInfo info_b = net::IsolationInfo::Create(
+      net::IsolationInfo::RedirectMode::kUpdateFrameOnly, origin_b, origin_b,
+      net::SiteForCookies());
+  LoadAndVerifyCached(url_b, info_b, false /* was_cached */);
 
   // Load again with the same isolation key. The cached entry should be loaded.
-  LoadAndVerifyCached(url_b, key_b, true /* was_cached */,
-                      true /* is_navigation */);
+  LoadAndVerifyCached(url_b, info_b, true /* was_cached */);
 }
 
 TEST_F(NetworkContextSplitCacheTest,
@@ -6364,16 +6364,18 @@
 
   GURL url = test_server()->GetURL("/resource");
   url::Origin origin_a = url::Origin::Create(GURL("http://a.test/"));
-  net::NetworkIsolationKey key_a(origin_a, origin_a);
-  LoadAndVerifyCached(url, key_a, false /* was_cached */,
-                      false /* is_navigation */);
+  net::IsolationInfo info_a = net::IsolationInfo::Create(
+      net::IsolationInfo::RedirectMode::kUpdateNothing, origin_a, origin_a,
+      net::SiteForCookies());
+  LoadAndVerifyCached(url, info_a, false /* was_cached */);
 
   // Load again with a different isolation key. The cached entry should not be
   // loaded.
   url::Origin origin_b = url::Origin::Create(GURL("http://b.test/"));
-  net::NetworkIsolationKey key_b(origin_a, origin_b);
-  LoadAndVerifyCached(url, key_b, false /* was_cached */,
-                      false /* is_navigation */);
+  net::IsolationInfo info_b = net::IsolationInfo::Create(
+      net::IsolationInfo::RedirectMode::kUpdateNothing, origin_a, origin_b,
+      net::SiteForCookies());
+  LoadAndVerifyCached(url, info_b, false /* was_cached */);
 }
 
 TEST_F(NetworkContextSplitCacheTest,
@@ -6383,112 +6385,27 @@
       "/server-redirect?" +
       test_server()->GetURL("othersite.test", "/title1.html").spec());
   url::Origin origin = url::Origin::Create(url);
-  net::NetworkIsolationKey key(origin, origin);
-  LoadAndVerifyCached(
-      url, key, false /* was_cached */, true /* is_navigation */,
-      mojom::UpdateNetworkIsolationKeyOnRedirect::kUpdateTopFrameAndFrameOrigin,
-      true /* expect_redirect */);
+  net::IsolationInfo info = net::IsolationInfo::Create(
+      net::IsolationInfo::RedirectMode::kUpdateTopFrame, origin, origin,
+      net::SiteForCookies::FromOrigin(origin));
+  LoadAndVerifyCached(url, info, false /* was_cached */,
+                      true /* expect_redirect */);
 
   // Now directly load with the key using the redirected URL. This should be a
   // cache hit.
   GURL redirected_url = test_server()->GetURL("othersite.test", "/title1.html");
   url::Origin redirected_origin = url::Origin::Create(redirected_url);
-  LoadAndVerifyCached(
-      redirected_url,
-      net::NetworkIsolationKey(redirected_origin, redirected_origin),
-      true /* was_cached */, true /* is_navigation */);
+  LoadAndVerifyCached(redirected_url, info.CreateForRedirect(redirected_origin),
+                      true /* was_cached */);
 
   // A non-navigation resource with the same key and url should also be cached.
-  LoadAndVerifyCached(
-      redirected_url,
-      net::NetworkIsolationKey(redirected_origin, redirected_origin),
-      true /* was_cached */, false /* is_navigation */);
-}
-
-TEST_F(NetworkContextSplitCacheTest,
-       NavigationResourceRedirectNetworkIsolationKeyWithNewUrl) {
-  // Create a request that redirects to othersite.test/title1.html.
-  GURL url = test_server()->GetURL(
-      "/server-redirect?" +
-      test_server()->GetURL("othersite.test", "/title1.html").spec());
-  url::Origin origin = url::Origin::Create(url);
-  net::NetworkIsolationKey key(origin, origin);
-
-  // Create a new url that should be used in the network isolation key computed
-  // in FollowRedirect instead of the redirected url.
-  GURL new_url = test_server()->GetURL("othersite.test", "/title2.html");
-  LoadAndVerifyCached(
-      url, key, false /* was_cached */, true /* is_navigation */,
-      mojom::UpdateNetworkIsolationKeyOnRedirect::kUpdateTopFrameAndFrameOrigin,
-      true /* expect_redirect */, new_url);
-
-  // Load with the key using the new url should be a cache hit.
-  origin = url::Origin::Create(new_url);
-  LoadAndVerifyCached(new_url, net::NetworkIsolationKey(origin, origin),
-                      true /* was_cached */, true /* is_navigation */);
-
-  // Now directly load with the key using the redirected URL. This should be a
-  // cache miss.
-  GURL redirected_url = test_server()->GetURL("othersite.test", "/title1.html");
-  origin = url::Origin::Create(redirected_url);
-  LoadAndVerifyCached(redirected_url, net::NetworkIsolationKey(origin, origin),
-                      false /* was_cached */, true /* is_navigation */);
-}
-
-TEST_F(NetworkContextSplitCacheTest,
-       NavigationResourceCachedUsingNetworkIsolationKeyWithFrameOrigin) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      {net::features::kSplitCacheByNetworkIsolationKey,
-       net::features::kAppendFrameOriginToNetworkIsolationKey},
-      {});
-  GURL url = test_server()->GetURL("othersite.test", "/main.html");
-  url::Origin origin_a = url::Origin::Create(url);
-  net::NetworkIsolationKey key_a(origin_a, origin_a);
-  LoadAndVerifyCached(url, key_a, false /* was_cached */,
-                      true /* is_navigation */);
-
-  // Load again with a isolation key using a different subframe origin. The
-  // cached entry should not be loaded.
-  url::Origin origin_b = url::Origin::Create(test_server()->base_url());
-  net::NetworkIsolationKey key_b(origin_a, origin_b);
-  LoadAndVerifyCached(url, key_b, false /* was_cached */,
-                      true /* is_navigation */);
-
-  // Load again with the same isolation key. The cached entry should be loaded.
-  LoadAndVerifyCached(url, key_b, true /* was_cached */,
-                      true /* is_navigation */);
-
-  // Same for a non-navigation entry.
-  LoadAndVerifyCached(url, key_b, true /* was_cached */,
-                      false /* is_navigation */);
-}
-
-TEST_F(NetworkContextSplitCacheTest,
-       NavigationResourceRedirectNetworkIsolationKeyWithFrameOrigin) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      {net::features::kSplitCacheByNetworkIsolationKey,
-       net::features::kAppendFrameOriginToNetworkIsolationKey},
-      {});
-  // Create a request that redirects to othersite.test/title1.html.
-  GURL url = test_server()->GetURL(
-      "/server-redirect?" +
-      test_server()->GetURL("othersite.test", "/title1.html").spec());
-  url::Origin origin = url::Origin::Create(url);
-  net::NetworkIsolationKey key(origin, origin);
-  LoadAndVerifyCached(
-      url, key, false /* was_cached */, true /* is_navigation */,
-      mojom::UpdateNetworkIsolationKeyOnRedirect::kUpdateFrameOrigin,
-      true /* expect_redirect */);
-
-  // Now directly load with the key using the redirected URL. This should be a
-  // cache hit.
-  GURL redirected_url = test_server()->GetURL("othersite.test", "/title1.html");
-  LoadAndVerifyCached(
-      redirected_url,
-      net::NetworkIsolationKey(origin, url::Origin::Create(redirected_url)),
-      true /* was_cached */, true /* is_navigation */);
+  net::IsolationInfo non_navigation_redirected_info =
+      net::IsolationInfo::Create(
+          net::IsolationInfo::RedirectMode::kUpdateNothing, redirected_origin,
+          redirected_origin,
+          net::SiteForCookies::FromOrigin(redirected_origin));
+  LoadAndVerifyCached(redirected_url, non_navigation_redirected_info,
+                      true /* was_cached */);
 }
 
 TEST_F(NetworkContextTest, EnableTrustTokens) {
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn
index deb7d6d..a2bf02f3 100644
--- a/services/network/public/cpp/BUILD.gn
+++ b/services/network/public/cpp/BUILD.gn
@@ -156,6 +156,8 @@
     "http_raw_request_response_info.h",
     "http_request_headers_mojom_traits.cc",
     "http_request_headers_mojom_traits.h",
+    "isolation_info_mojom_traits.cc",
+    "isolation_info_mojom_traits.h",
     "isolation_opt_in_hints.cc",
     "isolation_opt_in_hints.h",
     "mutable_network_traffic_annotation_tag_mojom_traits.h",
@@ -252,6 +254,7 @@
     "initiator_lock_compatibility_unittest.cc",
     "ip_address_mojom_traits_unittest.cc",
     "is_potentially_trustworthy_unittest.cc",
+    "isolation_info_mojom_traits_unittest.cc",
     "mutable_network_traffic_annotation_tag_mojom_traits_unittest.cc",
     "mutable_partial_network_traffic_annotation_tag_mojom_traits_unittest.cc",
     "net_log_mojom_traits_unittest.cc",
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index 8f34ed9..1ae81498 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -115,15 +115,6 @@
 const base::Feature kBlockNonSecureExternalRequests{
     "BlockNonSecureExternalRequests", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// When kPrefetchMainResourceNetworkIsolationKey is enabled, cross-origin
-// prefetch requests for main-resources, as well as their preload response
-// headers, will use a special NetworkIsolationKey allowing them to be reusable
-// from a cross-origin context when the HTTP cache is partitioned by the
-// NetworkIsolationKey.
-const base::Feature kPrefetchMainResourceNetworkIsolationKey{
-    "PrefetchMainResourceNetworkIsolationKey",
-    base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables or defaults splittup up server (not proxy) entries in the
 // HttpAuthCache.
 const base::Feature kSplitAuthCacheByNetworkIsolationKey{
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h
index 3436bb2c..3153a3f 100644
--- a/services/network/public/cpp/features.h
+++ b/services/network/public/cpp/features.h
@@ -43,8 +43,6 @@
 COMPONENT_EXPORT(NETWORK_CPP)
 extern const base::Feature kBlockNonSecureExternalRequests;
 COMPONENT_EXPORT(NETWORK_CPP)
-extern const base::Feature kPrefetchMainResourceNetworkIsolationKey;
-COMPONENT_EXPORT(NETWORK_CPP)
 extern const base::Feature kSplitAuthCacheByNetworkIsolationKey;
 COMPONENT_EXPORT(NETWORK_CPP)
 extern const base::Feature kDnsOverHttpsUpgrade;
diff --git a/services/network/public/cpp/isolation_info_mojom_traits.cc b/services/network/public/cpp/isolation_info_mojom_traits.cc
new file mode 100644
index 0000000..69b1481
--- /dev/null
+++ b/services/network/public/cpp/isolation_info_mojom_traits.cc
@@ -0,0 +1,72 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/isolation_info_mojom_traits.h"
+
+#include "base/logging.h"
+#include "services/network/public/cpp/site_for_cookies_mojom_traits.h"
+
+namespace mojo {
+
+bool EnumTraits<network::mojom::IsolationInfoRedirectMode,
+                net::IsolationInfo::RedirectMode>::
+    FromMojom(network::mojom::IsolationInfoRedirectMode redirect_mode,
+              net::IsolationInfo::RedirectMode* out) {
+  switch (redirect_mode) {
+    case network::mojom::IsolationInfoRedirectMode::kUpdateTopFrame:
+      *out = net::IsolationInfo::RedirectMode::kUpdateTopFrame;
+      return true;
+    case network::mojom::IsolationInfoRedirectMode::kUpdateFrameOnly:
+      *out = net::IsolationInfo::RedirectMode::kUpdateFrameOnly;
+      return true;
+    case network::mojom::IsolationInfoRedirectMode::kUpdateNothing:
+      *out = net::IsolationInfo::RedirectMode::kUpdateNothing;
+      return true;
+  }
+  return false;
+}
+
+network::mojom::IsolationInfoRedirectMode EnumTraits<
+    network::mojom::IsolationInfoRedirectMode,
+    net::IsolationInfo::RedirectMode>::ToMojom(net::IsolationInfo::RedirectMode
+                                                   redirect_mode) {
+  switch (redirect_mode) {
+    case net::IsolationInfo::RedirectMode::kUpdateTopFrame:
+      return network::mojom::IsolationInfoRedirectMode::kUpdateTopFrame;
+    case net::IsolationInfo::RedirectMode::kUpdateFrameOnly:
+      return network::mojom::IsolationInfoRedirectMode::kUpdateFrameOnly;
+    case net::IsolationInfo::RedirectMode::kUpdateNothing:
+      return network::mojom::IsolationInfoRedirectMode::kUpdateNothing;
+  }
+
+  NOTREACHED();
+  return network::mojom::IsolationInfoRedirectMode::kUpdateNothing;
+}
+
+bool StructTraits<network::mojom::IsolationInfoDataView, net::IsolationInfo>::
+    Read(network::mojom::IsolationInfoDataView data, net::IsolationInfo* out) {
+  base::Optional<url::Origin> top_frame_origin;
+  base::Optional<url::Origin> frame_origin;
+  net::SiteForCookies site_for_cookies;
+  net::IsolationInfo::RedirectMode redirect_mode;
+
+  if (!data.ReadTopFrameOrigin(&top_frame_origin) ||
+      !data.ReadFrameOrigin(&frame_origin) ||
+      !data.ReadSiteForCookies(&site_for_cookies) ||
+      !data.ReadRedirectMode(&redirect_mode)) {
+    return false;
+  }
+
+  base::Optional<net::IsolationInfo> isolation_info =
+      net::IsolationInfo::CreateIfConsistent(redirect_mode, top_frame_origin,
+                                             frame_origin, site_for_cookies,
+                                             data.opaque_and_non_transient());
+  if (!isolation_info)
+    return false;
+
+  *out = std::move(*isolation_info);
+  return true;
+}
+
+}  // namespace mojo
diff --git a/services/network/public/cpp/isolation_info_mojom_traits.h b/services/network/public/cpp/isolation_info_mojom_traits.h
new file mode 100644
index 0000000..fee49ca
--- /dev/null
+++ b/services/network/public/cpp/isolation_info_mojom_traits.h
@@ -0,0 +1,61 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_ISOLATION_INFO_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_ISOLATION_INFO_MOJOM_TRAITS_H_
+
+#include "mojo/public/cpp/bindings/enum_traits.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "net/base/isolation_info.h"
+#include "net/cookies/site_for_cookies.h"
+#include "services/network/public/mojom/isolation_info.mojom-shared.h"
+#include "url/mojom/origin_mojom_traits.h"
+#include "url/origin.h"
+
+namespace mojo {
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+    EnumTraits<network::mojom::IsolationInfoRedirectMode,
+               net::IsolationInfo::RedirectMode> {
+  static network::mojom::IsolationInfoRedirectMode ToMojom(
+      net::IsolationInfo::RedirectMode redirect_mode);
+  static bool FromMojom(network::mojom::IsolationInfoRedirectMode redirect_mode,
+                        net::IsolationInfo::RedirectMode* out);
+};
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+    StructTraits<network::mojom::IsolationInfoDataView, net::IsolationInfo> {
+  static net::IsolationInfo::RedirectMode redirect_mode(
+      const net::IsolationInfo& input) {
+    return input.redirect_mode();
+  }
+
+  static const base::Optional<url::Origin>& top_frame_origin(
+      const net::IsolationInfo& input) {
+    return input.top_frame_origin();
+  }
+
+  static const base::Optional<url::Origin>& frame_origin(
+      const net::IsolationInfo& input) {
+    return input.frame_origin();
+  }
+
+  static bool opaque_and_non_transient(const net::IsolationInfo& input) {
+    return input.opaque_and_non_transient();
+  }
+
+  static const net::SiteForCookies& site_for_cookies(
+      const net::IsolationInfo& input) {
+    return input.site_for_cookies();
+  }
+
+  static bool Read(network::mojom::IsolationInfoDataView data,
+                   net::IsolationInfo* out);
+};
+
+}  // namespace mojo
+
+#endif  // SERVICES_NETWORK_PUBLIC_CPP_ISOLATION_INFO_MOJOM_TRAITS_H_
diff --git a/services/network/public/cpp/isolation_info_mojom_traits_unittest.cc b/services/network/public/cpp/isolation_info_mojom_traits_unittest.cc
new file mode 100644
index 0000000..f79d4a5
--- /dev/null
+++ b/services/network/public/cpp/isolation_info_mojom_traits_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/network/public/cpp/isolation_info_mojom_traits.h"
+
+#include <vector>
+
+#include "base/optional.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "net/base/isolation_info.h"
+#include "net/cookies/site_for_cookies.h"
+#include "services/network/public/mojom/isolation_info.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace mojo {
+
+TEST(IsolationInfoMojomTraitsTest, SerializeAndDeserialize) {
+  const url::Origin kOrigin1 = url::Origin::Create(GURL("https://a.test/"));
+  const url::Origin kOrigin2 = url::Origin::Create(GURL("https://b.test/"));
+  std::vector<net::IsolationInfo> keys = {
+      net::IsolationInfo(),
+      net::IsolationInfo::CreateTransient(),
+      net::IsolationInfo::CreateOpaqueAndNonTransient(),
+      net::IsolationInfo::Create(
+          net::IsolationInfo::RedirectMode::kUpdateTopFrame, kOrigin1, kOrigin1,
+          net::SiteForCookies::FromOrigin(kOrigin1)),
+      net::IsolationInfo::Create(
+          net::IsolationInfo::RedirectMode::kUpdateFrameOnly, kOrigin1,
+          kOrigin2, net::SiteForCookies::FromOrigin(kOrigin1)),
+      net::IsolationInfo::Create(
+          net::IsolationInfo::RedirectMode::kUpdateFrameOnly, kOrigin1,
+          kOrigin2, net::SiteForCookies()),
+      net::IsolationInfo::Create(
+          net::IsolationInfo::RedirectMode::kUpdateNothing, kOrigin1, kOrigin1,
+          net::SiteForCookies::FromOrigin(kOrigin1)),
+      net::IsolationInfo::Create(
+          net::IsolationInfo::RedirectMode::kUpdateNothing, url::Origin(),
+          url::Origin(), net::SiteForCookies()),
+  };
+
+  for (auto original : keys) {
+    net::IsolationInfo copied;
+    EXPECT_TRUE(
+        mojo::test::SerializeAndDeserialize<network::mojom::IsolationInfo>(
+            &original, &copied));
+    EXPECT_TRUE(original.IsEqualForTesting(copied));
+  }
+}
+
+}  // namespace mojo
diff --git a/services/network/public/cpp/simple_url_loader_unittest.cc b/services/network/public/cpp/simple_url_loader_unittest.cc
index d89802a..de9882a 100644
--- a/services/network/public/cpp/simple_url_loader_unittest.cc
+++ b/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -614,7 +614,8 @@
     params->process_id = mojom::kBrowserProcessId;
     params->is_corb_enabled = false;
     url::Origin origin = url::Origin::Create(test_server_.base_url());
-    params->network_isolation_key = net::NetworkIsolationKey(origin, origin);
+    params->isolation_info =
+        net::IsolationInfo::CreateForInternalRequest(origin);
     params->is_trusted = true;
     network_context_->CreateURLLoaderFactory(
         url_loader_factory_.BindNewPipeAndPassReceiver(), std::move(params));
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index 9a0b0f20..32ed125e 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -290,6 +290,7 @@
     "http_raw_request_response_info.mojom",
     "http_request_headers.mojom",
     "ip_address_space.mojom",
+    "isolation_info.mojom",
     "load_timing_info.mojom",
     "mdns_responder.mojom",
     "net_log.mojom",
@@ -442,6 +443,20 @@
     {
       types = [
         {
+          mojom = "network.mojom.IsolationInfo"
+          cpp = "::net::IsolationInfo"
+        },
+      ]
+      traits_headers =
+          [ "//services/network/public/cpp/isolation_info_mojom_traits.h" ]
+      traits_public_deps = [
+        "//net",
+        "//services/network/public/cpp:cpp_base",
+      ]
+    },
+    {
+      types = [
+        {
           mojom = "network.mojom.NetworkInterface"
           cpp = "::net::NetworkInterface"
         },
diff --git a/services/network/public/mojom/isolation_info.mojom b/services/network/public/mojom/isolation_info.mojom
new file mode 100644
index 0000000..eb00944
--- /dev/null
+++ b/services/network/public/mojom/isolation_info.mojom
@@ -0,0 +1,27 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module network.mojom;
+
+import "services/network/public/mojom/site_for_cookies.mojom";
+import "url/mojom/origin.mojom";
+
+// Mapped to net::IsolationInfo::RedirectMode, which is what consumers should
+// be using instead of using this directly.
+enum IsolationInfoRedirectMode {
+  kUpdateTopFrame,
+  kUpdateFrameOnly,
+  kUpdateNothing,
+};
+
+// Mapped to net::IsolationInfo.
+struct IsolationInfo {
+  // These fields should not be used directly, but rather through the mapped
+  // net::IsolationInfo.
+  IsolationInfoRedirectMode redirect_mode;
+  url.mojom.Origin? top_frame_origin;
+  url.mojom.Origin? frame_origin;
+  bool opaque_and_non_transient;
+  SiteForCookies site_for_cookies;
+};
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 1dc1133..75bc4ea 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -25,6 +25,7 @@
 import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";
 import "services/network/public/mojom/net_log.mojom";
 import "services/network/public/mojom/network_isolation_key.mojom";
+import "services/network/public/mojom/isolation_info.mojom";
 import "services/network/public/mojom/network_param.mojom";
 import "services/network/public/mojom/origin_policy_manager.mojom";
 import "services/network/public/mojom/p2p.mojom";
@@ -592,8 +593,9 @@
   // interface. This still respects the per-context block lists.
   CorsOriginAccessPatterns? factory_bound_access_patterns;
 
-  // Key used to isolate shared network resources like the cache.
-  NetworkIsolationKey? network_isolation_key;
+  // Information used restrict access to identity information (like SameSite
+  // cookies) and to shard network resources, like the cache.
+  IsolationInfo isolation_info;
 
   // Whether secure DNS should be disabled for requests.
   bool disable_secure_dns = false;
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index f3955f99..4bb0a62e 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -13,6 +13,8 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
+#include "base/debug/alias.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/files/file.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
@@ -558,10 +560,11 @@
   url_request_->set_referrer_policy(request.referrer_policy);
   url_request_->set_upgrade_if_insecure(request.upgrade_if_insecure);
 
-  net::IsolationInfo::RedirectMode redirect_mode;
-  if (!request.trusted_params) {
-    redirect_mode = net::IsolationInfo::RedirectMode::kUpdateNothing;
-  } else {
+  if (!factory_params_->isolation_info.IsEmpty()) {
+    url_request_->set_isolation_info(factory_params_->isolation_info);
+  } else if (request.trusted_params &&
+             !request.trusted_params->network_isolation_key.IsEmpty()) {
+    net::IsolationInfo::RedirectMode redirect_mode;
     switch (request.trusted_params->update_network_isolation_key_on_redirect) {
       case mojom::UpdateNetworkIsolationKeyOnRedirect::
           kUpdateTopFrameAndFrameOrigin:
@@ -574,12 +577,6 @@
         redirect_mode = net::IsolationInfo::RedirectMode::kUpdateNothing;
         break;
     }
-  }
-  if (factory_params_->network_isolation_key) {
-    url_request_->set_isolation_info(net::IsolationInfo::CreatePartial(
-        redirect_mode, factory_params_->network_isolation_key.value()));
-  } else if (request.trusted_params &&
-             !request.trusted_params->network_isolation_key.IsEmpty()) {
     url_request_->set_isolation_info(net::IsolationInfo::CreatePartial(
         redirect_mode, request.trusted_params->network_isolation_key));
   }
diff --git a/services/network/url_loader_factory.cc b/services/network/url_loader_factory.cc
index f17117d..f021104 100644
--- a/services/network/url_loader_factory.cc
+++ b/services/network/url_loader_factory.cc
@@ -70,6 +70,9 @@
   DCHECK(context);
   DCHECK_NE(mojom::kInvalidProcessId, params_->process_id);
   DCHECK(!params_->factory_override);
+  // Only non-navigation IsolationInfos should be bound to URLLoaderFactories.
+  DCHECK_EQ(net::IsolationInfo::RedirectMode::kUpdateNothing,
+            params_->isolation_info.redirect_mode());
 
   if (!params_->top_frame_id) {
     params_->top_frame_id = base::UnguessableToken::Create();
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index 109d497..afcb65d 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -40,6 +40,7 @@
 #include "net/base/escape.h"
 #include "net/base/features.h"
 #include "net/base/io_buffer.h"
+#include "net/base/isolation_info.h"
 #include "net/base/load_flags.h"
 #include "net/base/mime_sniffer.h"
 #include "net/base/net_errors.h"
@@ -483,7 +484,8 @@
     params.process_id = mojom::kBrowserProcessId;
     params.is_corb_enabled = false;
     url::Origin origin = url::Origin::Create(url);
-    params.network_isolation_key = net::NetworkIsolationKey(origin, origin);
+    params.isolation_info =
+        net::IsolationInfo::CreateForInternalRequest(origin);
     params.is_trusted = true;
     url_loader = std::make_unique<URLLoader>(
         context(), nullptr /* network_service_client */,
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc
index b0127af..1eabb897 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_linux.cc
@@ -181,6 +181,8 @@
     region->byte_stats_shared_clean_resident = ReadCounterBytes(counter_line);
   } else if (strcmp(counter_name, "Swap:") == 0) {
     region->byte_stats_swapped = ReadCounterBytes(counter_line);
+  } else if (strcmp(counter_name, "Locked:") == 0) {
+    region->byte_locked = ReadCounterBytes(counter_line);
   } else {
     res = 0;
   }
@@ -196,7 +198,7 @@
   fseek(smaps_file, 0, SEEK_SET);
 
   char line[kMaxLineSize];
-  const uint32_t kNumExpectedCountersPerRegion = 6;
+  const uint32_t kNumExpectedCountersPerRegion = 7;
   uint32_t counters_parsed_for_current_region = 0;
   uint32_t num_valid_regions = 0;
   bool should_add_current_region = false;
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_unittest.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_unittest.cc
index 84865e8..f1b812a 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_unittest.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_unittest.cc
@@ -61,7 +61,7 @@
     "Swap:                  0 kB\n"
     "KernelPageSize:        4 kB\n"
     "MMUPageSize:           4 kB\n"
-    "Locked:                0 kB\n"
+    "Locked:                1 kB\n"
     "VmFlags: rd ex mr mw me dw sd";
 
 const char kTestSmaps2[] =
@@ -115,7 +115,7 @@
     "Swap:                  0 kB\n"
     "KernelPageSize:        4 kB\n"
     "MMUPageSize:           4 kB\n"
-    "Locked:                0 kB\n"
+    "Locked:                11 kB\n"
     "VmFlags: rd wr mr mw me ac sd\n";
 
 void CreateTempFileWithContents(const char* contents, base::ScopedFILE* file) {
@@ -176,6 +176,7 @@
   EXPECT_EQ(0UL, maps_1[0]->byte_stats_private_clean_resident);
   EXPECT_EQ(68 * 1024UL, maps_1[0]->byte_stats_private_dirty_resident);
   EXPECT_EQ(4 * 1024UL, maps_1[0]->byte_stats_swapped);
+  EXPECT_EQ(0 * 1024UL, maps_1[0]->byte_locked);
 
   EXPECT_EQ(0xff000000UL, maps_1[1]->start_address);
   EXPECT_EQ(0xff800000UL - 0xff000000UL, maps_1[1]->size_in_bytes);
@@ -187,6 +188,7 @@
   EXPECT_EQ(60 * 1024UL, maps_1[1]->byte_stats_private_clean_resident);
   EXPECT_EQ(8 * 1024UL, maps_1[1]->byte_stats_private_dirty_resident);
   EXPECT_EQ(0 * 1024UL, maps_1[1]->byte_stats_swapped);
+  EXPECT_EQ(1 * 1024UL, maps_1[1]->byte_locked);
 
   // Parse the 2nd smaps file.
   base::ScopedFILE temp_file2;
@@ -204,6 +206,7 @@
   EXPECT_EQ(8 * 1024UL, maps_2[0]->byte_stats_private_clean_resident);
   EXPECT_EQ(4 * 1024UL, maps_2[0]->byte_stats_private_dirty_resident);
   EXPECT_EQ(0 * 1024UL, maps_2[0]->byte_stats_swapped);
+  EXPECT_EQ(11 * 1024UL, maps_2[0]->byte_locked);
 }
 
 TEST(OSMetricsTest, GetMappedAndResidentPages) {
diff --git a/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom b/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
index d12e4d9f..b04abf5 100644
--- a/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
+++ b/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
@@ -119,6 +119,7 @@
   uint64 byte_stats_shared_clean_resident;
 
   uint64 byte_stats_swapped;
+  uint64 byte_locked;
 
   // For multiprocess accounting.
   uint64 byte_stats_proportional_resident;
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 26d626c..4f781be 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -21233,8 +21233,7 @@
           "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "merge": {
           "args": [
@@ -21247,12 +21246,9 @@
         },
         "name": "chrome_public_test_vr_apk-ddready-ddview",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -21625,8 +21621,7 @@
           "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "merge": {
           "args": [
@@ -21639,12 +21634,9 @@
         },
         "name": "chrome_public_test_vr_apk-ddready-ddview",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -37211,8 +37203,7 @@
           "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "merge": {
           "args": [
@@ -37225,12 +37216,9 @@
         },
         "name": "chrome_public_test_vr_apk-ddready-ddview",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.ci.json b/testing/buildbot/chromium.ci.json
index eea002f2..1124cc1 100644
--- a/testing/buildbot/chromium.ci.json
+++ b/testing/buildbot/chromium.ci.json
@@ -6963,8 +6963,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -6973,12 +6972,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -7008,8 +7004,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7018,12 +7013,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -7495,8 +7487,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7505,12 +7496,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -7540,8 +7528,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7550,12 +7537,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -7779,8 +7763,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7789,12 +7772,9 @@
         },
         "name": "android_webview_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -8012,8 +7992,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -8022,12 +8001,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -8056,8 +8032,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -8066,12 +8041,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -8599,8 +8571,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -8609,12 +8580,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -8644,8 +8612,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -8654,12 +8621,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -9210,8 +9174,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -9220,12 +9183,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -9255,8 +9215,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -9265,12 +9224,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -9773,8 +9729,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -9783,12 +9738,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -9818,8 +9770,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -9828,12 +9779,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -9966,8 +9914,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -9976,12 +9923,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -10118,8 +10062,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -10128,12 +10071,9 @@
         },
         "name": "egl_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -10217,8 +10157,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -10227,12 +10166,9 @@
         },
         "name": "vulkan_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -10573,8 +10509,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -10583,12 +10518,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -10617,8 +10549,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -10627,12 +10558,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -37778,8 +37706,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -37788,12 +37715,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -37821,8 +37745,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -37831,12 +37754,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -38258,8 +38178,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -38268,12 +38187,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -38301,8 +38217,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -38311,12 +38226,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -39034,8 +38946,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -39044,12 +38955,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -39078,8 +38986,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -39088,12 +38995,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -39614,8 +39518,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -39624,12 +39527,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -39657,8 +39557,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -39667,12 +39566,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -40232,8 +40128,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -40242,12 +40137,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -40276,8 +40168,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -40286,12 +40177,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -40874,8 +40762,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -40884,12 +40771,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -40917,8 +40801,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -40927,12 +40810,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -41391,8 +41271,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -41401,12 +41280,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -41506,8 +41382,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -41516,12 +41391,9 @@
         },
         "name": "skia_renderer_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -41593,8 +41465,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -41603,12 +41474,9 @@
         },
         "name": "vulkan_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -41826,8 +41694,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -41836,12 +41703,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -41941,8 +41805,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -41951,12 +41814,9 @@
         },
         "name": "skia_renderer_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -42028,8 +41888,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -42038,12 +41897,9 @@
         },
         "name": "vulkan_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -44926,8 +44782,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -44936,12 +44791,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -44969,8 +44821,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -44979,12 +44830,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -58773,8 +58621,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -58783,12 +58630,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -58815,8 +58659,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -58825,12 +58668,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -59280,8 +59120,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -59290,12 +59129,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -59322,8 +59158,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -59332,12 +59167,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -59965,8 +59797,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -59975,12 +59806,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -60013,8 +59841,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -60023,12 +59850,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -60642,8 +60466,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -60652,12 +60475,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -60684,8 +60504,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -60694,12 +60513,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -61293,8 +61109,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -61303,12 +61118,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -61337,8 +61149,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -61347,12 +61158,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -61836,8 +61644,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -61846,12 +61653,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -61880,8 +61684,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -61890,12 +61693,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -62374,8 +62174,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -62384,12 +62183,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -62418,8 +62214,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -62428,12 +62223,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -63071,8 +62863,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -63081,12 +62872,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -63115,8 +62903,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -63125,12 +62912,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -63832,8 +63616,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -63842,12 +63625,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -63876,8 +63656,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -63886,12 +63665,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -64331,8 +64107,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -64341,12 +64116,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -64373,8 +64145,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -64383,12 +64154,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -64787,8 +64555,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -64798,12 +64565,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -64830,8 +64594,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -64841,12 +64604,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -65230,8 +64990,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -65240,12 +64999,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -65274,8 +65030,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -65284,12 +65039,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -65681,8 +65433,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -65691,12 +65442,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -65725,8 +65473,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -65735,12 +65482,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -66167,8 +65911,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -66178,12 +65921,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -66212,8 +65952,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -66223,12 +65962,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -87368,8 +87104,7 @@
           "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "merge": {
           "args": [
@@ -87382,12 +87117,9 @@
         },
         "name": "chrome_public_test_vr_apk-ddready-ddview",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -90123,8 +89855,7 @@
           "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "merge": {
           "args": [
@@ -90137,12 +89868,9 @@
         },
         "name": "chrome_public_test_vr_apk-ddready-ddview",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -131089,8 +130817,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -131099,12 +130826,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -131132,8 +130856,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -131142,12 +130865,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -131903,8 +131623,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -131913,12 +131632,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -131947,8 +131663,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -131957,12 +131672,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -132778,8 +132490,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -132788,12 +132499,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -132822,8 +132530,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -132832,12 +132539,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -133582,8 +133286,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -133592,12 +133295,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -133625,8 +133325,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -133635,12 +133334,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -134518,8 +134214,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -134528,12 +134223,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -134562,8 +134254,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -134572,12 +134263,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -135437,8 +135125,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -135447,12 +135134,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -135481,8 +135165,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -135491,12 +135174,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -136487,8 +136167,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -136497,12 +136176,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -136579,8 +136255,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -136589,12 +136264,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -137220,8 +136892,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -137230,12 +136901,9 @@
         },
         "name": "gl_renderer_maps_pixel_tests",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -137263,8 +136931,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -137273,12 +136940,9 @@
         },
         "name": "gl_renderer_pixel_skia_gold_tests",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -138656,8 +138320,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -138666,12 +138329,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -138748,8 +138408,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -138758,12 +138417,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -139432,8 +139088,7 @@
           "--browser-ui-tests-verify-pixels",
           "--test-launcher-retry-limit=0",
           "--enable-pixel-output-in-tests",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "experiment_percentage": 100,
         "merge": {
@@ -139442,12 +139097,9 @@
         },
         "name": "pixel_browser_tests",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -147932,8 +147584,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -147942,12 +147593,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -147975,8 +147623,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -147985,12 +147632,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -148523,8 +148167,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -148533,12 +148176,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -148575,8 +148215,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -148585,12 +148224,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -149206,8 +148842,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -149217,12 +148852,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -149259,8 +148891,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -149270,12 +148901,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -150150,8 +149778,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -150160,12 +149787,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -150194,8 +149818,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -150204,12 +149827,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -150830,8 +150450,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -150840,12 +150459,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -150874,8 +150490,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -150884,12 +150499,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -151729,8 +151341,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -151739,12 +151350,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -151782,8 +151390,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -151792,12 +151399,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -152801,8 +152405,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -152811,12 +152414,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -152854,8 +152454,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -152864,12 +152463,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -185303,8 +184899,7 @@
           "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_keyboard/vr_keyboard_current.apk",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "merge": {
           "args": [
@@ -185317,12 +184912,9 @@
         },
         "name": "chrome_public_test_vr_apk-ddready-ddview",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -238945,8 +238537,7 @@
           "--browser-ui-tests-verify-pixels",
           "--test-launcher-retry-limit=0",
           "--enable-pixel-output-in-tests",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "experiment_percentage": 100,
         "merge": {
@@ -238955,12 +238546,9 @@
         },
         "name": "pixel_browser_tests",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index ab5de72d8..0c0bcf7f 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -42356,8 +42356,7 @@
           "--browser-ui-tests-verify-pixels",
           "--test-launcher-retry-limit=0",
           "--enable-pixel-output-in-tests",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "experiment_percentage": 100,
         "merge": {
@@ -42366,12 +42365,9 @@
         },
         "name": "pixel_browser_tests",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index c40dd6c2..2c49b91 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -3817,8 +3817,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -3827,12 +3826,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -3862,8 +3858,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -3872,12 +3867,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -4349,8 +4341,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -4359,12 +4350,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -4394,8 +4382,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -4404,12 +4391,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -4633,8 +4617,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -4643,12 +4626,9 @@
         },
         "name": "android_webview_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -4866,8 +4846,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -4876,12 +4855,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -4910,8 +4886,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -4920,12 +4895,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -5453,8 +5425,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -5463,12 +5434,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -5498,8 +5466,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -5508,12 +5475,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -6064,8 +6028,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -6074,12 +6037,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -6109,8 +6069,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -6119,12 +6078,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -6627,8 +6583,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -6637,12 +6592,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -6672,8 +6624,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -6682,12 +6633,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -6820,8 +6768,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -6830,12 +6777,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -6972,8 +6916,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -6982,12 +6925,9 @@
         },
         "name": "egl_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -7071,8 +7011,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7081,12 +7020,9 @@
         },
         "name": "vulkan_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -7586,8 +7522,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7596,12 +7531,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -7629,8 +7561,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7639,12 +7570,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -8362,8 +8290,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -8372,12 +8299,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -8406,8 +8330,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -8416,12 +8339,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -8942,8 +8862,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -8952,12 +8871,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -8985,8 +8901,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -8995,12 +8910,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -9560,8 +9472,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -9570,12 +9481,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -9604,8 +9512,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -9614,12 +9521,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -10202,8 +10106,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -10212,12 +10115,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -10245,8 +10145,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -10255,12 +10154,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -10719,8 +10615,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -10729,12 +10624,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -10834,8 +10726,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -10844,12 +10735,9 @@
         },
         "name": "skia_renderer_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -10921,8 +10809,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -10931,12 +10818,9 @@
         },
         "name": "vulkan_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -11154,8 +11038,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -11164,12 +11047,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -11269,8 +11149,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -11279,12 +11158,9 @@
         },
         "name": "skia_renderer_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -11356,8 +11232,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -11366,12 +11241,9 @@
         },
         "name": "vulkan_pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -12075,8 +11947,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -12085,12 +11956,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -12117,8 +11985,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -12127,12 +11994,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -12760,8 +12624,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -12770,12 +12633,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -12808,8 +12668,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -12818,12 +12677,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -13437,8 +13293,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -13447,12 +13302,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -13479,8 +13331,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -13489,12 +13340,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -14088,8 +13936,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -14098,12 +13945,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -14132,8 +13976,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -14142,12 +13985,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -14631,8 +14471,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -14641,12 +14480,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -14675,8 +14511,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -14685,12 +14520,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -15169,8 +15001,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -15179,12 +15010,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -15213,8 +15041,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -15223,12 +15050,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -15866,8 +15690,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -15876,12 +15699,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -15910,8 +15730,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -15920,12 +15739,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -16627,8 +16443,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -16637,12 +16452,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -16671,8 +16483,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -16681,12 +16492,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -19775,8 +19583,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -19785,12 +19592,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -19818,8 +19622,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -19828,12 +19631,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -20589,8 +20389,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -20599,12 +20398,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -20633,8 +20429,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -20643,12 +20438,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -21464,8 +21256,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -21474,12 +21265,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -21508,8 +21296,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -21518,12 +21305,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -22268,8 +22052,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -22278,12 +22061,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -22311,8 +22091,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -22321,12 +22100,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -23204,8 +22980,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -23214,12 +22989,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -23248,8 +23020,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -23258,12 +23029,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -24123,8 +23891,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -24133,12 +23900,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -24167,8 +23931,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -24177,12 +23940,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -25173,8 +24933,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -25183,12 +24942,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -25265,8 +25021,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -25275,12 +25030,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -25906,8 +25658,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -25916,12 +25667,9 @@
         },
         "name": "gl_renderer_maps_pixel_tests",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -25949,8 +25697,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -25959,12 +25706,9 @@
         },
         "name": "gl_renderer_pixel_skia_gold_tests",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -27342,8 +27086,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -27352,12 +27095,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -27434,8 +27174,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -27444,12 +27183,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -28463,8 +28199,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -28473,12 +28208,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -28507,8 +28239,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -28517,12 +28248,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -29143,8 +28871,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -29153,12 +28880,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -29187,8 +28911,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -29197,12 +28920,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -30042,8 +29762,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -30052,12 +29771,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -30095,8 +29811,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -30105,12 +29820,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -31114,8 +30826,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -31124,12 +30835,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -31167,8 +30875,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -31177,12 +30884,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json
index b75c4746..d8b3db8 100644
--- a/testing/buildbot/chromium.gpu.json
+++ b/testing/buildbot/chromium.gpu.json
@@ -173,8 +173,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -183,12 +182,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -217,8 +213,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -227,12 +222,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -654,8 +646,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -664,12 +655,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -697,8 +685,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -707,12 +694,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1097,8 +1081,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1107,12 +1090,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1140,8 +1120,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1150,12 +1129,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1499,8 +1475,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1509,12 +1484,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1541,8 +1513,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1551,12 +1522,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1922,8 +1890,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1932,12 +1899,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1964,8 +1928,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1974,12 +1937,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -2378,8 +2338,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -2389,12 +2348,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -2421,8 +2377,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -2432,12 +2387,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -2821,8 +2773,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -2831,12 +2782,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -2865,8 +2813,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -2875,12 +2822,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -3272,8 +3216,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -3282,12 +3225,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -3316,8 +3256,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -3326,12 +3265,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -3758,8 +3694,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -3769,12 +3704,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -3803,8 +3735,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -3814,12 +3745,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -4287,8 +4215,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -4297,12 +4224,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -4330,8 +4254,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -4340,12 +4263,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -4878,8 +4798,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -4888,12 +4807,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -4930,8 +4846,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -4940,12 +4855,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -5561,8 +5473,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -5572,12 +5483,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -5614,8 +5522,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "isolate_coverage_data": true,
         "isolate_name": "telemetry_gpu_integration_test",
@@ -5625,12 +5532,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index 23c38e4f..650e4b39 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -204,6 +204,7 @@
         "isolate_name": "performance_test_suite",
         "merge": {
           "args": [
+            "--lightweight",
             "--skip-perf"
           ],
           "script": "//tools/perf/process_perf_results.py"
@@ -240,6 +241,14 @@
       }
     ]
   },
+  "linux-processor-perf-fyi": {
+    "merge": {
+      "args": [
+        "--lightweight"
+      ],
+      "script": "//tools/perf/process_perf_results.py"
+    }
+  },
   "win-10_laptop_low_end-perf_HP-Candidate": {
     "isolated_scripts": [
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index ff42b26..3828f92 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -1743,8 +1743,7 @@
           "--browser-ui-tests-verify-pixels",
           "--test-launcher-retry-limit=0",
           "--enable-pixel-output-in-tests",
-          "--git-revision",
-          "${got_revision}"
+          "--git-revision=${got_revision}"
         ],
         "experiment_percentage": 100,
         "merge": {
@@ -1753,12 +1752,9 @@
         },
         "name": "pixel_browser_tests",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json
index 1eb9c95..87c82ac 100644
--- a/testing/buildbot/client.v8.fyi.json
+++ b/testing/buildbot/client.v8.fyi.json
@@ -134,8 +134,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -144,12 +143,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -177,8 +173,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -187,12 +182,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -465,8 +457,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -475,12 +466,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -507,8 +495,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -517,12 +504,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -791,8 +775,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -801,12 +784,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -833,8 +813,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -843,12 +822,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1113,8 +1089,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1123,12 +1098,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1154,8 +1126,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1164,12 +1135,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1781,8 +1749,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1791,12 +1758,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1823,8 +1787,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1833,12 +1796,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
diff --git a/testing/buildbot/filters/android.emulator.chrome_public_test_apk.filter b/testing/buildbot/filters/android.emulator.chrome_public_test_apk.filter
index eafdee9..4523df6 100644
--- a/testing/buildbot/filters/android.emulator.chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/android.emulator.chrome_public_test_apk.filter
@@ -8,9 +8,6 @@
 -org.chromium.chrome.browser.shape_detection.ShapeDetectionTest.testBarcodeDetection
 -org.chromium.chrome.browser.shape_detection.ShapeDetectionTest.testTextDetection
 
-# crbug/1017141
--org.chromium.chrome.browser.tasks.tab_management.TabSwitcherMultiWindowTest.testMoveTabsAcrossWindow_GTS_WithoutGroup
-
 # crbug/1036552
 -org.chromium.chrome.browser.tasks.tab_management.TabGridDialogParentTest.testDialog_ZoomInFadeOut
 -org.chromium.chrome.browser.tasks.tab_management.TabGridDialogParentTest.testDialog_ZoomInZoomOut
diff --git a/testing/buildbot/filters/android.pie_arm64_rel.chrome_public_test_apk.filter b/testing/buildbot/filters/android.pie_arm64_rel.chrome_public_test_apk.filter
index 8966b337..61b8ff6 100644
--- a/testing/buildbot/filters/android.pie_arm64_rel.chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/android.pie_arm64_rel.chrome_public_test_apk.filter
@@ -40,9 +40,6 @@
 -org.chromium.chrome.browser.suggestions.tile.TileGroupTest.testDismissTileUndo
 -org.chromium.chrome.browser.suggestions.tile.TileGroupTest.testDismissTileWithContextMenu
 
-# crbug/1017141
--org.chromium.chrome.browser.tasks.tab_management.TabSwitcherMultiWindowTest.testMoveTabsAcrossWindow_GTS_WithoutGroup
-
 # crbug/1036552
 -org.chromium.chrome.browser.tasks.tab_management.TabGridDialogParentTest.testDialog_ZoomInFadeOut
 -org.chromium.chrome.browser.tasks.tab_management.TabGridDialogParentTest.testDialog_ZoomInZoomOut
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index c8475ed..8f371a3 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -633,12 +633,12 @@
   'skia_gold_test': {
     '$mixin_append': {
       'args': [
-        '--git-revision', '${got_revision}',
+        '--git-revision=${got_revision}',
       ],
       'precommit_args': [
-        '--gerrit-issue', '${patch_issue}',
-        '--gerrit-patchset', '${patch_set}',
-        '--buildbucket-id', '${buildbucket_build_id}',
+        '--gerrit-issue=${patch_issue}',
+        '--gerrit-patchset=${patch_set}',
+        '--buildbucket-id=${buildbucket_build_id}',
       ],
     }
   },
diff --git a/testing/buildbot/v8.ci.json b/testing/buildbot/v8.ci.json
index dfaae979..43e5807 100644
--- a/testing/buildbot/v8.ci.json
+++ b/testing/buildbot/v8.ci.json
@@ -134,8 +134,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -144,12 +143,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -177,8 +173,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -187,12 +182,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1611,8 +1603,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1621,12 +1612,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1653,8 +1641,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1663,12 +1650,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1937,8 +1921,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1947,12 +1930,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -1979,8 +1959,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -1989,12 +1968,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -2259,8 +2235,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -2269,12 +2244,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -2300,8 +2272,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -2310,12 +2281,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -2927,8 +2895,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -2937,12 +2904,9 @@
         },
         "name": "maps_pixel_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
@@ -2969,8 +2933,7 @@
           "--dont-restore-color-profile-after-test",
           "--test-machine-name",
           "${buildername}",
-          "--git-revision",
-          "${got_cr_revision}"
+          "--git-revision=${got_cr_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -2979,12 +2942,9 @@
         },
         "name": "pixel_skia_gold_test",
         "precommit_args": [
-          "--gerrit-issue",
-          "${patch_issue}",
-          "--gerrit-patchset",
-          "${patch_set}",
-          "--buildbucket-id",
-          "${buildbucket_build_id}"
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
         ],
         "should_retry_with_patch": false,
         "swarming": {
diff --git a/testing/test.gni b/testing/test.gni
index d2b54c2..eda4330 100644
--- a/testing/test.gni
+++ b/testing/test.gni
@@ -217,7 +217,7 @@
       package = ":$_pkg_target"
       package_name_override = _output_name
 
-      data_deps = [ "//testing/buildbot/filters:fuchsia_filters" ]
+      deps = [ "//testing/buildbot/filters:fuchsia_filters" ]
     }
 
     cr_fuchsia_package(_pkg_target) {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 8c3e806..489bb34d 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2581,17 +2581,17 @@
             ],
             "experiments": [
                 {
-                    "name": "Settings_Main",
+                    "name": "Settings_Privacy",
                     "params": {
-                        "en_site_id": "u4ggjx6754eqhvca4nct6iytdi",
+                        "en_site_id": "gjhdonsbcw64p5i2sfhrdetucq",
                         "probability": "1.0",
-                        "survey": "settings"
+                        "survey": "settings-privacy"
                     },
                     "enable_features": [
-                        "HappinessTrackingSurveysForDesktopSettings"
+                        "HappinessTrackingSurveysForDesktopSettingsPrivacy"
                     ],
                     "disable_features": [
-                        "HappinessTrackingSurveysForDesktopSettingsPrivacy"
+                        "HappinessTrackingSurveysForDesktopSettings"
                     ]
                 }
             ]
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 07fb2dc..e665a7c 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -122,6 +122,7 @@
 /libaom/source/libaom
 /libc++-static/libc++.a
 /libaddressinput/src
+/libavif/src
 /libdrm/src
 /libFuzzer/src
 /libgav1/src
diff --git a/third_party/blink/common/BUILD.gn b/third_party/blink/common/BUILD.gn
index c563df9b..551b119 100644
--- a/third_party/blink/common/BUILD.gn
+++ b/third_party/blink/common/BUILD.gn
@@ -80,7 +80,6 @@
     "loader/mime_sniffing_url_loader.cc",
     "loader/resource_type_util.cc",
     "loader/throttling_url_loader.cc",
-    "loader/throttling_url_loader.h",
     "loader/url_loader_factory_bundle.cc",
     "loader/url_loader_factory_bundle_mojom_traits.cc",
     "loader/url_loader_throttle.cc",
@@ -132,6 +131,8 @@
 
   deps = [
     "//base",
+    "//media/capture:capture_base",
+    "//media/capture/mojom:video_capture_mojom_support",
     "//mojo/public/cpp/system",
     "//net",
     "//services/metrics/public/cpp:metrics_cpp",
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 7fba3348..1eab95a 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -496,5 +496,8 @@
 
 const base::Feature kAppCache{"AppCache", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables the AV1 Image File Format (AVIF).
+const base::Feature kAVIF{"AVIF", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 }  // namespace blink
diff --git a/third_party/blink/common/manifest/manifest.cc b/third_party/blink/common/manifest/manifest.cc
index f32b662..9423118 100644
--- a/third_party/blink/common/manifest/manifest.cc
+++ b/third_party/blink/common/manifest/manifest.cc
@@ -47,9 +47,9 @@
          display == blink::mojom::DisplayMode::kUndefined &&
          orientation == blink::kWebScreenOrientationLockDefault &&
          icons.empty() && shortcuts.empty() && !share_target.has_value() &&
-         related_applications.empty() && !prefer_related_applications &&
-         !theme_color && !background_color && gcm_sender_id.is_null() &&
-         scope.is_empty();
+         related_applications.empty() && file_handlers.empty() &&
+         !prefer_related_applications && !theme_color && !background_color &&
+         gcm_sender_id.is_null() && scope.is_empty();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/common/mime_util/mime_util.cc b/third_party/blink/common/mime_util/mime_util.cc
index c8ccb699..6082075 100644
--- a/third_party/blink/common/mime_util/mime_util.cc
+++ b/third_party/blink/common/mime_util/mime_util.cc
@@ -10,7 +10,9 @@
 #include "base/lazy_instance.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
+#include "media/media_buildflags.h"
 #include "net/base/mime_util.h"
+#include "third_party/blink/public/common/features.h"
 
 #if !defined(OS_IOS)
 // iOS doesn't use and must not depend on //media
@@ -134,6 +136,14 @@
     non_image_types_.insert(type);
   for (const char* type : kSupportedImageTypes)
     image_types_.insert(type);
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+  // TODO(wtc): Add "image/avif" and "image/avif-sequence" to the
+  // kSupportedImageTypes array when the AVIF feature is shipped.
+  if (base::FeatureList::IsEnabled(features::kAVIF)) {
+    image_types_.insert("image/avif");
+    image_types_.insert("image/avif-sequence");
+  }
+#endif
   for (const char* type : kUnsupportedTextTypes)
     unsupported_text_types_.insert(type);
   for (const char* type : kSupportedJavascriptTypes) {
diff --git a/third_party/blink/common/mime_util/mime_util_unittest.cc b/third_party/blink/common/mime_util/mime_util_unittest.cc
index 3febb192..e6f54a1 100644
--- a/third_party/blink/common/mime_util/mime_util_unittest.cc
+++ b/third_party/blink/common/mime_util/mime_util_unittest.cc
@@ -5,8 +5,10 @@
 #include "third_party/blink/public/common/mime_util/mime_util.h"
 
 #include "build/build_config.h"
+#include "media/media_buildflags.h"
 #include "net/base/mime_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
 
 namespace blink {
 
@@ -16,6 +18,15 @@
 
   EXPECT_TRUE(IsSupportedImageMimeType("image/jpeg"));
   EXPECT_TRUE(IsSupportedImageMimeType("Image/JPEG"));
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+  EXPECT_EQ(IsSupportedImageMimeType("image/avif"),
+            base::FeatureList::IsEnabled(features::kAVIF));
+  EXPECT_EQ(IsSupportedImageMimeType("image/avif-sequence"),
+            base::FeatureList::IsEnabled(features::kAVIF));
+#else
+  EXPECT_FALSE(IsSupportedImageMimeType("image/avif"));
+  EXPECT_FALSE(IsSupportedImageMimeType("image/avif-sequence"));
+#endif
   EXPECT_FALSE(IsSupportedImageMimeType("image/lolcat"));
   EXPECT_FALSE(IsSupportedImageMimeType("Image/LolCat"));
   EXPECT_TRUE(IsSupportedNonImageMimeType("text/html"));
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index bc8c1e4..62981f7 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -167,6 +167,8 @@
 
 BLINK_COMMON_EXPORT extern const base::Feature kAppCache;
 
+BLINK_COMMON_EXPORT extern const base::Feature kAVIF;
+
 }  // namespace features
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 11af02e..48c2e713 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -1210,8 +1210,9 @@
 bool NGBlockNode::HasAspectRatio() const {
   LayoutBox* layout_object = GetLayoutBox();
   if (!layout_object->IsImage() && !IsA<LayoutVideo>(layout_object) &&
-      !layout_object->IsCanvas())
+      !layout_object->IsCanvas() && !layout_object->IsSVGRoot()) {
     return false;
+  }
 
   // Retrieving this and throwing it away is wasteful. We could make this method
   // return Optional<LogicalSize> that returns the aspect_ratio if there is one.
diff --git a/third_party/blink/renderer/core/layout/scrollbars_test.cc b/third_party/blink/renderer/core/layout/scrollbars_test.cc
index 0d242d6..bd666e9 100644
--- a/third_party/blink/renderer/core/layout/scrollbars_test.cc
+++ b/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -568,45 +568,6 @@
   EXPECT_TRUE(scrollable_root->HorizontalScrollbar()->FrameRect().IsEmpty());
 }
 
-// Ensure that overlay scrollbars are not created, even in overflow:scroll,
-// situations when there's no overflow. Specifically, after style-only changes.
-TEST_F(ScrollbarsTest, OverlayScrolblarNotCreatedInUnscrollableAxis) {
-  // This test is specifically checking the behavior when overlay scrollbars
-  // are enabled.
-  ENABLE_OVERLAY_SCROLLBARS(true);
-
-  WebView().MainFrameWidget()->Resize(WebSize(800, 600));
-  SimRequest request("https://example.com/test.html", "text/html");
-  LoadURL("https://example.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style>
-      #target {
-        width: 100px;
-        height: 100px;
-        overflow-y: scroll;
-        opacity: 0.5;
-      }
-    </style>
-    <div id="target"></div>
-  )HTML");
-
-  Compositor().BeginFrame();
-
-  auto* target = GetDocument().getElementById("target");
-  auto* scrollable_area = target->GetLayoutBox()->GetScrollableArea();
-
-  ASSERT_FALSE(scrollable_area->VerticalScrollbar());
-  ASSERT_FALSE(scrollable_area->HorizontalScrollbar());
-
-  // Mutate the opacity so that we cause a style-only change.
-  target->setAttribute(html_names::kStyleAttr, "opacity: 0.9");
-  Compositor().BeginFrame();
-
-  ASSERT_FALSE(scrollable_area->VerticalScrollbar());
-  ASSERT_FALSE(scrollable_area->HorizontalScrollbar());
-}
-
 TEST_F(ScrollbarsTest, scrollbarIsNotHandlingTouchpadScroll) {
   WebView().MainFrameWidget()->Resize(WebSize(200, 200));
   SimRequest request("https://example.com/test.html", "text/html");
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc
index f8372a6..91f685d1 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.cc
+++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -515,17 +515,14 @@
 
     ResourceRequest resource_request(params.href);
 
-    if (base::FeatureList::IsEnabled(
-            network::features::kPrefetchMainResourceNetworkIsolationKey)) {
-      if (EqualIgnoringASCIICase(params.as, "document"))
-        resource_request.SetPrefetchMaybeForTopLevelNavigation(true);
+    if (EqualIgnoringASCIICase(params.as, "document"))
+      resource_request.SetPrefetchMaybeForTopLevelNavigation(true);
 
-      // If this request was originally a preload header on a prefetch response,
-      // it may have a recursive prefetch token, used by the browser process to
-      // ensure this request is cached correctly.
-      resource_request.SetRecursivePrefetchToken(
-          params.recursive_prefetch_token);
-    }
+    // This request could have originally been a preload header on a prefetch
+    // response, that was promoted to a prefetch request by LoadLinksFromHeader.
+    // In that case, it may have a recursive prefetch token used by the browser
+    // process to ensure this request is cached correctly. Propagate it.
+    resource_request.SetRecursivePrefetchToken(params.recursive_prefetch_token);
 
     resource_request.SetReferrerPolicy(params.referrer_policy);
     resource_request.SetFetchImportanceMode(
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc
index 50e76a0..2e281e3 100644
--- a/third_party/blink/renderer/core/page/page.cc
+++ b/third_party/blink/renderer/core/page/page.cc
@@ -219,7 +219,8 @@
   // Android, unit tests run without a ThemeEngine and thus must set a mock
   // ScrollbarTheme, if they don't this call will crash. To set a mock theme,
   // see ScopedMockOverlayScrollbars or WebScopedMockScrollbars.
-  DCHECK(&GetScrollbarTheme());
+  // TODO(bokan): Reenable once all tests are fixed. crbug.com/1068595
+  // DCHECK(&GetScrollbarTheme());
 }
 
 Page::~Page() {
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index 4a32393..a7c94b07 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -1305,6 +1305,7 @@
       mask_layer_->SetElementId(element_id);
       if (GetLayoutObject().HasBackdropFilter())
         mask_layer_->CcLayer()->SetIsBackdropFilterMask(true);
+      mask_layer_->SetHitTestable(true);
       layer_changed = true;
     }
   } else if (mask_layer_) {
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
index b43664b..da509ea 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping_test.cc
@@ -1776,7 +1776,7 @@
   EXPECT_FALSE(mapping->NeedsRepaint(*vertical_scrollbar_layer));
 
   GetDocument().getElementById("child")->setAttribute(html_names::kStyleAttr,
-                                                      "height: 50px");
+                                                      "height: 300px");
   GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
       DocumentUpdateReason::kTest);
   EXPECT_TRUE(mapping->NeedsRepaint(*vertical_scrollbar_layer));
diff --git a/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc b/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
index a845275..bf27da1 100644
--- a/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
+++ b/third_party/blink/renderer/core/paint/object_paint_invalidator_test.cc
@@ -56,9 +56,7 @@
     style='position: relative'></div>
         <div
     id='non-stacked-layered-child-of-composited-non-stacking-context'
-    style='overflow: scroll'>
-          <div style="height:40px"></div>
-        </div>
+    style='overflow: scroll'></div>
       </div>
     </div>
   )HTML");
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index e585179..3fcd6749 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -1128,6 +1128,13 @@
     UpdateScrollbarProportions();
   }
 
+  if (!scrollbars_are_frozen && HasOverlayScrollbars()) {
+    if (!ScrollSize(kHorizontalScrollbar))
+      SetHasHorizontalScrollbar(false);
+    if (!ScrollSize(kVerticalScrollbar))
+      SetHasVerticalScrollbar(false);
+  }
+
   ClampScrollOffsetAfterOverflowChange();
 
   if (!scrollbars_are_frozen) {
@@ -1296,8 +1303,9 @@
 
   bool needs_horizontal_scrollbar;
   bool needs_vertical_scrollbar;
+  // We add auto scrollbars only during layout to prevent spurious activations.
   ComputeScrollbarExistence(needs_horizontal_scrollbar,
-                            needs_vertical_scrollbar, kOverflowIndependent);
+                            needs_vertical_scrollbar, kForbidAddingAutoBars);
 
   UpdateResizerStyle(old_style);
 
@@ -1549,89 +1557,45 @@
     return;
   }
 
-  mojom::blink::ScrollbarMode h_mode = mojom::blink::ScrollbarMode::kAuto;
-  mojom::blink::ScrollbarMode v_mode = mojom::blink::ScrollbarMode::kAuto;
+  needs_horizontal_scrollbar = GetLayoutBox()->ScrollsOverflowX();
+  needs_vertical_scrollbar = GetLayoutBox()->ScrollsOverflowY();
 
-  // First, determine what behavior the scrollbars say they should have.
-  {
-    if (auto* layout_view = DynamicTo<LayoutView>(GetLayoutBox())) {
-      // LayoutView is special as there's various quirks and settings that
-      // style doesn't account for.
-      layout_view->CalculateScrollbarModes(h_mode, v_mode);
-    } else {
-      auto overflow_x = GetLayoutBox()->StyleRef().OverflowX();
-      if (overflow_x == EOverflow::kScroll) {
-        h_mode = mojom::blink::ScrollbarMode::kAlwaysOn;
-      } else if (overflow_x == EOverflow::kHidden ||
-                 overflow_x == EOverflow::kVisible) {
-        h_mode = mojom::blink::ScrollbarMode::kAlwaysOff;
-      }
-
-      auto overflow_y = GetLayoutBox()->StyleRef().OverflowY();
-      if (overflow_y == EOverflow::kScroll) {
-        v_mode = mojom::blink::ScrollbarMode::kAlwaysOn;
-      } else if (overflow_y == EOverflow::kHidden ||
-                 overflow_y == EOverflow::kVisible) {
-        v_mode = mojom::blink::ScrollbarMode::kAlwaysOff;
-      }
-    }
-
-    // Since overlay scrollbars (the fade-in/out kind, not overflow: overlay)
-    // only appear when scrolling, we don't create them if there isn't overflow
-    // to scroll. Thus, overlay scrollbars can't be "always on". i.e.
-    // |overlay:scroll| behaves like |overlay:auto|.
-    bool has_custom_scrollbar_style =
-        ScrollbarStyleSource(*GetLayoutBox())
-            .StyleRef()
-            .HasPseudoElementStyle(kPseudoIdScrollbar);
-    bool will_be_overlay = GetPageScrollbarTheme().UsesOverlayScrollbars() &&
-                           !has_custom_scrollbar_style;
-    if (will_be_overlay) {
-      if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
-        h_mode = mojom::blink::ScrollbarMode::kAuto;
-      if (v_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
-        v_mode = mojom::blink::ScrollbarMode::kAuto;
-    }
+  // Don't add auto scrollbars if the box contents aren't visible.
+  if (GetLayoutBox()->HasAutoHorizontalScrollbar()) {
+    if (option == kForbidAddingAutoBars)
+      needs_horizontal_scrollbar &= HasHorizontalScrollbar();
+    needs_horizontal_scrollbar &=
+        GetLayoutBox()->IsRooted() && HasHorizontalOverflow() &&
+        VisibleContentRect(kIncludeScrollbars).Height();
   }
 
-  // By default, don't make any changes.
-  needs_horizontal_scrollbar = HasHorizontalScrollbar();
-  needs_vertical_scrollbar = HasVerticalScrollbar();
+  if (GetLayoutBox()->HasAutoVerticalScrollbar()) {
+    if (option == kForbidAddingAutoBars)
+      needs_vertical_scrollbar &= HasVerticalScrollbar();
+    needs_vertical_scrollbar &= GetLayoutBox()->IsRooted() &&
+                                HasVerticalOverflow() &&
+                                VisibleContentRect(kIncludeScrollbars).Width();
+  }
 
-  // If the behavior doesn't depend on overflow or any other information, we
-  // can set it now.
-  {
+  if (auto* layout_view = DynamicTo<LayoutView>(GetLayoutBox())) {
+    mojom::blink::ScrollbarMode h_mode;
+    mojom::blink::ScrollbarMode v_mode;
+    layout_view->CalculateScrollbarModes(h_mode, v_mode);
+
+    // Look for the scrollbarModes and reset the needs Horizontal & vertical
+    // Scrollbar values based on scrollbarModes, as during force style change
+    // StyleResolver::styleForDocument returns documentStyle with no overflow
+    // values, due to which we are destroying the scrollbars that were already
+    // present.
     if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
       needs_horizontal_scrollbar = true;
     else if (h_mode == mojom::blink::ScrollbarMode::kAlwaysOff)
       needs_horizontal_scrollbar = false;
-
     if (v_mode == mojom::blink::ScrollbarMode::kAlwaysOn)
       needs_vertical_scrollbar = true;
     else if (v_mode == mojom::blink::ScrollbarMode::kAlwaysOff)
       needs_vertical_scrollbar = false;
   }
-
-  // If this is being performed before layout, we want to only update scrollbar
-  // existence if its based on purely style based reasons.
-  if (option == kOverflowIndependent)
-    return;
-
-  // If we have clean layout, we can make a decision on any scrollbars that
-  // depend on overflow.
-  {
-    if (h_mode == mojom::blink::ScrollbarMode::kAuto) {
-      // Don't add auto scrollbars if the box contents aren't visible.
-      needs_horizontal_scrollbar =
-          GetLayoutBox()->IsRooted() && HasHorizontalOverflow() &&
-          VisibleContentRect(kIncludeScrollbars).Height();
-    }
-    if (v_mode == mojom::blink::ScrollbarMode::kAuto) {
-      needs_vertical_scrollbar = GetLayoutBox()->IsRooted() &&
-                                 HasVerticalOverflow() &&
-                                 VisibleContentRect(kIncludeScrollbars).Width();
-    }
-  }
 }
 
 bool PaintLayerScrollableArea::TryRemovingAutoScrollbars(
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index afe17a03..4e319bf 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -621,21 +621,11 @@
   int HorizontalScrollbarStart() const;
   IntSize ScrollbarOffset(const Scrollbar&) const;
 
-  // If OverflowIndependent is specified, will only change current scrollbar
-  // existence if the new style doesn't depend on overflow which requires
-  // layout to be clean. It'd be nice if we could always determine existence at
-  // one point, after layout. Unfortunately, it seems that parts of layout are
-  // dependent on scrollbar existence in cases like |overflow:scroll|, removing
-  // the post style pass causes breaks in tests e.g. forms web_tests. Thus, we
-  // must do two scrollbar existence passes.
-  enum ComputeScrollbarExistenceOption {
-    kDependsOnOverflow,
-    kOverflowIndependent
-  };
+  enum ComputeScrollbarExistenceOption { kDefault, kForbidAddingAutoBars };
   void ComputeScrollbarExistence(
       bool& needs_horizontal_scrollbar,
       bool& needs_vertical_scrollbar,
-      ComputeScrollbarExistenceOption = kDependsOnOverflow) const;
+      ComputeScrollbarExistenceOption = kDefault) const;
 
   // If the content fits entirely in the area without auto scrollbars, returns
   // true to try to remove them. This is a heuristic and can be incorrect if the
diff --git a/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.cc b/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.cc
index d628250..7ccfe59c 100644
--- a/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.cc
+++ b/third_party/blink/renderer/modules/webaudio/biquad_dsp_kernel.cc
@@ -47,8 +47,7 @@
 }
 
 void BiquadDSPKernel::UpdateCoefficientsIfNecessary(int frames_to_process) {
-  if (GetBiquadProcessor()->FilterCoefficientsDirty() &&
-      GetBiquadProcessor()->IsAudioRate()) {
+  if (GetBiquadProcessor()->FilterCoefficientsDirty()) {
     float cutoff_frequency[audio_utilities::kRenderQuantumFrames];
     float q[audio_utilities::kRenderQuantumFrames];
     float gain[audio_utilities::kRenderQuantumFrames];
@@ -80,10 +79,10 @@
       UpdateCoefficients(isConstant ? 1 : frames_to_process, cutoff_frequency,
                          q, gain, detune);
     } else {
-      cutoff_frequency[0] = GetBiquadProcessor()->Parameter1().FinalValue();
-      q[0] = GetBiquadProcessor()->Parameter2().FinalValue();
-      gain[0] = GetBiquadProcessor()->Parameter3().FinalValue();
-      detune[0] = GetBiquadProcessor()->Parameter4().FinalValue();
+      cutoff_frequency[0] = GetBiquadProcessor()->Parameter1().Value();
+      q[0] = GetBiquadProcessor()->Parameter2().Value();
+      gain[0] = GetBiquadProcessor()->Parameter3().Value();
+      detune[0] = GetBiquadProcessor()->Parameter4().Value();
       UpdateCoefficients(1, cutoff_frequency, q, gain, detune);
     }
   }
diff --git a/third_party/blink/renderer/modules/webaudio/biquad_processor.cc b/third_party/blink/renderer/modules/webaudio/biquad_processor.cc
index 2fa4094..d0ff387 100644
--- a/third_party/blink/renderer/modules/webaudio/biquad_processor.cc
+++ b/third_party/blink/renderer/modules/webaudio/biquad_processor.cc
@@ -63,18 +63,12 @@
   filter_coefficients_dirty_ = false;
   has_sample_accurate_values_ = false;
 
-  if (parameter1_->HasSampleAccurateValuesTimeline() ||
-      parameter2_->HasSampleAccurateValuesTimeline() ||
-      parameter3_->HasSampleAccurateValuesTimeline() ||
-      parameter4_->HasSampleAccurateValuesTimeline()) {
-    // Coefficients are dirty if any of them has automations or if there are
-    // connections to the AudioParam.
+  if (parameter1_->HasSampleAccurateValues() ||
+      parameter2_->HasSampleAccurateValues() ||
+      parameter3_->HasSampleAccurateValues() ||
+      parameter4_->HasSampleAccurateValues()) {
     filter_coefficients_dirty_ = true;
     has_sample_accurate_values_ = true;
-    // If any parameter is a-rate, then the filter must do a-rate processing for
-    // everything.
-    is_audio_rate_ = parameter1_->IsAudioRate() || parameter2_->IsAudioRate() ||
-                     parameter3_->IsAudioRate() || parameter4_->IsAudioRate();
   } else {
     if (has_just_reset_) {
       // Snap to exact values first time after reset, then smooth for subsequent
diff --git a/third_party/blink/renderer/modules/webaudio/biquad_processor.h b/third_party/blink/renderer/modules/webaudio/biquad_processor.h
index 1552b718..6dcd0416 100644
--- a/third_party/blink/renderer/modules/webaudio/biquad_processor.h
+++ b/third_party/blink/renderer/modules/webaudio/biquad_processor.h
@@ -82,7 +82,6 @@
 
   bool FilterCoefficientsDirty() const { return filter_coefficients_dirty_; }
   bool HasSampleAccurateValues() const { return has_sample_accurate_values_; }
-  bool IsAudioRate() const { return is_audio_rate_; }
 
   AudioParamHandler& Parameter1() { return *parameter1_; }
   AudioParamHandler& Parameter2() { return *parameter2_; }
@@ -105,9 +104,6 @@
 
   // Set to true if any of the filter parameters are sample-accurate.
   bool has_sample_accurate_values_;
-
-  // Set to true if any of the filter parameters are a-rate.
-  bool is_audio_rate_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 6658b51..cc1d57ce 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -8,6 +8,7 @@
 import("//build/config/features.gni")
 import("//build/config/jumbo.gni")
 import("//build/config/ui.gni")
+import("//media/media_options.gni")
 import("//testing/libfuzzer/fuzzer_test.gni")
 import("//testing/test.gni")
 import("//third_party/blink/public/public_features.gni")
@@ -1610,6 +1611,15 @@
     ]
   }
 
+  if (enable_av1_decoder) {
+    sources += [
+      "image-decoders/avif/avif_image_decoder.cc",
+      "image-decoders/avif/avif_image_decoder.h",
+    ]
+
+    deps += [ "//third_party/libavif" ]
+  }
+
   if (current_cpu == "x86" || current_cpu == "x64") {
     deps += [ ":blink_x86_avx" ]
   }
diff --git a/third_party/blink/renderer/platform/exported/web_url_request.cc b/third_party/blink/renderer/platform/exported/web_url_request.cc
index 651e79a..074cac7 100644
--- a/third_party/blink/renderer/platform/exported/web_url_request.cc
+++ b/third_party/blink/renderer/platform/exported/web_url_request.cc
@@ -516,8 +516,6 @@
   if (resource_request_->PrefetchMaybeForTopLeveNavigation()) {
     DCHECK_EQ(resource_request_->GetRequestContext(),
               blink::mojom::RequestContextType::PREFETCH);
-    DCHECK(base::FeatureList::IsEnabled(
-        network::features::kPrefetchMainResourceNetworkIsolationKey));
     if (!resource_request_->RequestorOrigin()->IsSameOriginWith(
             SecurityOrigin::Create(resource_request_->Url()).get())) {
       load_flags |= net::LOAD_RESTRICTED_PREFETCH;
diff --git a/third_party/blink/renderer/platform/image-decoders/DEPS b/third_party/blink/renderer/platform/image-decoders/DEPS
index 8bcb951..7733cea 100644
--- a/third_party/blink/renderer/platform/image-decoders/DEPS
+++ b/third_party/blink/renderer/platform/image-decoders/DEPS
@@ -6,8 +6,9 @@
     "+third_party/blink/renderer/platform/image-decoders",
 
     # Dependencies.
-    "+base/bits.h",
+    "+base",
     "+cc/paint/image_animation_count.h",
+    "+media",
     "+third_party/blink/renderer/platform/geometry",
     "+third_party/blink/renderer/platform/graphics",
     "+third_party/blink/renderer/platform/instrumentation/histogram.h",
@@ -19,11 +20,3 @@
     "+third_party/blink/renderer/platform/testing",
     "+third_party/blink/renderer/platform/wtf",
 ]
-
-specific_include_rules = {
-    'image_decoder_base_test\.cc': [
-        "+base/hash/md5.h",
-        "+base/path_service.h",
-        "+base/strings/utf_string_conversions.h",
-    ],
-}
diff --git a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc
new file mode 100644
index 0000000..c5f164f
--- /dev/null
+++ b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc
@@ -0,0 +1,633 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h"
+
+#include <memory>
+
+#include "base/containers/adapters.h"
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/numerics/ranges.h"
+#include "base/timer/elapsed_timer.h"
+#include "build/build_config.h"
+#include "media/base/video_color_space.h"
+#include "media/base/video_frame.h"
+#include "media/renderers/paint_canvas_video_renderer.h"
+#include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
+#include "third_party/blink/renderer/platform/image-decoders/image_animation.h"
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/libavif/src/include/avif/avif.h"
+#include "third_party/libyuv/include/libyuv.h"
+#include "third_party/skia/include/core/SkData.h"
+#include "third_party/skia/include/core/SkYUVAIndex.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/color_transform.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+#include "ui/gfx/half_float.h"
+#include "ui/gfx/icc_profile.h"
+
+#if defined(ARCH_CPU_BIG_ENDIAN)
+#error Blink assumes a little-endian target.
+#endif
+
+namespace {
+
+media::VideoPixelFormat AvifToVideoPixelFormat(avifPixelFormat fmt, int depth) {
+  if (depth != 8 && depth != 10 && depth != 12) {
+    // Unsupported bit depth.
+    NOTREACHED();
+    return media::PIXEL_FORMAT_UNKNOWN;
+  }
+  int index = (depth - 8) / 2;
+  static constexpr media::VideoPixelFormat kYUV420Formats[] = {
+      media::PIXEL_FORMAT_I420, media::PIXEL_FORMAT_YUV420P10,
+      media::PIXEL_FORMAT_YUV420P12};
+  static constexpr media::VideoPixelFormat kYUV422Formats[] = {
+      media::PIXEL_FORMAT_I422, media::PIXEL_FORMAT_YUV422P10,
+      media::PIXEL_FORMAT_YUV422P12};
+  static constexpr media::VideoPixelFormat kYUV444Formats[] = {
+      media::PIXEL_FORMAT_I444, media::PIXEL_FORMAT_YUV444P10,
+      media::PIXEL_FORMAT_YUV444P12};
+  switch (fmt) {
+    case AVIF_PIXEL_FORMAT_YUV420:
+      return kYUV420Formats[index];
+    case AVIF_PIXEL_FORMAT_YUV422:
+      return kYUV422Formats[index];
+    case AVIF_PIXEL_FORMAT_YUV444:
+      return kYUV444Formats[index];
+    case AVIF_PIXEL_FORMAT_YV12:
+      NOTIMPLEMENTED();
+      return media::PIXEL_FORMAT_UNKNOWN;
+    case AVIF_PIXEL_FORMAT_NONE:
+      NOTREACHED();
+      return media::PIXEL_FORMAT_UNKNOWN;
+  }
+}
+
+// TODO(wtc): Combine all these very-similar conversion functions into a single
+// function that uses some mechanism (such as template parameters) to handle the
+// actual conversion and output bits.
+void YUVAToBGRA8888(const avifImage* image,
+                    const avifPixelFormatInfo* format_info,
+                    const gfx::ColorTransform* transform,
+                    uint32_t* rgba_dest) {
+  DCHECK_EQ(image->depth, 8u);
+  gfx::Point3F pixel;
+  const float max_channel = float{(1 << image->depth) - 1};
+  for (uint32_t j = 0; j < image->height; ++j) {
+    const int uv_j = j >> format_info->chromaShiftY;
+
+    const uint8_t* y_ptr = reinterpret_cast<uint8_t*>(
+        &image->yuvPlanes[AVIF_CHAN_Y][j * image->yuvRowBytes[AVIF_CHAN_Y]]);
+    const uint8_t* u_ptr = reinterpret_cast<uint8_t*>(
+        &image->yuvPlanes[AVIF_CHAN_U][uv_j * image->yuvRowBytes[AVIF_CHAN_U]]);
+    const uint8_t* v_ptr = reinterpret_cast<uint8_t*>(
+        &image->yuvPlanes[AVIF_CHAN_V][uv_j * image->yuvRowBytes[AVIF_CHAN_V]]);
+
+    for (uint32_t i = 0; i < image->width; ++i) {
+      const int uv_i = i >> format_info->chromaShiftX;
+      // TODO(wtc): Use templates or other ways to avoid doing this comparison
+      // and checking whether the image supports alpha in the inner loop.
+      if (image->yuvRange == AVIF_RANGE_LIMITED) {
+        pixel.set_x(avifLimitedToFullY(image->depth, y_ptr[i]) / max_channel);
+        pixel.set_y(avifLimitedToFullUV(image->depth, u_ptr[uv_i]) /
+                    max_channel);
+        pixel.set_z(avifLimitedToFullUV(image->depth, v_ptr[uv_i]) /
+                    max_channel);
+      } else {
+        pixel.set_x(y_ptr[i] / max_channel);
+        pixel.set_y(u_ptr[uv_i] / max_channel);
+        pixel.set_z(v_ptr[uv_i] / max_channel);
+      }
+
+      transform->Transform(&pixel, 1);
+
+      uint16_t alpha = (1 << image->depth) - 1;
+      if (image->alphaPlane) {
+        alpha = image->alphaPlane[i + j * image->alphaRowBytes];
+        if (image->alphaRange == AVIF_RANGE_LIMITED)
+          alpha = avifLimitedToFullY(image->depth, alpha);
+        if (alpha != (1 << image->depth) - 1)
+          pixel.Scale(alpha / max_channel);
+      }
+
+      *rgba_dest++ = SkPackARGB32NoCheck(
+          alpha,
+          gfx::ToRoundedInt(base::ClampToRange(pixel.x(), 0.0f, 1.0f) *
+                            max_channel),
+          gfx::ToRoundedInt(base::ClampToRange(pixel.y(), 0.0f, 1.0f) *
+                            max_channel),
+          gfx::ToRoundedInt(base::ClampToRange(pixel.z(), 0.0f, 1.0f) *
+                            max_channel));
+    }
+  }
+}
+
+void YAToMono8888(const avifImage* image,
+                  const avifPixelFormatInfo* format_info,
+                  const gfx::ColorTransform* transform,
+                  uint32_t* rgba_dest) {
+  DCHECK_EQ(image->depth, 8u);
+  gfx::Point3F pixel;
+  const float max_channel = float{(1 << image->depth) - 1};
+  for (uint32_t j = 0; j < image->height; ++j) {
+    const uint8_t* y_ptr = reinterpret_cast<uint8_t*>(
+        &image->yuvPlanes[AVIF_CHAN_Y][j * image->yuvRowBytes[AVIF_CHAN_Y]]);
+
+    for (uint32_t i = 0; i < image->width; ++i) {
+      pixel.set_y(0.5f);
+      pixel.set_z(0.5f);
+
+      if (image->yuvRange == AVIF_RANGE_LIMITED) {
+        pixel.set_x(avifLimitedToFullY(image->depth, y_ptr[i]) / max_channel);
+      } else {
+        pixel.set_x(y_ptr[i] / max_channel);
+      }
+
+      transform->Transform(&pixel, 1);
+
+      uint16_t alpha = (1 << image->depth) - 1;
+      if (image->alphaPlane) {
+        alpha = image->alphaPlane[i + j * image->alphaRowBytes];
+        if (image->alphaRange == AVIF_RANGE_LIMITED)
+          alpha = avifLimitedToFullY(image->depth, alpha);
+        if (alpha != (1 << image->depth) - 1)
+          pixel.Scale(alpha / max_channel);
+      }
+
+      *rgba_dest++ = SkPackARGB32NoCheck(
+          alpha,
+          gfx::ToRoundedInt(base::ClampToRange(pixel.x(), 0.0f, 1.0f) *
+                            max_channel),
+          gfx::ToRoundedInt(base::ClampToRange(pixel.y(), 0.0f, 1.0f) *
+                            max_channel),
+          gfx::ToRoundedInt(base::ClampToRange(pixel.z(), 0.0f, 1.0f) *
+                            max_channel));
+    }
+  }
+}
+
+void YUVAToRGBAHalfFloat(const avifImage* image,
+                         const avifPixelFormatInfo* format_info,
+                         const gfx::ColorTransform* transform,
+                         uint16_t* rgba_dest) {
+  DCHECK_GT(image->depth, 8u);
+  float rgba_pixels[] = {0, 0, 0, 1};
+  gfx::Point3F pixel;
+  const float max_channel = float{(1 << image->depth) - 1};
+  const uint16_t* a_ptr = nullptr;
+  uint32_t a_stride = 0;
+  if (image->alphaPlane) {
+    a_ptr = reinterpret_cast<uint16_t*>(image->alphaPlane);
+    a_stride = image->alphaRowBytes >> 1;
+  }
+  for (uint32_t j = 0; j < image->height; ++j) {
+    const int uv_j = j >> format_info->chromaShiftY;
+
+    const uint16_t* y_ptr = reinterpret_cast<uint16_t*>(
+        &image->yuvPlanes[AVIF_CHAN_Y][j * image->yuvRowBytes[AVIF_CHAN_Y]]);
+    const uint16_t* u_ptr = reinterpret_cast<uint16_t*>(
+        &image->yuvPlanes[AVIF_CHAN_U][uv_j * image->yuvRowBytes[AVIF_CHAN_U]]);
+    const uint16_t* v_ptr = reinterpret_cast<uint16_t*>(
+        &image->yuvPlanes[AVIF_CHAN_V][uv_j * image->yuvRowBytes[AVIF_CHAN_V]]);
+
+    for (uint32_t i = 0; i < image->width; ++i) {
+      const int uv_i = i >> format_info->chromaShiftX;
+      if (image->yuvRange == AVIF_RANGE_LIMITED) {
+        pixel.set_x(avifLimitedToFullY(image->depth, y_ptr[i]) / max_channel);
+        pixel.set_y(avifLimitedToFullUV(image->depth, u_ptr[uv_i]) /
+                    max_channel);
+        pixel.set_z(avifLimitedToFullUV(image->depth, v_ptr[uv_i]) /
+                    max_channel);
+      } else {
+        pixel.set_x(y_ptr[i] / max_channel);
+        pixel.set_y(u_ptr[uv_i] / max_channel);
+        pixel.set_z(v_ptr[uv_i] / max_channel);
+      }
+
+      transform->Transform(&pixel, 1);
+
+      rgba_pixels[0] = pixel.x();
+      rgba_pixels[1] = pixel.y();
+      rgba_pixels[2] = pixel.z();
+      if (image->alphaPlane) {
+        if (image->alphaRange == AVIF_RANGE_LIMITED) {
+          rgba_pixels[3] =
+              avifLimitedToFullY(image->depth, a_ptr[i]) / max_channel;
+        } else {
+          rgba_pixels[3] = a_ptr[i] / max_channel;
+        }
+        a_ptr += a_stride;
+      }
+
+      gfx::FloatToHalfFloat(rgba_pixels, rgba_dest, base::size(rgba_pixels));
+      rgba_dest += 4;
+    }
+  }
+}
+
+void YAToMonoHalfFloat(const avifImage* image,
+                       const avifPixelFormatInfo* format_info,
+                       const gfx::ColorTransform* transform,
+                       uint16_t* rgba_dest) {
+  DCHECK_GT(image->depth, 8u);
+  float rgba_pixels[] = {0, 0, 0, 1};
+  gfx::Point3F pixel;
+  const float max_channel = float{(1 << image->depth) - 1};
+  const uint16_t* a_ptr = nullptr;
+  uint32_t a_stride = 0;
+  if (image->alphaPlane) {
+    a_ptr = reinterpret_cast<uint16_t*>(image->alphaPlane);
+    a_stride = image->alphaRowBytes >> 1;
+  }
+  for (uint32_t j = 0; j < image->height; ++j) {
+    const uint16_t* y_ptr = reinterpret_cast<uint16_t*>(
+        &image->yuvPlanes[AVIF_CHAN_Y][j * image->yuvRowBytes[AVIF_CHAN_Y]]);
+
+    for (uint32_t i = 0; i < image->width; ++i) {
+      pixel.set_y(0.5f);
+      pixel.set_z(0.5f);
+
+      if (image->yuvRange == AVIF_RANGE_LIMITED) {
+        pixel.set_x(avifLimitedToFullY(image->depth, y_ptr[i]) / max_channel);
+      } else {
+        pixel.set_x(y_ptr[i] / max_channel);
+      }
+
+      transform->Transform(&pixel, 1);
+
+      rgba_pixels[0] = rgba_pixels[1] = rgba_pixels[2] = pixel.x();
+      if (image->alphaPlane) {
+        if (image->alphaRange == AVIF_RANGE_LIMITED) {
+          rgba_pixels[3] =
+              avifLimitedToFullY(image->depth, a_ptr[i]) / max_channel;
+        } else {
+          rgba_pixels[3] = a_ptr[i] / max_channel;
+        }
+        a_ptr += a_stride;
+      }
+
+      gfx::FloatToHalfFloat(rgba_pixels, rgba_dest, base::size(rgba_pixels));
+      rgba_dest += 4;
+    }
+  }
+}
+
+}  // namespace
+
+namespace blink {
+
+AVIFImageDecoder::AVIFImageDecoder(AlphaOption alpha_option,
+                                   HighBitDepthDecodingOption hbd_option,
+                                   const ColorBehavior& color_behavior,
+                                   size_t max_decoded_bytes)
+    : ImageDecoder(alpha_option,
+                   hbd_option,
+                   color_behavior,
+                   max_decoded_bytes) {}
+
+AVIFImageDecoder::~AVIFImageDecoder() = default;
+
+bool AVIFImageDecoder::ImageIsHighBitDepth() {
+  return is_high_bit_depth_;
+}
+
+void AVIFImageDecoder::OnSetData(SegmentReader* data) {
+  // avifDecoder requires all the data be available before reading and cannot
+  // read incrementally as data comes in. See
+  // https://github.com/AOMediaCodec/libavif/issues/11.
+  if (IsAllDataReceived())
+    MaybeCreateDemuxer();
+}
+
+int AVIFImageDecoder::RepetitionCount() const {
+  return decoded_frame_count_ > 1 ? kAnimationLoopInfinite : kAnimationNone;
+}
+
+base::TimeDelta AVIFImageDecoder::FrameDurationAtIndex(size_t index) const {
+  return index < frame_buffer_cache_.size()
+             ? frame_buffer_cache_[index].Duration()
+             : base::TimeDelta();
+}
+
+// static
+bool AVIFImageDecoder::MatchesAVIFSignature(
+    const FastSharedBufferReader& fast_reader) {
+  // avifPeekCompatibleFileType() clamps compatible brands at 32 when reading in
+  // the ftyp box in ISOBMFF for the 'av01' brand. So the maximum number of
+  // bytes read is 144 bytes (type 4 bytes, size 4 bytes, major brand 4 bytes,
+  // version 4 bytes, and 4 bytes * 32 compatible brands).
+  char buffer[144];
+  avifROData input;
+  input.size = std::min(sizeof(buffer), fast_reader.size());
+  input.data = reinterpret_cast<const uint8_t*>(
+      fast_reader.GetConsecutiveData(0, input.size, buffer));
+  return avifPeekCompatibleFileType(&input);
+}
+
+void AVIFImageDecoder::DecodeSize() {
+  // Because avifDecoder cannot read incrementally as data comes in, we cannot
+  // decode the size until all data is received. When all data is received,
+  // OnSetData() decodes the size right away. So DecodeSize() doesn't need to do
+  // anything.
+}
+
+size_t AVIFImageDecoder::DecodeFrameCount() {
+  return decoded_frame_count_;
+}
+
+void AVIFImageDecoder::InitializeNewFrame(size_t index) {
+  auto& buffer = frame_buffer_cache_[index];
+
+  buffer.SetOriginalFrameRect(IntRect(IntPoint(), Size()));
+
+  // TODO(wtc): libavif provides only the current frame's duration. But when
+  // this method is called, we have not decoded any frames. Change libavif to
+  // provide all frames' durations after avifDecoderParse(). Then call
+  // buffer.SetDuration() here and remove the buffer.SetDuration() call in
+  // Decode().
+
+  // TODO(wtc): Find out if disposal method and alpha blend source are specified
+  // in the file format.
+  buffer.SetDisposalMethod(ImageFrame::kDisposeKeep);
+
+  // TODO(dalecurtis): Is this right? Due to the progressive nature of AV1 video
+  // frames, it seems it should always be "blend atop background"
+  buffer.SetAlphaBlendSource(ImageFrame::kBlendAtopBgcolor);
+
+  if (decode_to_half_float_)
+    buffer.SetPixelFormat(ImageFrame::PixelFormat::kRGBA_F16);
+
+  if (index > 0 && !avifDecoderIsKeyframe(decoder_.get(), index))
+    buffer.SetRequiredPreviousFrameIndex(index - 1);
+}
+
+void AVIFImageDecoder::Decode(size_t index) {
+  // TODO(dalecurtis): For fragmented avif-sequence files we probably want to
+  // allow partial decoding. Depends on if we see frequent use of multi-track
+  // images where there's lots to ignore.
+  if (Failed() || !IsAllDataReceived())
+    return;
+
+  // If we're just decoding metadata create an entry for the first image.
+  auto frames_to_decode = frame_buffer_cache_.IsEmpty()
+                              ? Vector<size_t>(1, 0)
+                              : FindFramesToDecode(index);
+
+  // TODO(wtc): Split up this for loop into component functions for readability
+  // and to reduce nesting. Something like:
+  // DecodeImage(i);
+  // MaybeSetSize(image);
+  // cs = SetColorSpace(image, buffer);
+  // RenderImage(image, cs, buffer);
+  for (auto i : base::Reversed(frames_to_decode)) {
+    if (!pending_decoded_image_ || decoder_->imageIndex != int{i}) {
+      auto ret = (decoder_->imageIndex + 1 == int{i})
+                     ? avifDecoderNextImage(decoder_.get())
+                     : avifDecoderNthImage(decoder_.get(), i);
+      if (ret != AVIF_RESULT_OK || !decoder_->image) {
+        // We shouldn't be called more times than specified in
+        // DecodeFrameCount(); possibly this should truncate if the initial
+        // count is wrong?
+        DCHECK_NE(ret, AVIF_RESULT_NO_IMAGES_REMAINING);
+        SetFailed();
+        return;
+      }
+    }
+
+    const auto* image = decoder_->image;
+    is_high_bit_depth_ = image->depth > 8;
+    decode_to_half_float_ =
+        is_high_bit_depth_ &&
+        high_bit_depth_decoding_option_ == kHighBitDepthToHalfFloat;
+
+    // All frames must be the same size.
+    if (IsSizeAvailable() ? Size() != IntSize(image->width, image->height)
+                          : !SetSize(image->width, image->height)) {
+      SetFailed();
+      return;
+    }
+
+    if (frame_buffer_cache_.IsEmpty()) {
+      pending_decoded_image_ = true;
+      return;
+    }
+
+    pending_decoded_image_ = false;
+    ImageFrame& buffer = frame_buffer_cache_[i];
+    if (buffer.GetStatus() == ImageFrame::kFrameComplete)
+      continue;
+
+    buffer.SetHasAlpha(!!image->alphaPlane);
+    if (decode_to_half_float_)
+      buffer.SetPixelFormat(ImageFrame::PixelFormat::kRGBA_F16);
+
+    // Set color space information on the frame if appropriate.
+    gfx::ColorSpace frame_cs;
+    if (!IgnoresColorSpace()) {
+      if (image->profileFormat == AVIF_PROFILE_FORMAT_NCLX) {
+        media::VideoColorSpace color_space(
+            image->nclx.colourPrimaries, image->nclx.transferCharacteristics,
+            image->nclx.matrixCoefficients,
+            image->nclx.fullRangeFlag ? gfx::ColorSpace::RangeID::FULL
+                                      : gfx::ColorSpace::RangeID::LIMITED);
+        if (color_space.IsSpecified()) {
+          frame_cs = color_space.ToGfxColorSpace();
+        } else if (image->nclx.fullRangeFlag) {
+          frame_cs = gfx::ColorSpace::CreateJpeg();
+        } else {
+          frame_cs = gfx::ColorSpace::CreateREC709();
+        }
+      } else if (image->profileFormat == AVIF_PROFILE_FORMAT_ICC) {
+        auto iccp = gfx::ICCProfile::FromData(image->icc.data, image->icc.size);
+        if (iccp.IsValid())
+          frame_cs = iccp.GetColorSpace();
+
+        // TODO(dalecurtis): Do we need to reparse this per frame when dealing
+        // with animated AVIF files? Or is it only for still picture?
+
+        // TODO(wtc): We need to set the color profile using
+        // SetEmbeddedColorProfile() rather than handling all the color space
+        // conversion during decode.
+      }
+    }
+
+    if (CanSetColorSpace()) {
+      last_color_space_ = frame_cs.GetAsFullRangeRGB();
+    } else {
+      // Just use whatever color space Skia wants us to use.
+    }
+
+    // TODO(wtc): This should use the value of |last_color_space_|. Implement
+    // it.
+    if (!InitFrameBuffer(i)) {
+      DVLOG(1) << "Failed to create frame buffer...";
+      SetFailed();
+      return;
+    }
+
+    auto dest_rgb_cs = gfx::ColorSpace(*buffer.Bitmap().colorSpace());
+    if (!format_info_) {
+      format_info_ = std::make_unique<avifPixelFormatInfo>();
+      avifGetPixelFormatInfo(image->yuvFormat, format_info_.get());
+    }
+
+    const bool is_mono = !image->yuvPlanes[AVIF_CHAN_U];
+
+    // TODO(dalecurtis): We should decode to YUV when possible. Currently the
+    // YUV path seems to only support still-image YUV8.
+    if (decode_to_half_float_) {
+      if (!UpdateColorTransform(frame_cs, dest_rgb_cs)) {
+        DVLOG(1) << "Failed to update color transform...";
+        SetFailed();
+        return;
+      }
+
+      uint16_t* rgba_hhhh =
+          reinterpret_cast<uint16_t*>(buffer.GetAddrF16(0, 0));
+
+      // Color and format convert from YUV HBD -> RGBA half float.
+      if (is_mono) {
+        YAToMonoHalfFloat(image, format_info_.get(), color_transform_.get(),
+                          rgba_hhhh);
+      } else {
+        // TODO: Add fast path for 10bit 4:2:0 using libyuv.
+        YUVAToRGBAHalfFloat(image, format_info_.get(), color_transform_.get(),
+                            rgba_hhhh);
+      }
+    } else {
+      uint32_t* rgba_8888 = buffer.GetAddr(0, 0);
+      if (ImageIsHighBitDepth() ||
+          // TODO(wtc): Figure out a way to check frame_cs == ~BT.2020 too since
+          // ConvertVideoFrameToRGBPixels() can handle that too.
+          frame_cs == gfx::ColorSpace::CreateREC709() ||
+          frame_cs == gfx::ColorSpace::CreateREC601() ||
+          frame_cs == gfx::ColorSpace::CreateJpeg()) {
+        // Create temporary frame wrapping the YUVA planes.
+        scoped_refptr<media::VideoFrame> frame;
+        auto pixel_format =
+            AvifToVideoPixelFormat(image->yuvFormat, image->depth);
+        if (pixel_format == media::PIXEL_FORMAT_UNKNOWN) {
+          SetFailed();
+          return;
+        }
+        auto size = gfx::Size(image->width, image->height);
+        if (image->alphaPlane) {
+          if (pixel_format == media::PIXEL_FORMAT_I420) {
+            pixel_format = media::PIXEL_FORMAT_I420A;
+          } else {
+            NOTIMPLEMENTED();
+            SetFailed();
+            return;
+          }
+          frame = media::VideoFrame::WrapExternalYuvaData(
+              pixel_format, size, gfx::Rect(size), size, image->yuvRowBytes[0],
+              image->yuvRowBytes[1], image->yuvRowBytes[2],
+              image->alphaRowBytes, image->yuvPlanes[0], image->yuvPlanes[1],
+              image->yuvPlanes[2], image->alphaPlane, base::TimeDelta());
+        } else {
+          frame = media::VideoFrame::WrapExternalYuvData(
+              pixel_format, size, gfx::Rect(size), size, image->yuvRowBytes[0],
+              image->yuvRowBytes[1], image->yuvRowBytes[2], image->yuvPlanes[0],
+              image->yuvPlanes[1], image->yuvPlanes[2], base::TimeDelta());
+        }
+
+        // Really only handles 709, 601, JPEG 8-bit conversions and uses libyuv
+        // under the hood, so is much faster than our manual path.
+        //
+        // Technically has support for 10-bit 4:2:0 and 4:2:2, but not to
+        // half-float and only has support for 4:4:4 and 12-bit by down-shifted
+        // copies.
+        //
+        // https://bugs.chromium.org/p/libyuv/issues/detail?id=845
+        media::PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
+            frame.get(), rgba_8888, frame->visible_rect().width() * 4);
+      } else {
+        if (!UpdateColorTransform(frame_cs, dest_rgb_cs)) {
+          DVLOG(1) << "Failed to update color transform...";
+          SetFailed();
+          return;
+        }
+        if (is_mono) {
+          YAToMono8888(image, format_info_.get(), color_transform_.get(),
+                       rgba_8888);
+        } else {
+          YUVAToBGRA8888(image, format_info_.get(), color_transform_.get(),
+                         rgba_8888);
+        }
+      }
+    }
+
+    buffer.SetDuration(
+        base::TimeDelta::FromSecondsD(decoder_->imageTiming.duration));
+    buffer.SetPixelsChanged(true);
+    buffer.SetStatus(ImageFrame::kFrameComplete);
+  }
+}
+
+void AVIFImageDecoder::MaybeCreateDemuxer() {
+  if (Failed() || !IsAllDataReceived() || decoder_)
+    return;
+
+  decoder_ = std::unique_ptr<avifDecoder, void (*)(avifDecoder*)>(
+      avifDecoderCreate(), avifDecoderDestroy);
+  if (!decoder_) {
+    SetFailed();
+    return;
+  }
+
+  // TODO(dalecurtis): This may create a second copy of the media data in
+  // memory, which is not great. Upstream should provide a read() based API:
+  // https://github.com/AOMediaCodec/libavif/issues/11
+  image_data_ = data_->GetAsSkData();
+  if (!image_data_) {
+    SetFailed();
+    return;
+  }
+
+  avifROData raw_data = {image_data_->bytes(), image_data_->size()};
+  auto ret = avifDecoderParse(decoder_.get(), &raw_data);
+  if (ret != AVIF_RESULT_OK) {
+    DVLOG(1) << "avifDecoderParse failed: " << avifResultToString(ret);
+    SetFailed();
+    return;
+  }
+
+  DCHECK_GT(decoder_->imageCount, 0);
+  decoded_frame_count_ = decoder_->imageCount;
+  is_high_bit_depth_ = decoder_->containerDepth > 8;
+  decode_to_half_float_ =
+      is_high_bit_depth_ &&
+      high_bit_depth_decoding_option_ == kHighBitDepthToHalfFloat;
+
+  // Try to get the size from the container if possible instead of decoding.
+  if (decoder_->containerWidth && decoder_->containerHeight) {
+    SetSize(decoder_->containerWidth, decoder_->containerHeight);
+    return;
+  }
+
+  // We need to SetSize() to proceed, so decode the first frame.
+  Decode(0);
+}
+
+bool AVIFImageDecoder::UpdateColorTransform(const gfx::ColorSpace& src_cs,
+                                            const gfx::ColorSpace& dest_cs) {
+  if (color_transform_ && color_transform_->GetSrcColorSpace() == src_cs)
+    return true;
+  color_transform_ = gfx::ColorTransform::NewColorTransform(
+      src_cs, dest_cs, gfx::ColorTransform::Intent::INTENT_PERCEPTUAL);
+  return !!color_transform_;
+}
+
+// TODO(wtc): We must be able to set the color space accurately. Find a solution
+// that lets us set the color space for all images and not just the half float
+// and animated cases.
+bool AVIFImageDecoder::CanSetColorSpace() const {
+  return decode_to_half_float_ || decoded_frame_count_ > 1;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h
new file mode 100644
index 0000000..da23b0f
--- /dev/null
+++ b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h
@@ -0,0 +1,79 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_AVIF_AVIF_IMAGE_DECODER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_AVIF_AVIF_IMAGE_DECODER_H_
+
+#include <memory>
+
+#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkData.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/color_transform.h"
+
+struct avifDecoder;
+struct avifPixelFormatInfo;
+
+namespace blink {
+
+class FastSharedBufferReader;
+
+class PLATFORM_EXPORT AVIFImageDecoder final : public ImageDecoder {
+ public:
+  AVIFImageDecoder(AlphaOption,
+                   HighBitDepthDecodingOption,
+                   const ColorBehavior&,
+                   size_t max_decoded_bytes);
+  AVIFImageDecoder(const AVIFImageDecoder&) = delete;
+  AVIFImageDecoder& operator=(const AVIFImageDecoder&) = delete;
+  ~AVIFImageDecoder() override;
+
+  // ImageDecoder:
+  String FilenameExtension() const override { return "avif"; }
+  bool ImageIsHighBitDepth() override;
+  void OnSetData(SegmentReader* data) override;
+  int RepetitionCount() const override;
+  base::TimeDelta FrameDurationAtIndex(size_t) const override;
+
+  // Returns true if the data in fast_reader begins with a valid FileTypeBox
+  // (ftyp) that supports the brand 'avif' or 'avis'.
+  static bool MatchesAVIFSignature(const FastSharedBufferReader& fast_reader);
+
+ private:
+  // ImageDecoder:
+  void DecodeSize() override;
+  size_t DecodeFrameCount() override;
+  void InitializeNewFrame(size_t) override;
+  void Decode(size_t) override;
+
+  // Creates |decoder_| and decodes the first frame.
+  void MaybeCreateDemuxer();
+
+  // Updates or creates |color_transform_|. Returns true on success, false on
+  // failure.
+  bool UpdateColorTransform(const gfx::ColorSpace& src_cs,
+                            const gfx::ColorSpace& dest_cs);
+
+  // Returns true if we can set the color space on the image.
+  bool CanSetColorSpace() const;
+
+  bool pending_decoded_image_ = false;
+  bool is_high_bit_depth_ = false;
+  bool decode_to_half_float_ = false;
+  size_t decoded_frame_count_ = 0;
+  std::unique_ptr<avifDecoder, void (*)(avifDecoder*)> decoder_{nullptr,
+                                                                nullptr};
+
+  std::unique_ptr<avifPixelFormatInfo> format_info_;
+  std::unique_ptr<gfx::ColorTransform> color_transform_;
+
+  gfx::ColorSpace last_color_space_;
+  sk_sp<SkData> image_data_;
+  SkBitmap temp_bitmap_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_AVIF_AVIF_IMAGE_DECODER_H_
diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
index f677b4003..76c56ed 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
+++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc
@@ -23,6 +23,8 @@
 #include <memory>
 
 #include "base/numerics/safe_conversions.h"
+#include "media/media_buildflags.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.h"
 #include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
 #include "third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder.h"
@@ -34,6 +36,10 @@
 #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
 #include "ui/gfx/geometry/size.h"
 
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+#include "third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h"
+#endif
+
 namespace blink {
 
 namespace {
@@ -51,6 +57,12 @@
     return cc::ImageType::kICO;
   if (image_extension == "bmp")
     return cc::ImageType::kBMP;
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+  if (base::FeatureList::IsEnabled(features::kAVIF) &&
+      image_extension == "avif") {
+    return cc::ImageType::kAVIF;
+  }
+#endif
   return cc::ImageType::kInvalid;
 }
 
@@ -148,6 +160,13 @@
   } else if (MatchesBMPSignature(contents)) {
     decoder = std::make_unique<BMPImageDecoder>(alpha_option, color_behavior,
                                                 max_decoded_bytes);
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+  } else if (base::FeatureList::IsEnabled(features::kAVIF) &&
+             AVIFImageDecoder::MatchesAVIFSignature(fast_reader)) {
+    decoder = std::make_unique<AVIFImageDecoder>(
+        alpha_option, high_bit_depth_decoding_option, color_behavior,
+        max_decoded_bytes);
+#endif
   }
 
   if (decoder)
@@ -182,6 +201,13 @@
     return "image/x-icon";
   if (MatchesBMPSignature(contents))
     return "image/bmp";
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+  if (base::FeatureList::IsEnabled(features::kAVIF) &&
+      AVIFImageDecoder::MatchesAVIFSignature(fast_reader)) {
+    // TODO(wtc): Sniff AVIF image sequences and return image/avif-sequence.
+    return "image/avif";
+  }
+#endif
   return String();
 }
 
@@ -246,6 +272,18 @@
     }
   }
 
+#if BUILDFLAG(ENABLE_AV1_DECODER)
+  // Attempt to sniff whether an AVIF image is using a lossy or lossless
+  // compression algorithm.
+  // TODO(wtc): Implement this. Figure out whether to return kUndefinedFormat or
+  // a new kAVIFAnimationFormat in the case of an animated AVIF image.
+  if (base::FeatureList::IsEnabled(features::kAVIF) &&
+      (EqualIgnoringASCIICase(mime_type, "image/avif") ||
+       EqualIgnoringASCIICase(mime_type, "image/avif-sequence"))) {
+    return kLossyFormat;
+  }
+#endif
+
   if (MIMETypeRegistry::IsLossyImageMIMEType(mime_type))
     return kLossyFormat;
   if (MIMETypeRegistry::IsLosslessImageMIMEType(mime_type))
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index a344d39..57de3c3 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6596,3 +6596,6 @@
 crbug.com/1067084 virtual/paint-timing/external/wpt/paint-timing/fcp-only/fcp-with-rtl.html [ Pass Failure ]
 # Sheriff 2020-04-04
 crbug.com/1067533 [ Mac10.10 ] external/wpt/shape-detection/idlharness.https.any.sharedworker.html [ Pass Failure ]
+
+crbug.com/1064422 external/wpt/html/user-activation/propagation-crossorigin.sub.tentative.html [ Pass Timeout ]
+crbug.com/1066178 external/wpt/html/user-activation/consumption-crossorigin.sub.tentative.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/css3/filters/effect-reference-lighting-no-light.html b/third_party/blink/web_tests/css3/filters/effect-reference-lighting-no-light.html
deleted file mode 100644
index b957e55..0000000
--- a/third_party/blink/web_tests/css3/filters/effect-reference-lighting-no-light.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<style>
-.target {
-  display: inline-block;
-  width: 100px;
-  height: 100px;
-  background-color: red;
-}
-</style>
-<div class="target" style="filter: url(#noLightDiffuse)"></div>
-<div class="target" style="filter: url(#noLightSpecular)"></div>
-<svg height="0" color-interpolation-filters="sRGB">
-  <filter id="noLightDiffuse" x="0" y="0" width="1" height="1">
-    <feDiffuseLighting lighting-color="blue"/>
-    <feColorMatrix values="1 0 0 0 0,
-                           0 1 0 0 0.5,
-                           0 0 1 0 0,
-                           0 0 0 1 1"/>
-  </filter>
-
-  <filter id="noLightSpecular" x="0" y="0" width="1" height="1">
-    <feSpecularLighting lighting-color="blue"/>
-    <feColorMatrix values="1 0 0 0 0,
-                           0 1 0 0 0.5,
-                           0 0 1 0 0,
-                           0 0 0 1 1"/>
-  </filter>
-</svg>
diff --git a/third_party/blink/web_tests/css3/flexbox/crash-removing-out-of-flow-child.html b/third_party/blink/web_tests/css3/flexbox/crash-removing-out-of-flow-child.html
deleted file mode 100644
index bcf25f2..0000000
--- a/third_party/blink/web_tests/css3/flexbox/crash-removing-out-of-flow-child.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<link href="resources/flexbox.css" rel="stylesheet">
-</head>
-<body>
-
-<p>This test passes if it doesn't crash.</p>
-
-<div id="outer" class="inline-flexbox"><div class="inline-flexbox"><div id="inner" style="position: absolute">absolute</div></div></div>
-
-<script>
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-var outer = document.getElementById("outer");
-var inner = document.getElementById("inner");
-
-// Force layout.
-outer.offsetHeight;
-
-outer.firstChild.removeChild(inner);
-</script>
-
-<div>This test passes if it doesn't crash.</div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/css3/flexbox/overflow-auto-dynamic-changes.html b/third_party/blink/web_tests/css3/flexbox/overflow-auto-dynamic-changes.html
deleted file mode 100644
index 851ef3b..0000000
--- a/third_party/blink/web_tests/css3/flexbox/overflow-auto-dynamic-changes.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!DOCTYPE html>
-
-<style>
-  body {
-    width: 400px;
-    height: 300px;
-  }
-
-  .flexbox {
-    display: flex;
-  }
-
-  .column {
-    flex-direction: column;
-  }
-
-  .flex11a {
-    flex: 1 1 auto;
-  }
-
-  .root {
-    height: 100px;
-    overflow-y: auto;
-  }
-</style>
-
-
-<p>This test should not have a horizontal scrollbar</p>
-
-<div class="flexbox column">
-  <div class="flexbox">
-    <div class="flex11a">
-      <div class="root">
-        <div id="history"></div>
-      </div>
-    </div>
-  </div>
-</div>
-
-<script>
-onload = function() {
-  var historyEl = document.getElementById('history');
-  historyEl.offsetWidth;
-  historyEl.innerText = '\n\n\n\n\n\n\n\n';
-};
-</script>
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/overflow-auto-007.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/overflow-auto-007.html
new file mode 100644
index 0000000..1bb6230
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/overflow-auto-007.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<title>CSS Flexbox: vertical space after changes with overflow: auto and flex-direction: column.</title>
+<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#overflow-properties">
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#flex-direction-property">
+<link rel="help" href="https://crbug.com/590683">
+<link rel="help" href="https://crbug.com/594465">
+<link rel="match" href="reference/overflow-auto-007-ref.html">
+<meta name="assert" content="This test checks that vertical space allocated to the content of a flexbox with 'overflow: auto' and 'flex-direction: column' is properly computed when its contents change." />
+
+<style>
+body {
+  width: 400px;
+  height: 300px;
+}
+
+.flexbox {
+  display: flex;
+}
+
+.column {
+  flex-direction: column;
+}
+
+.flex11a {
+  flex: 1 1 auto;
+}
+
+.root {
+  height: 100px;
+  overflow-y: auto;
+}
+</style>
+
+<body onload="runTest()">
+
+<p>This test should not have a horizontal scrollbar</p>
+
+<div class="flexbox column">
+  <div class="flexbox">
+    <div class="flex11a">
+      <div class="root">
+        <div id="history"></div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<script>
+function runTest() {
+  var historyEl = document.getElementById('history');
+  historyEl.offsetWidth;
+  historyEl.innerText = '\n\n\n\n\n\n\n\n';
+};
+</script>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/css3/flexbox/overflow-auto-dynamic-changes-expected.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/reference/overflow-auto-007-ref.html
similarity index 100%
rename from third_party/blink/web_tests/css3/flexbox/overflow-auto-dynamic-changes-expected.html
rename to third_party/blink/web_tests/external/wpt/css/css-flexbox/reference/overflow-auto-007-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/remove-out-of-flow-child-crash.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/remove-out-of-flow-child-crash.html
new file mode 100644
index 0000000..dfffdffd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/remove-out-of-flow-child-crash.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>CSS Flexbox: absolutely position child removal.</title>
+<link rel="stylesheet" href="support/flexbox.css" >
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#abspos-items">
+<meta name="assert" content="This test ensures that removing absolute positioned flexbox children works."/>
+</head>
+<body>
+
+<div id="outer" class="inline-flexbox">
+  <div id="middle" class="inline-flexbox">
+    <div id="inner" style="position: absolute">absolute</div>
+  </div>
+</div>
+
+<script>
+  var outer = document.getElementById("outer");
+  var middle = document.getElementById("middle");
+  var inner = document.getElementById("inner");
+
+  // Force layout.
+  outer.offsetHeight;
+
+  middle.removeChild(inner);
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/svg-root-as-flex-item-001.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/svg-root-as-flex-item-001.html
new file mode 100644
index 0000000..d42cf652
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/svg-root-as-flex-item-001.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>SVG root as flex item</title>
+<link rel="author" title="David Grogan" href="mailto:dgrogan@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#algo-main-item" title="Part E">
+<!-- The note refers to CSS2§10, but I didn't include that here because items in flex formatting contexts aren't included. -->
+<link rel="help" href="https://www.w3.org/TR/css-sizing-3/#intrinsic-sizes" title="first Note">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<link rel="bookmark" href="https://crbug.com/1065134">
+<meta name="flags" content="" />
+<meta name="assert" content="Honor SVG root's aspect ratio for flex layout." />
+
+<style>
+#reference-overlapped-red {
+  position: absolute;
+  background-color: red;
+  width: 100px;
+  height: 100px;
+  z-index: -1;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div id="reference-overlapped-red"></div>
+
+<div style="display: flex;">
+  <svg viewBox="0 0 200 200" style="height: 100px">
+    <rect width="200" height="200" fill="green" />
+  </svg>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-lighting-no-light.tentative.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-lighting-no-light.tentative.html
new file mode 100644
index 0000000..beefd47
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/filter-effects/effect-reference-lighting-no-light.tentative.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>CSS Filters: feDiffuseLighting and feSpecularLighting error handling.</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects/#feDiffuseLightingElement">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects/#feSpecularLightingElement">
+<link rel="match" href="reference/effect-reference-lighting-no-light.tentative-ref.html">
+<meta name="assert" content="This test ensures that invalid parameters to both feDiffuseLighting and feSpecularLighting produce transparent black."/>
+<style>
+.target {
+  display: inline-block;
+  width: 100px;
+  height: 100px;
+  background-color: red;
+}
+</style>
+<div class="target" style="filter: url(#noLightDiffuse)"></div>
+<div class="target" style="filter: url(#noLightSpecular)"></div>
+<svg height="0" color-interpolation-filters="sRGB">
+  <filter id="noLightDiffuse" x="0" y="0" width="1" height="1">
+    <feDiffuseLighting lighting-color="blue"/>
+    <!-- Using 0.5 on the matrices below can cause in different engines
+     an off-by-one difference (127 vs. 128), when rounding 127.5 (255 * 0.5)
+     either up or downwards.
+     Hence, the test uses 0.502 (~128/255) to avoid this tie-break. -->
+    <feColorMatrix values="1 0 0 0 0,
+                           0 1 0 0 0.502,
+                           0 0 1 0 0,
+                           0 0 0 1 1"/>
+  </filter>
+
+  <filter id="noLightSpecular" x="0" y="0" width="1" height="1">
+    <feSpecularLighting lighting-color="blue"/>
+    <feColorMatrix values="1 0 0 0 0,
+                           0 1 0 0 0.502,
+                           0 0 1 0 0,
+                           0 0 0 1 1"/>
+  </filter>
+</svg>
diff --git a/third_party/blink/web_tests/css3/filters/effect-reference-lighting-no-light-expected.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-lighting-no-light.tentative-ref.html
similarity index 100%
rename from third_party/blink/web_tests/css3/filters/effect-reference-lighting-no-light-expected.html
rename to third_party/blink/web_tests/external/wpt/css/filter-effects/reference/effect-reference-lighting-no-light.tentative-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/k-rate-biquad-connection.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/k-rate-biquad-connection.html
deleted file mode 100644
index 89e9915..0000000
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/k-rate-biquad-connection.html
+++ /dev/null
@@ -1,421 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>Test k-rate AudioParam Inputs for BiquadFilterNode</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="/webaudio/resources/audit-util.js"></script>
-    <script src="/webaudio/resources/audit.js"></script>
-  </head>
-
-  <body>
-    <script>
-      // sampleRate and duration are fairly arbitrary.  We use low values to
-      // limit the complexity of the test.
-      let sampleRate = 8000;
-      let testDuration = 0.5;
-
-      let audit = Audit.createTaskRunner();
-
-      audit.define(
-          {label: 'Frequency AudioParam', description: 'k-rate input works'},
-          (task, should) => {
-            // Test frequency AudioParam using a lowpass filter whose bandwidth
-            // is initially larger than the oscillator frequency.  Then automate
-            // the frequency to 0 so that the output of the filter is 0 (because
-            // the cutoff is 0).
-            let oscFrequency = 440;
-
-            let options = {
-              sampleRate: sampleRate,
-              paramName: 'frequency',
-              oscFrequency: oscFrequency,
-              testDuration: testDuration,
-              filterOptions: {type: 'lowpass', frequency: 0},
-              autoStart:
-                  {method: 'setValueAtTime', args: [2 * oscFrequency, 0]},
-              autoEnd: {
-                method: 'linearRampToValueAtTime',
-                args: [0, testDuration / 4]
-              }
-            };
-
-            doTest(should, options)
-                .then(buffer => {
-                  let expected = buffer.getChannelData(0);
-                  let actual = buffer.getChannelData(1);
-                  let halfLength = expected.length / 2;
-
-                  // Sanity check.  The expected output should not be zero for
-                  // the first half, but should be zero for the second half
-                  // (because the filter bandwidth is exactly 0).
-                  const prefix = 'Expected k-rate frequency with automation';
-
-                  should(
-                      expected.slice(0, halfLength),
-                      `${prefix} output[0:${halfLength - 1}]`)
-                      .notBeConstantValueOf(0);
-                  should(
-                      expected.slice(expected.length),
-                      `${prefix} output[${halfLength}:]`)
-                      .beConstantValueOf(0);
-
-                  // Outputs should be the same.  Break the message into two
-                  // parts so we can see the expected outputs.
-                  checkForSameOutput(
-                      should, options.paramName, actual, expected);
-                })
-                .then(() => task.done());
-          });
-
-      audit.define(
-          {label: 'Q AudioParam', description: 'k-rate input works'},
-          (task, should) => {
-            // Test Q AudioParam.  Use a bandpass filter whose center frequency
-            // is fairly far from the oscillator frequency.  Then start with a Q
-            // value of 0 (so everything goes through) and then increase Q to
-            // some large value such that the out-of-band signals are basically
-            // cutoff.
-            let frequency = 440;
-            let oscFrequency = 4 * frequency;
-
-            let options = {
-              sampleRate: sampleRate,
-              oscFrequency: oscFrequency,
-              testDuration: testDuration,
-              paramName: 'Q',
-              filterOptions: {type: 'bandpass', frequency: frequency, Q: 0},
-              autoStart: {method: 'setValueAtTime', args: [0, 0]},
-              autoEnd: {
-                method: 'linearRampToValueAtTime',
-                args: [100, testDuration / 4]
-              }
-            };
-
-            doTest(should, options)
-                .then(buffer => {
-                  let expected = buffer.getChannelData(0);
-                  let actual = buffer.getChannelData(1);
-
-                  // Outputs should be the same
-                  checkForSameOutput(
-                      should, options.paramName, actual, expected);
-                })
-                .then(() => task.done());
-          });
-
-      audit.define(
-          {label: 'Gain AudioParam', description: 'k-rate input works'},
-          (task, should) => {
-            // Test gain AudioParam.  Use a peaking filter with a large Q so the
-            // peak is narrow with a center frequency the same as the oscillator
-            // frequency.  Start with a gain of 0 so everything goes through and
-            // then ramp the gain down to -100 so that the oscillator is
-            // filtered out.
-            let oscFrequency = 4 * 440;
-
-            let options = {
-              sampleRate: sampleRate,
-              oscFrequency: oscFrequency,
-              testDuration: testDuration,
-              paramName: 'gain',
-              filterOptions:
-                  {type: 'peaking', frequency: oscFrequency, Q: 100, gain: 0},
-              autoStart: {method: 'setValueAtTime', args: [0, 0]},
-              autoEnd: {
-                method: 'linearRampToValueAtTime',
-                args: [-100, testDuration / 4]
-              }
-            };
-
-            doTest(should, options)
-                .then(buffer => {
-                  let expected = buffer.getChannelData(0);
-                  let actual = buffer.getChannelData(1);
-
-                  // Outputs should be the same
-                  checkForSameOutput(
-                      should, options.paramName, actual, expected);
-                })
-                .then(() => task.done());
-          });
-
-      audit.define(
-          {label: 'Detune AudioParam', description: 'k-rate input works'},
-          (task, should) => {
-            // Test detune AudioParam.  The basic idea is the same as the
-            // frequency test above, but insteda of automating the frequency, we
-            // automate the detune value so that initially the filter cutuff is
-            // unchanged and then changing the detune until the cutoff goes to 1
-            // Hz, which would cause the oscillator to be filtered out.
-            let oscFrequency = 440;
-            let filterFrequency = 5 * oscFrequency;
-
-            // For a detune value d, the computed frequency, fc, of the filter
-            // is fc = f*2^(d/1200), where f is the frequency of the filter.  Or
-            // d = 1200*log2(fc/f).  Compute the detune value to produce a final
-            // cutoff frequency of 1 Hz.
-            let detuneEnd = 1200 * Math.log2(1 / filterFrequency);
-
-            let options = {
-              sampleRate: sampleRate,
-              oscFrequency: oscFrequency,
-              testDuration: testDuration,
-              paramName: 'detune',
-              filterOptions: {
-                type: 'lowpass',
-                frequency: filterFrequency,
-                detune: 0,
-                gain: 0
-              },
-              autoStart: {method: 'setValueAtTime', args: [0, 0]},
-              autoEnd: {
-                method: 'linearRampToValueAtTime',
-                args: [detuneEnd, testDuration / 4]
-              }
-            };
-
-            doTest(should, options)
-                .then(buffer => {
-                  let expected = buffer.getChannelData(0);
-                  let actual = buffer.getChannelData(1);
-
-                  // Outputs should be the same
-                  checkForSameOutput(
-                      should, options.paramName, actual, expected);
-                })
-                .then(() => task.done());
-          });
-
-      audit.define('All k-rate inputs', (task, should) => {
-        // Test the case where all AudioParams are set to k-rate with an input
-        // to each AudioParam.  Similar to the above tests except all the params
-        // are k-rate.
-        let testFrames = testDuration * sampleRate;
-        let context = new OfflineAudioContext(
-            {numberOfChannels: 2, sampleRate: sampleRate, length: testFrames});
-
-        let merger = new ChannelMergerNode(
-            context, {numberOfInputs: context.destination.channelCount});
-        merger.connect(context.destination);
-
-        let src = new OscillatorNode(context);
-
-        // The peaking filter uses all four AudioParams, so this is the node to
-        // test.
-        let filterOptions =
-            {type: 'peaking', frequency: 0, detune: 0, gain: 0, Q: 0};
-        let refNode =
-            new BiquadFilterNode(context, {type: 'peaking', filterOptions});
-        let tstNode =
-            new BiquadFilterNode(context, {type: 'peaking', filterOptions});
-
-        // Make all the AudioParams k-rate.
-        ['frequency', 'Q', 'gain', 'detune'].forEach(param => {
-          refNode[param].automationRate = 'k-rate';
-          tstNode[param].automationRate = 'k-rate';
-        });
-
-        // One input for each AudioParam.
-        let mod = {};
-        ['frequency', 'Q', 'gain', 'detune'].forEach(param => {
-          mod[param] = new ConstantSourceNode(context, {offset: 0});
-          mod[param].offset.automationRate = 'a-rate';
-        });
-
-        // Set up automations for refNode.  We want to start the filter with
-        // parameters that let the oscillator signal through more or less
-        // untouched.  Then change the filter parameters to filter out the
-        // oscillator.  What happens in between doesn't reall matter for this
-        // test.  Hence, set the initial parameters with a center frequency well
-        // above the oscillator and a Q and gain of 0 to pass everthing.
-        [['frequency', [4 * src.frequency.value, 0]], ['Q', [0, 0]],
-         ['gain', [0, 0]], ['detune', [4 * 1200, 0]]]
-            .forEach(param => {
-              refNode[param[0]].setValueAtTime(...param[1]);
-              for (let modParam in mod) {
-                mod[modParam].offset.setValueAtTime(...param[1]);
-              }
-            });
-
-        // Now move the filter frequency to the oscillator frequency with a high
-        // Q and very low gain to remove the oscillator signal.
-        [['frequency', [src.frequency.value, testDuration / 4]],
-         ['Q', [40, testDuration / 4]], ['gain', [-100, testDuration / 4]],
-         ['detune', [0, testDuration / 4]]]
-            .forEach(param => {
-              refNode[param[0]].linearRampToValueAtTime(...param[1]);
-              for (let modParam in mod) {
-                mod[modParam].offset.linearRampToValueAtTime(...param[1]);
-              }
-            });
-
-        // Connect everything
-        src.connect(refNode).connect(merger, 0, 0);
-        src.connect(tstNode).connect(merger, 0, 1);
-
-        src.start();
-        for (let param in mod) {
-          mod[param].connect(tstNode[param]);
-          mod[param].start();
-        }
-
-        context.startRendering()
-            .then(buffer => {
-              let expected = buffer.getChannelData(0);
-              let actual = buffer.getChannelData(1);
-
-              // Sanity check that the output isn't all zeroes.
-              should(actual, 'All k-rate AudioParams').notBeConstantValueOf(0);
-              should(actual, 'All k-rate AudioParams')
-                  .beCloseToArray(expected, {absoluteThreshold: 0});
-            })
-            .then(() => task.done());
-      });
-
-      function doTest(should, options) {
-        // Test that a k-rate AudioParam with an input reads the input value and
-        // is actually k-rate.
-        //
-        // A refNode is created with an automation timeline.  This is the
-        // expected output.
-        //
-        // The testNode is the same, but it has a node connected to the k-rate
-        // AudioParam.  The input to the node is an a-rate ConstantSourceNode
-        // whose output is automated in exactly the same was as the refNode.  If
-        // the test passes, the outputs of the two nodes MUST match exactly.
-
-        // The options argument MUST contain the following members:
-        //   sampleRate - the sample rate for the offline context
-        //   testDuration - duration of the offline context, in sec.
-        //   paramName  - the name of the AudioParam to be tested
-        //   oscFrequency - frequency of oscillator source
-        //   filterOptions - options used to construct the BiquadFilterNode
-        //   autoStart     - information about how to start the automation
-        //   autoEnd       - information about how to end the automation
-        //
-        //   The autoStart and autoEnd options are themselves dictionaries with
-        //   the following required members:
-        //     method - name of the automation method to be applied
-        //     args   - array of arguments to be supplied to the method.
-        let {
-          sampleRate,
-          paramName,
-          oscFrequency,
-          autoStart,
-          autoEnd,
-          testDuration,
-          filterOptions
-        } = options;
-
-        let testFrames = testDuration * sampleRate;
-        let context = new OfflineAudioContext(
-            {numberOfChannels: 2, sampleRate: sampleRate, length: testFrames});
-
-        let merger = new ChannelMergerNode(
-            context, {numberOfInputs: context.destination.channelCount});
-        merger.connect(context.destination);
-
-        // Any calls to |should| are meant to be informational so we can see
-        // what nodes are created and the automations used.
-        let src;
-
-        // Create the source.
-        should(
-            () => {
-              src = new OscillatorNode(context, {frequency: oscFrequency});
-            },
-            `${paramName}: new OscillatorNode(context, {frequency: ${
-                oscFrequency}})`)
-            .notThrow();
-
-        // The refNode automates the AudioParam with k-rate automations, no
-        // inputs.
-        let refNode;
-        should(
-            () => {
-              refNode = new BiquadFilterNode(context, filterOptions);
-            },
-            `Reference BiquadFilterNode(c, ${JSON.stringify(filterOptions)})`)
-            .notThrow();
-
-        refNode[paramName].automationRate = 'k-rate';
-
-        // Set up automations for the reference node.
-        should(
-            () => {
-              refNode[paramName][autoStart.method](...autoStart.args);
-            },
-            `refNode.${paramName}.${autoStart.method}(${autoStart.args})`)
-            .notThrow();
-        should(
-            () => {
-              refNode[paramName][autoEnd.method](...autoEnd.args);
-            },
-            `refNode.${paramName}.${autoEnd.method}.(${autoEnd.args})`)
-            .notThrow();
-
-        // The tstNode does the same automation, but it comes from the input
-        // connected to the AudioParam.
-        let tstNode;
-        should(
-            () => {
-              tstNode = new BiquadFilterNode(context, filterOptions);
-            },
-            `Test BiquadFilterNode(context, ${JSON.stringify(filterOptions)})`)
-            .notThrow();
-        tstNode[paramName].automationRate = 'k-rate';
-
-        // Create the input to the AudioParam of the test node.  The output of
-        // this node MUST have the same set of automations as the reference
-        // node, and MUST be a-rate to make sure we're handling k-rate inputs
-        // correctly.
-        let mod = new ConstantSourceNode(context);
-        mod.offset.automationRate = 'a-rate';
-        should(
-            () => {
-              mod.offset[autoStart.method](...autoStart.args);
-            },
-            `${paramName}: mod.offset.${autoStart.method}(${autoStart.args})`)
-            .notThrow();
-        should(
-            () => {
-              mod.offset[autoEnd.method](...autoEnd.args);
-            },
-            `${paramName}: mod.offset.${autoEnd.method}(${autoEnd.args})`)
-            .notThrow();
-
-        // Create graph
-        mod.connect(tstNode[paramName]);
-        src.connect(refNode).connect(merger, 0, 0);
-        src.connect(tstNode).connect(merger, 0, 1);
-
-        // Run!
-        src.start();
-        mod.start();
-        return context.startRendering();
-      }
-
-      function checkForSameOutput(should, paramName, actual, expected) {
-        let halfLength = expected.length / 2;
-
-        // Outputs should be the same.  We break the check into halves so we can
-        // see the expected outputs.  Mostly for a simple visual check that the
-        // output from the second half is small because the tests generally try
-        // to filter out the signal so that the last half of the output is
-        // small.
-        should(
-            actual.slice(0, halfLength),
-            `k-rate ${paramName} with input: output[0,${halfLength}]`)
-            .beCloseToArray(
-                expected.slice(0, halfLength), {absoluteThreshold: 0});
-        should(
-            actual.slice(halfLength),
-            `k-rate ${paramName} with input: output[${halfLength}:]`)
-            .beCloseToArray(expected.slice(halfLength), {absoluteThreshold: 0});
-      }
-
-      audit.run();
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/k-rate-panner-connections.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/k-rate-panner-connections.html
index 77b32c2..001cf63 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/k-rate-panner-connections.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioparam-interface/k-rate-panner-connections.html
@@ -136,9 +136,9 @@
         let actual0 = buffer.getChannelData(2);
         let actual1 = buffer.getChannelData(3);
 
-        should(expected0, 'Expected output channel 0')
+        should(expected0, `Panner: ${options.param}: Expected output channel 0`)
             .notBeConstantValueOf(expected0[0]);
-        should(expected1, 'Expected output channel 1')
+        should(expected1, `${options.param}: Expected output channel 1`)
             .notBeConstantValueOf(expected1[0]);
 
         // Verify output is a stair step because positionX is k-rate,
@@ -147,23 +147,23 @@
         for (let k = 0; k < testFrames; k += RENDER_QUANTUM_FRAMES) {
           should(
               actual0.slice(k, k + RENDER_QUANTUM_FRAMES),
-              `Channel 0 output[${k}, ${k + RENDER_QUANTUM_FRAMES - 1}]`)
+              `Panner: ${options.param}: Channel 0 output[${k}, ${
+                  k + RENDER_QUANTUM_FRAMES - 1}]`)
               .beConstantValueOf(actual0[k]);
         }
 
         for (let k = 0; k < testFrames; k += RENDER_QUANTUM_FRAMES) {
           should(
               actual1.slice(k, k + RENDER_QUANTUM_FRAMES),
-              `Channel 1 output[${k}, ${k + RENDER_QUANTUM_FRAMES - 1}]`)
+              `Panner: ${options.param}: Channel 1 output[${k}, ${
+                  k + RENDER_QUANTUM_FRAMES - 1}]`)
               .beConstantValueOf(actual1[k]);
         }
 
-        should(actual0, 'Actual output channel 0').beCloseToArray(expected0, {
-          absoluteThreshold: 0
-        });
-        should(actual1, 'Actual output channel 1').beCloseToArray(expected1, {
-          absoluteThreshold: 0
-        });
+        should(actual0, `Panner: ${options.param}: Actual output channel 0`)
+            .beCloseToArray(expected0, {absoluteThreshold: 0});
+        should(actual1, `Panner: ${options.param}: Actual output channel 1`)
+            .beCloseToArray(expected1, {absoluteThreshold: 0});
       }
 
       async function testListenerParams(should, options) {
@@ -220,14 +220,16 @@
         for (let k = 0; k < testFrames; k += RENDER_QUANTUM_FRAMES) {
           should(
               c0.slice(k, k + RENDER_QUANTUM_FRAMES),
-              `Channel 0 output[${k}, ${k + RENDER_QUANTUM_FRAMES - 1}]`)
+              `Listener: ${options.param}: Channel 0 output[${k}, ${
+                  k + RENDER_QUANTUM_FRAMES - 1}]`)
               .beConstantValueOf(c0[k]);
         }
 
         for (let k = 0; k < testFrames; k += RENDER_QUANTUM_FRAMES) {
           should(
               c1.slice(k, k + RENDER_QUANTUM_FRAMES),
-              `Channel 1 output[${k}, ${k + RENDER_QUANTUM_FRAMES - 1}]`)
+              `Listener: ${options.param}: Channel 1 output[${k}, ${
+                  k + RENDER_QUANTUM_FRAMES - 1}]`)
               .beConstantValueOf(c1[k]);
         }
       }
diff --git a/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-insertable-streams.html b/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-insertable-streams.html
index 9bbb5e5..4100afc 100644
--- a/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-insertable-streams.html
+++ b/third_party/blink/web_tests/fast/peerconnection/RTCPeerConnection-insertable-streams.html
@@ -231,6 +231,60 @@
   return onmessagePromise;
 }, 'RTCRtpSender readable stream transferred to a Worker and the Worker sends an RTCEncodedVideoFrame back');
 
+async function testNormalDataFlowWithInsertableStreamsForOtherKind(t, normalKind) {
+  const flowAudio = (normalKind == 'audio');
+  const pcConfig = flowAudio
+    ? {forceEncodedVideoInsertableStreams:true}
+    : {forceEncodedAudioInsertableStreams:true};
+  const caller = new RTCPeerConnection(pcConfig);
+  t.add_cleanup(() => caller.close());
+  const callee = new RTCPeerConnection(pcConfig);
+  t.add_cleanup(() => callee.close());
+
+  const stream = await navigator.mediaDevices.getUserMedia(
+    {audio: flowAudio, video: !flowAudio});
+  const track = stream.getTracks()[0];
+  t.add_cleanup(() => track.stop());
+
+  const sender = caller.addTrack(track, stream);
+  const ontrackPromise = new Promise((resolve,reject) => {
+    callee.ontrack =  t.step_func(async e => {
+      let numGetStats = 0;
+      const intervalId = window.setInterval(async ()=> {
+        let statsReport = await callee.getStats();
+        statsReport.forEach(report => {
+          if (report.type == 'inbound-rtp' &&
+              report.kind == normalKind &&
+              report.bytesReceived > 0) {
+            clearInterval(intervalId);
+            resolve();
+            return;
+          }
+        });
+        if (++numGetStats >= 20) {
+          clearInterval(intervalId);
+          reject('No bytes received.');
+          return;
+        }
+      }, 50);
+    });
+  });
+
+
+  exchangeIceCandidates(caller, callee);
+  await doSignalingHandshake(caller, callee);
+
+  return ontrackPromise;
+}
+
+promise_test(t => {
+  return testNormalDataFlowWithInsertableStreamsForOtherKind(t, 'audio');
+}, 'Audio flows when insertable streams is enabled for video and disabled for audio.');
+
+promise_test(t => {
+  return testNormalDataFlowWithInsertableStreamsForOtherKind(t, 'video');
+}, 'Video flows when insertable streams is enabled for audio and disabled for audio.');
+
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/fast/scrolling/css-clip-scroll.html b/third_party/blink/web_tests/fast/scrolling/css-clip-scroll.html
new file mode 100644
index 0000000..465be89
--- /dev/null
+++ b/third_party/blink/web_tests/fast/scrolling/css-clip-scroll.html
@@ -0,0 +1,64 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Composited scrolling ignores CSS clip</title>
+    <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1058870">
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src='../../resources/gesture-util.js'></script>
+    <style>
+    .behindscroller {
+      width: 200px;
+      height: 400px;
+      background: lightgreen;
+      position: absolute;
+      top: 50px;
+      left: 0;
+    }
+    .scroller {
+      width: 200px;
+      height: 400px;
+      overflow-y: scroll;
+      clip-path: circle(220px at 0 150px);
+      position: absolute;
+      top: 50px;
+      left: 0;
+    }
+    </style>
+  </head>
+  <body onload="onLoad()">
+    <div id="behindscroller" class="behindscroller"></div>
+    <div id="scroller" class="scroller">
+      <div id="forcescroll" style="height: 1000px; width: 100%; background: linear-gradient(grey, white)"></div>
+    </div>
+    You should not be able to wheel scroll with the mouse cursor in the green area.
+  </body>
+  <script>
+    function onLoad(){
+      var behindscroller= document.getElementById("behindscroller");
+      var behindscrollerRect = behindscroller.getBoundingClientRect();
+
+      if(window.promise_test){
+        promise_test(function(){
+          return new Promise(async function(resolve, reject){
+            const distance = 10;
+            const x = behindscrollerRect.right - 10;
+            const y = behindscrollerRect.top + 5;
+            const input_source = GestureSourceType.MOUSE_INPUT;
+            const direction = "down";
+            const scroll_speed = SPEED_INSTANT;
+
+            await smoothScroll(distance, x, y, input_source, direction,
+              scroll_speed,
+              true /* precise_scrolling_deltas */,
+              false /* scroll_by_page */);
+
+            await conditionHolds( () => {
+              return scroller.scrollTop == 0;
+            }).then(resolve, reject);
+          });
+        }, "No scrolling in clipped out region");
+      }
+    }
+  </script>
+</html>
diff --git a/third_party/blink/web_tests/scrollbars/mock-scrollbars-expected.html b/third_party/blink/web_tests/scrollbars/mock-scrollbars-expected.html
index 22a69582..cf2bde2 100644
--- a/third_party/blink/web_tests/scrollbars/mock-scrollbars-expected.html
+++ b/third_party/blink/web_tests/scrollbars/mock-scrollbars-expected.html
@@ -1,13 +1,14 @@
 <!DOCTYPE html>
-<script>
-  if (window.internals)
-    internals.useMockOverlayScrollbars();
-  onload = ()=> {
-    child.style.display = "block";
-  }
-</script>
 <style>body { overflow:hidden; }</style>
 <p>The scrollable container below should not appear to be scrollable.</p>
 <div id="child" style="display:none; overflow:scroll; width:200px; height:200px;">
   <div style="box-sizing:border-box; border:solid; width:100%; height:100%;"></div>
 </div>
+<script>
+onload = ()=> {
+  if (!window.internals)
+    return;
+  internals.useMockOverlayScrollbars();
+  child.style.display = "block";
+}
+</script>
diff --git a/third_party/blink/web_tests/scrollbars/mock-scrollbars.html b/third_party/blink/web_tests/scrollbars/mock-scrollbars.html
index 14143f1..c472a63 100644
--- a/third_party/blink/web_tests/scrollbars/mock-scrollbars.html
+++ b/third_party/blink/web_tests/scrollbars/mock-scrollbars.html
@@ -1,10 +1,13 @@
 <!DOCTYPE html>
-<script>
-  if (window.internals)
-    internals.useMockOverlayScrollbars();
-</script>
 <style>body { overflow:hidden; }</style>
 <p>The scrollable container below should not appear to be scrollable.</p>
 <div style="overflow:scroll; width:200px; height:200px;">
   <div style="box-sizing:border-box; border:solid; width:100%; height:100%;"></div>
 </div>
+<script>
+onload = ()=> {
+  if (!window.internals)
+    return;
+  internals.useMockOverlayScrollbars();
+}
+</script>
diff --git a/third_party/libavif/BUILD.gn b/third_party/libavif/BUILD.gn
new file mode 100644
index 0000000..07c7cf2
--- /dev/null
+++ b/third_party/libavif/BUILD.gn
@@ -0,0 +1,30 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("libavif") {
+  sources = [
+    "src/include/avif/avif.h",
+    "src/include/avif/internal.h",
+    "src/src/alpha.c",
+    "src/src/avif.c",
+    "src/src/codec_dav1d.c",
+    "src/src/colr.c",
+    "src/src/mem.c",
+    "src/src/rawdata.c",
+    "src/src/read.c",
+    "src/src/reformat.c",
+    "src/src/stream.c",
+    "src/src/utils.c",
+  ]
+
+  # configs -= [ "//build/config/compiler:chromium_code" ]
+  # configs += [ "//build/config/compiler:no_chromium_code" ]
+  include_dirs = [
+    "src/include/",
+    "../dav1d/libdav1d/include/",
+  ]
+  defines = [ "AVIF_CODEC_DAV1D" ]
+
+  deps = [ "//third_party/dav1d" ]
+}
diff --git a/third_party/libavif/LICENSE b/third_party/libavif/LICENSE
new file mode 100644
index 0000000..5b188d7
--- /dev/null
+++ b/third_party/libavif/LICENSE
@@ -0,0 +1,46 @@
+Copyright 2019 Joe Drago. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+------------------------------------------------------------------------------
+
+Files: tests/cJSON.*
+
+Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/third_party/libavif/OWNERS b/third_party/libavif/OWNERS
new file mode 100644
index 0000000..eace771
--- /dev/null
+++ b/third_party/libavif/OWNERS
@@ -0,0 +1,2 @@
+# COMPONENT: Internals>Media>Codecs
+file://media/OWNERS
diff --git a/third_party/libavif/README.chromium b/third_party/libavif/README.chromium
new file mode 100644
index 0000000..1aa95fd7
--- /dev/null
+++ b/third_party/libavif/README.chromium
@@ -0,0 +1,12 @@
+Name: libavif - Library for encoding and decoding .avif files
+Short Name: avif
+URL: https://github.com/AOMediaCodec/libavif
+Version: master
+License: 2-Clause BSD
+License File: LICENSE
+Security Critical: yes
+Source: https://github.com/AOMediaCodec/libavif
+
+--[ DESCRIPTION ] ------------------
+This contains the source to the AV1 image format demuxer; used for demuxing and
+decoding .avif files in Chromium.
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index daa943517..d605ba2 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -6,9 +6,9 @@
 License File: source/libvpx/LICENSE
 Security Critical: yes
 
-Date: Monday April 06 2020
+Date: Tuesday April 07 2020
 Branch: master
-Commit: 1717ac939c12e31a358056a36c2fa7a8882e71ed
+Commit: 8dc6f353c6d04329cf59529f41a6f46d9dbfcafa
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 69d7671..26d0affc 100644
--- a/third_party/libvpx/source/config/vpx_version.h
+++ b/third_party/libvpx/source/config/vpx_version.h
@@ -2,8 +2,8 @@
 #define VERSION_MAJOR 1
 #define VERSION_MINOR 8
 #define VERSION_PATCH 2
-#define VERSION_EXTRA "138-g1717ac939"
+#define VERSION_EXTRA "140-g8dc6f353c"
 #define VERSION_PACKED \
   ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.8.2-138-g1717ac939"
-#define VERSION_STRING " v1.8.2-138-g1717ac939"
+#define VERSION_STRING_NOSP "v1.8.2-140-g8dc6f353c"
+#define VERSION_STRING " v1.8.2-140-g8dc6f353c"
diff --git a/third_party/protobuf/proto_library.gni b/third_party/protobuf/proto_library.gni
index 55bde54..44c7fef 100644
--- a/third_party/protobuf/proto_library.gni
+++ b/third_party/protobuf/proto_library.gni
@@ -116,6 +116,7 @@
 #  }
 
 import("//build/config/sanitizers/sanitizers.gni")
+import("//build/toolchain/kythe.gni")
 
 if (host_os == "win") {
   _host_executable_suffix = ".exe"
@@ -277,6 +278,9 @@
         "--cc-out-dir",
         rel_cc_out_dir,
       ]
+      if (enable_kythe_annotations) {
+        args += [ "--enable-kythe-annotation" ]
+      }
       if (defined(invoker.cc_generator_options)) {
         args += [
           "--cc-options",
diff --git a/third_party/re2/OWNERS b/third_party/re2/OWNERS
index 87658c13..d4c5914a 100644
--- a/third_party/re2/OWNERS
+++ b/third_party/re2/OWNERS
@@ -1,4 +1,3 @@
 mmoroz@chromium.org
-tfarina@chromium.org
 thakis@chromium.org
 # COMPONENT: Internals
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 64041cd..8083f90 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -5873,6 +5873,17 @@
   <int value="4" label="Available unknown LE"/>
 </enum>
 
+<enum name="BluetoothConnectionFailureReason">
+  <int value="0" label="Unknown error"/>
+  <int value="1" label="System or Chrome runtime error"/>
+  <int value="2" label="Authentication failed"/>
+  <int value="3" label="Authentication timed out"/>
+  <int value="4" label="Connection failed"/>
+  <int value="5" label="Unknown connection error"/>
+  <int value="6" label="Unsupported device"/>
+  <int value="7" label="Not connectable"/>
+</enum>
+
 <enum name="BluetoothDiscoveryOutcomes">
   <int value="0" label="Success"/>
   <int value="1"
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 162c65ab..f6ec3a4 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -4951,9 +4951,10 @@
 </histogram>
 
 <histogram name="Android.WebView.SupportLibrary.ClientIsCompat"
-    enum="WebViewClientTypeEnum" expires_after="2020-05-05">
+    enum="WebViewClientTypeEnum" expires_after="2021-05-05">
+  <owner>laisminchillo@chromium.org</owner>
   <owner>ntfschr@chromium.org</owner>
-  <owner>changwan@chromium.org</owner>
+  <owner>src/android_webview/OWNERS</owner>
   <summary>
     Records whether the WebViewClient provided by the app is an instance of
     WebViewClientCompat (and therefore exposes AndroidX callbacks). This is
@@ -20464,6 +20465,22 @@
   </summary>
 </histogram>
 
+<histogram name="Bluetooth.ChromeOS.Pairing.Result.FailureReason"
+    enum="BluetoothConnectionFailureReason" expires_after="2021-03-05">
+<!-- Name completed by histogram_suffixes name="BluetoothTransportTypes" -->
+
+  <owner>hansberry@chromium.org</owner>
+  <owner>cros-system-services-networking@google.com</owner>
+  <summary>
+    Breaks down why a pairing attempt to a peripheral failed (see
+    'Bluetooth.ChromeOS.Pairing.Result').
+
+    Suffixed by Bluetooth transport type. View the base histogram to see results
+    for all transport types aggregated together, and suffixed histograms for the
+    results of just that particular transport type.
+  </summary>
+</histogram>
+
 <histogram name="Bluetooth.ChromeOS.Pairing.TransportType"
     enum="BluetoothTransportType" expires_after="2021-03-05">
   <owner>hansberry@chromium.org</owner>
@@ -20493,6 +20510,23 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result.FailureReason"
+    enum="BluetoothConnectionFailureReason" expires_after="2021-03-05">
+<!-- Name completed by histogram_suffixes name="BluetoothUISurfaces" -->
+
+  <owner>hansberry@chromium.org</owner>
+  <owner>cros-system-services-networking@google.com</owner>
+  <summary>
+    Breaks down why a user-initiated reconnection attempt to a peripheral failed
+    (see 'Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result').
+
+    Suffixed by Bluetooth UI surface. View the base histogram to see results for
+    all UI surfaces aggregated together, and suffixed histograms for the results
+    of just that particular UI surfaces.
+  </summary>
+</histogram>
+
 <histogram name="Bluetooth.ConnectedDeviceCount" units="devices"
     expires_after="2020-09-06">
   <owner>adlr@chromium.org</owner>
@@ -65481,6 +65515,28 @@
   </summary>
 </histogram>
 
+<histogram name="InputMethod.VirtualKeyboard.ResizableWindowInitWidth"
+    units="px" expires_after="2020-08-18">
+  <owner>curtismcmullan@chromium.org</owner>
+  <owner>essential-inputs-team@google.com</owner>
+  <summary>
+    The width of the virtual keyboard window, in pixels, when the floating
+    keyboard is initialized. This is recorded only once on startup, when the
+    virtual keyboard is initialized in floating mode.
+  </summary>
+</histogram>
+
+<histogram name="InputMethod.VirtualKeyboard.ResizableWindowWidth" units="px"
+    expires_after="2020-08-18">
+  <owner>curtismcmullan@chromium.org</owner>
+  <owner>essential-inputs-team@google.com</owner>
+  <summary>
+    The width of the virtual keyboard window, in pixels, after a user has
+    completed resizing the virtual keyboard. This is recorded when the user
+    lifts their finger at the end of a drag that initiates a resize.
+  </summary>
+</histogram>
+
 <histogram name="InputMethod.VirtualKeyboard.SwitchMode" enum="IMEVKMode"
     expires_after="2020-06-30">
   <owner>essential-inputs-team@google.com</owner>
@@ -125554,7 +125610,11 @@
   </summary>
 </histogram>
 
-<histogram name="Prefetch.Redirect" enum="PrefetchRedirect" expires_after="M83">
+<histogram name="Prefetch.Redirect" enum="PrefetchRedirect"
+    expires_after="2020-03-31">
+  <obsolete>
+    Removed March 31 2020.
+  </obsolete>
   <owner>dom@chromium.org</owner>
   <owner>yhirano@chromium.org</owner>
   <owner>yoavweiss@chromium.org</owner>
@@ -185571,6 +185631,7 @@
   <affected-histogram name="Bluetooth.ChromeOS.Pairing.Duration.Failure"/>
   <affected-histogram name="Bluetooth.ChromeOS.Pairing.Duration.Success"/>
   <affected-histogram name="Bluetooth.ChromeOS.Pairing.Result"/>
+  <affected-histogram name="Bluetooth.ChromeOS.Pairing.Result.FailureReason"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="BluetoothUISurfaces" separator=".">
@@ -185579,6 +185640,8 @@
   <affected-histogram name="Bluetooth.ChromeOS.DeviceSelectionDuration"/>
   <affected-histogram
       name="Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result"/>
+  <affected-histogram
+      name="Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result.FailureReason"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="BrowserRunningMode" separator=".">
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 3a0f50c..8478306 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -96,115 +96,119 @@
 LIGHTWEIGHT_TESTERS = ['linux-perf-fyi']
 
 FYI_BUILDERS = {
-  'android-nexus5x-perf-fyi': {
-    'tests': [
-      {
-        'isolate': 'performance_test_suite',
-        'extra_args': [
-          '--output-format=histograms',
-          '--experimental-tbmv3-metrics',
+    'android-nexus5x-perf-fyi': {
+        'tests': [{
+            'isolate':
+            'performance_test_suite',
+            'extra_args': [
+                '--output-format=histograms',
+                '--experimental-tbmv3-metrics',
+            ],
+        }],
+        'platform':
+        'android-chrome',
+        'dimension': {
+            'pool': 'chrome.tests.perf-fyi',
+            'os': 'Android',
+            'device_type': 'bullhead',
+            'device_os': 'MMB29Q',
+            'device_os_flavor': 'google',
+        },
+    },
+    'android-pixel2-perf-fyi': {
+        'tests': [{
+            'isolate': 'performance_test_suite',
+        }],
+        'platform': 'android-chrome',
+        'browser': 'bin/monochrome_64_32_bundle',
+        'dimension': {
+            'pool': 'chrome.tests.perf-fyi',
+            'os': 'Android',
+            'device_type': 'walleye',
+            'device_os': 'O',
+            'device_os_flavor': 'google',
+        },
+    },
+    'android-pixel2-perf-aab-fyi': {
+        'tests': [{
+            'isolate': 'performance_test_suite',
+            'extra_args': [
+                '--run-ref-build',
+            ],
+        }],
+        'platform':
+        'android-chrome-bundle',
+        'dimension': {
+            'pool': 'chrome.tests.perf-fyi',
+            'os': 'Android',
+            'device_type': 'walleye',
+            'device_os': 'O',
+            'device_os_flavor': 'google',
+        },
+    },
+    'linux-perf-fyi': {
+        'tests': [{
+            'isolate':
+            'performance_test_suite',
+            'extra_args': [
+                '--output-format=histograms',
+                '--experimental-tbmv3-metrics',
+            ],
+        }],
+        'platform':
+        'linux',
+        'dimension': {
+            'gpu': '10de',
+            'id': 'build186-b7',
+            'os': 'Ubuntu-14.04',
+            'pool': 'chrome.tests.perf-fyi',
+        },
+    },
+    'win-10_laptop_low_end-perf_HP-Candidate': {
+        'tests': [
+            {
+                'isolate': 'performance_test_suite',
+            },
         ],
-      }
-    ],
-    'platform': 'android-chrome',
-    'dimension': {
-      'pool': 'chrome.tests.perf-fyi',
-      'os': 'Android',
-      'device_type': 'bullhead',
-      'device_os': 'MMB29Q',
-      'device_os_flavor': 'google',
+        'platform': 'win',
+        'target_bits': 64,
+        'dimension': {
+            'pool': 'chrome.tests.perf-fyi',
+            'id': 'build370-a7',
+            # TODO(crbug.com/971204): Explicitly set the gpu to None to make
+            # chromium_swarming recipe_module ignore this dimension.
+            'gpu': None,
+            'os': 'Windows-10',
+        },
     },
-  },
-  'android-pixel2-perf-fyi': {
-    'tests': [
-      {
-        'isolate': 'performance_test_suite',
-      }
-    ],
-    'platform': 'android-chrome',
-    'browser': 'bin/monochrome_64_32_bundle',
-    'dimension': {
-      'pool': 'chrome.tests.perf-fyi',
-      'os': 'Android',
-      'device_type': 'walleye',
-      'device_os': 'O',
-      'device_os_flavor': 'google',
-    },
-  },
-  'android-pixel2-perf-aab-fyi': {
-    'tests': [
-      {
-        'isolate': 'performance_test_suite',
-        'extra_args': [
-           '--run-ref-build',
+    'chromeos-kevin-perf-fyi': {
+        'tests': [
+            {
+                'isolate':
+                'performance_test_suite',
+                'extra_args': [
+                    # The magic hostname that resolves to a CrOS device in the test lab
+                    '--remote=variable_chromeos_device_hostname',
+                ],
+            },
         ],
-      }
-    ],
-    'platform': 'android-chrome-bundle',
-    'dimension': {
-      'pool': 'chrome.tests.perf-fyi',
-      'os': 'Android',
-      'device_type': 'walleye',
-      'device_os': 'O',
-      'device_os_flavor': 'google',
+        'platform':
+        'chromeos',
+        'target_bits':
+        32,
+        'dimension': {
+            'pool': 'luci.chrome.cros-dut',
+            # TODO(crbug.com/971204): Explicitly set the gpu to None to make
+            # chromium_swarming recipe_module ignore this dimension.
+            'gpu': None,
+            'os': 'ChromeOS',
+            'device_type': 'kevin',
+        },
     },
-  },
-  'linux-perf-fyi': {
-    'tests': [
-      {
-        'isolate': 'performance_test_suite',
-        'extra_args': [
-            '--output-format=histograms',
-            '--experimental-tbmv3-metrics',
-        ],
-      }
-    ],
-    'platform': 'linux',
-    'dimension': {
-      'gpu': '10de',
-      'id': 'build186-b7',
-      'os': 'Ubuntu-14.04',
-      'pool': 'chrome.tests.perf-fyi',
+    'linux-processor-perf-fyi': {
+        'platform': 'linux',
+        'perf_processor': True,
     },
-  },
-  'win-10_laptop_low_end-perf_HP-Candidate': {
-    'tests': [
-      {
-        'isolate': 'performance_test_suite',
-      },
-    ],
-    'platform': 'win',
-    'target_bits': 64,
-    'dimension': {
-      'pool': 'chrome.tests.perf-fyi',
-      'id': 'build370-a7',
-      # TODO(crbug.com/971204): Explicitly set the gpu to None to make
-      # chromium_swarming recipe_module ignore this dimension.
-      'gpu': None,
-      'os': 'Windows-10',
-    },
-  },
-  'chromeos-kevin-perf-fyi': {
-    'tests': [
-      {
-        'isolate': 'performance_test_suite',
-        'extra_args': [
-            # The magic hostname that resolves to a CrOS device in the test lab
-            '--remote=variable_chromeos_device_hostname',
-        ],
-      },
-    ],
-    'platform': 'chromeos',
-    'target_bits': 32,
-    'dimension': {
-      'pool': 'luci.chrome.cros-dut',
-      # TODO(crbug.com/971204): Explicitly set the gpu to None to make
-      # chromium_swarming recipe_module ignore this dimension.
-      'gpu': None,
-      'os': 'ChromeOS',
-      'device_type': 'kevin',
-    },
-  },
 }
 
 # These configurations are taken from chromium_perf.py in
@@ -1039,7 +1043,7 @@
       'script': '//tools/perf/process_perf_results.py',
   }
   if builder_name in LIGHTWEIGHT_TESTERS:
-    result['merge']['args'] = ['--skip-perf']
+    result['merge']['args'] = ['--lightweight', '--skip-perf']
 
   result['swarming'] = {
       # Always say this is true regardless of whether the tester
@@ -1074,6 +1078,11 @@
   if 'additional_compile_targets' in condensed_config:
     config['additional_compile_targets'] = (
         condensed_config['additional_compile_targets'])
+  if 'perf_processor' in condensed_config:
+    config['merge'] = {
+        'script': '//tools/perf/process_perf_results.py',
+    }
+    config['merge']['args'] = ['--lightweight']
 
   condensed_tests = condensed_config.get('tests')
   if condensed_tests:
diff --git a/tools/protoc_wrapper/protoc_wrapper.py b/tools/protoc_wrapper/protoc_wrapper.py
index d6e127f..4bb3f06 100755
--- a/tools/protoc_wrapper/protoc_wrapper.py
+++ b/tools/protoc_wrapper/protoc_wrapper.py
@@ -69,10 +69,10 @@
 
 def main(argv):
   parser = argparse.ArgumentParser()
-  parser.add_argument("--protoc",
+  parser.add_argument("--protoc", required=True,
                       help="Relative path to compiler.")
 
-  parser.add_argument("--proto-in-dir",
+  parser.add_argument("--proto-in-dir", required=True,
                       help="Base directory with source protos.")
   parser.add_argument("--cc-out-dir",
                       help="Output directory for standard C++ generator.")
@@ -81,6 +81,9 @@
   parser.add_argument("--plugin-out-dir",
                       help="Output directory for custom generator plugin.")
 
+  parser.add_argument('--enable-kythe-annotations', action='store_true',
+                      help='Enable generation of Kythe kzip, used for '
+                      'codesearch.')
   parser.add_argument("--plugin",
                       help="Relative path to custom generator plugin.")
   parser.add_argument("--plugin-options",
@@ -95,7 +98,7 @@
   parser.add_argument("protos", nargs="+",
                       help="Input protobuf definition file(s).")
 
-  options = parser.parse_args()
+  options = parser.parse_args(argv)
 
   proto_dir = os.path.relpath(options.proto_in_dir)
   protoc_cmd = [os.path.realpath(options.protoc)]
@@ -109,7 +112,19 @@
 
   if options.cc_out_dir:
     cc_out_dir = options.cc_out_dir
-    cc_options = FormatGeneratorOptions(options.cc_options)
+    cc_options_list = []
+    if options.enable_kythe_annotations:
+      cc_options_list.extend([
+          'annotate_headers', 'annotation_pragma_name=kythe_metadata',
+          'annotation_guard_name=KYTHE_IS_RUNNING'
+      ])
+
+    # cc_options will likely have trailing colon so needs to be inserted at the
+    # end.
+    if options.cc_options:
+      cc_options_list.append(options.cc_options)
+
+    cc_options = FormatGeneratorOptions(','.join(cc_options_list))
     protoc_cmd += ["--cpp_out", cc_options + cc_out_dir]
     for filename in protos:
       stripped_name = StripProtoExtension(filename)
@@ -146,7 +161,7 @@
 
 if __name__ == "__main__":
   try:
-    main(sys.argv)
+    main(sys.argv[1:])
   except RuntimeError as e:
     print(e, file=sys.stderr)
     sys.exit(1)
diff --git a/tools/protoc_wrapper/protoc_wrapper_test.py b/tools/protoc_wrapper/protoc_wrapper_test.py
new file mode 100755
index 0000000..ef89a95
--- /dev/null
+++ b/tools/protoc_wrapper/protoc_wrapper_test.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Tests for protoc_wrapper."""
+
+from __future__ import print_function
+
+import logging
+import sys
+import unittest
+
+if sys.version_info.major == 2:
+  from StringIO import StringIO
+  import mock
+else:
+  from io import StringIO
+  from unittest import mock
+
+import protoc_wrapper
+
+
+class ProtocWrapperTest(unittest.TestCase):
+  @mock.patch('subprocess.call', return_value=0)
+  def test_minimal_arguments(self, mock_call):
+    protoc_wrapper.main(
+        ['--proto-in-dir', './', '--protoc', '/foo/protoc', 'foo.proto'])
+    mock_call.assert_called_once_with(
+        ['/foo/protoc', '--proto_path', '.', './foo.proto'])
+
+  @mock.patch('subprocess.call', return_value=0)
+  def test_kythe_no_out(self, mock_call):
+    protoc_wrapper.main([
+        '--proto-in-dir', './', '--enable-kythe-annotation', '--protoc',
+        '/foo/protoc', 'foo.proto'
+    ])
+    mock_call.assert_called_once_with(
+        ['/foo/protoc', '--proto_path', '.', './foo.proto'])
+
+  @mock.patch('subprocess.call', return_value=0)
+  def test_kythe_cpp_out_no_options(self, mock_call):
+    protoc_wrapper.main([
+        '--proto-in-dir', './', '--enable-kythe-annotation', '--cc-out-dir',
+        './bar', '--protoc', '/foo/protoc', 'foo.proto'
+    ])
+    mock_call.assert_called_once_with([
+        '/foo/protoc', '--cpp_out',
+        'annotate_headers,annotation_pragma_name=kythe_metadata,annotation_guard_name=KYTHE_IS_RUNNING:./bar',
+        '--proto_path', '.', './foo.proto'
+    ])
+
+  @mock.patch('subprocess.call', return_value=0)
+  def test_kythe_cpp_out_with_options(self, mock_call):
+    protoc_wrapper.main([
+        '--proto-in-dir', './', '--enable-kythe-annotation', '--cc-options',
+        'foo=bar:', '--cc-out-dir', './bar', '--protoc', '/foo/protoc',
+        'foo.proto'
+    ])
+    mock_call.assert_called_once_with([
+        '/foo/protoc', '--cpp_out',
+        'annotate_headers,annotation_pragma_name=kythe_metadata,annotation_guard_name=KYTHE_IS_RUNNING,foo=bar:./bar',
+        '--proto_path', '.', './foo.proto'
+    ])
+
+  @mock.patch('subprocess.call', return_value=0)
+  def test_kythe_cpp_out_with_options_no_colon(self, mock_call):
+    protoc_wrapper.main([
+        '--proto-in-dir', './', '--enable-kythe-annotation', '--cc-options',
+        'foo=bar', '--cc-out-dir', './bar', '--protoc', '/foo/protoc',
+        'foo.proto'
+    ])
+    mock_call.assert_called_once_with([
+        '/foo/protoc', '--cpp_out',
+        'annotate_headers,annotation_pragma_name=kythe_metadata,annotation_guard_name=KYTHE_IS_RUNNING,foo=bar:./bar',
+        '--proto_path', '.', './foo.proto'
+    ])
+
+  @mock.patch('subprocess.call', return_value=0)
+  def test_cpp_out_with_options_no_colon(self, mock_call):
+    protoc_wrapper.main([
+        '--proto-in-dir', './', '--cc-options', 'foo=bar:', '--cc-out-dir',
+        './bar', '--protoc', '/foo/protoc', 'foo.proto'
+    ])
+    mock_call.assert_called_once_with([
+        '/foo/protoc', '--cpp_out', 'foo=bar:./bar', '--proto_path', '.',
+        './foo.proto'
+    ])
+
+
+if __name__ == '__main__':
+  logging.basicConfig(
+      level=logging.DEBUG if '-v' in sys.argv else logging.ERROR)
+  unittest.main()
diff --git a/ui/accessibility/platform/ax_system_caret_win.cc b/ui/accessibility/platform/ax_system_caret_win.cc
index e6b8c3c7..c2a996e3 100644
--- a/ui/accessibility/platform/ax_system_caret_win.cc
+++ b/ui/accessibility/platform/ax_system_caret_win.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/platform/ax_platform_node_win.h"
+#include "ui/display/win/screen_win.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/rect_f.h"
 
@@ -52,8 +53,8 @@
   return caret_accessible;
 }
 
-void AXSystemCaretWin::MoveCaretTo(const gfx::Rect& bounds) {
-  if (bounds.IsEmpty())
+void AXSystemCaretWin::MoveCaretTo(const gfx::Rect& bounds_physical_pixels) {
+  if (bounds_physical_pixels.IsEmpty())
     return;
 
   // If the caret has non-empty bounds, assume it has been made visible.
@@ -71,7 +72,7 @@
                      -caret_->GetUniqueId());
   }
 
-  gfx::RectF new_location(bounds);
+  gfx::RectF new_location(bounds_physical_pixels);
   // Avoid redundant caret move events (if the location stays the same), but
   // always fire when it's made visible again.
   if (data_.relative_bounds.bounds != new_location || newly_visible) {
@@ -114,10 +115,12 @@
     const AXClippingBehavior clipping_behavior,
     AXOffscreenResult* offscreen_result) const {
   switch (coordinate_system) {
-    case AXCoordinateSystem::kScreenDIPs:
+    case AXCoordinateSystem::kScreenPhysicalPixels:
       // We could optionally add clipping here if ever needed.
       return ToEnclosingRect(data_.relative_bounds.bounds);
-    case AXCoordinateSystem::kScreenPhysicalPixels:
+    case AXCoordinateSystem::kScreenDIPs:
+      return display::win::ScreenWin::ScreenToDIPRect(
+          event_target_, ToEnclosingRect(data_.relative_bounds.bounds));
     case AXCoordinateSystem::kRootFrame:
     case AXCoordinateSystem::kFrame:
       NOTIMPLEMENTED();
diff --git a/ui/accessibility/platform/ax_system_caret_win.h b/ui/accessibility/platform/ax_system_caret_win.h
index 0d017c6..a0d1b51 100644
--- a/ui/accessibility/platform/ax_system_caret_win.h
+++ b/ui/accessibility/platform/ax_system_caret_win.h
@@ -30,7 +30,7 @@
   ~AXSystemCaretWin() override;
 
   Microsoft::WRL::ComPtr<IAccessible> GetCaret() const;
-  void MoveCaretTo(const gfx::Rect& bounds);
+  void MoveCaretTo(const gfx::Rect& bounds_physical_pixels);
   void Hide();
 
  private:
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index dee8e22de..2039dbe5 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -121,61 +121,10 @@
 
 java_strings_grd("ui_strings_grd") {
   grd_file = "java/strings/android_ui_strings.grd"
-  outputs = [
-    "values/android_ui_strings.xml",
-    "values-am/android_ui_strings.xml",
-    "values-ar/android_ui_strings.xml",
-    "values-bg/android_ui_strings.xml",
-    "values-bn/android_ui_strings.xml",
-    "values-ca/android_ui_strings.xml",
-    "values-cs/android_ui_strings.xml",
-    "values-da/android_ui_strings.xml",
-    "values-de/android_ui_strings.xml",
-    "values-el/android_ui_strings.xml",
-    "values-en-rGB/android_ui_strings.xml",
-    "values-es/android_ui_strings.xml",
-    "values-es-rUS/android_ui_strings.xml",
-    "values-et/android_ui_strings.xml",
-    "values-fa/android_ui_strings.xml",
-    "values-fi/android_ui_strings.xml",
-    "values-fr/android_ui_strings.xml",
-    "values-gu/android_ui_strings.xml",
-    "values-hi/android_ui_strings.xml",
-    "values-hr/android_ui_strings.xml",
-    "values-hu/android_ui_strings.xml",
-    "values-in/android_ui_strings.xml",
-    "values-it/android_ui_strings.xml",
-    "values-iw/android_ui_strings.xml",
-    "values-ja/android_ui_strings.xml",
-    "values-kn/android_ui_strings.xml",
-    "values-ko/android_ui_strings.xml",
-    "values-lt/android_ui_strings.xml",
-    "values-lv/android_ui_strings.xml",
-    "values-ml/android_ui_strings.xml",
-    "values-mr/android_ui_strings.xml",
-    "values-ms/android_ui_strings.xml",
-    "values-nb/android_ui_strings.xml",
-    "values-nl/android_ui_strings.xml",
-    "values-pl/android_ui_strings.xml",
-    "values-pt-rBR/android_ui_strings.xml",
-    "values-pt-rPT/android_ui_strings.xml",
-    "values-ro/android_ui_strings.xml",
-    "values-ru/android_ui_strings.xml",
-    "values-sk/android_ui_strings.xml",
-    "values-sl/android_ui_strings.xml",
-    "values-sr/android_ui_strings.xml",
-    "values-sv/android_ui_strings.xml",
-    "values-sw/android_ui_strings.xml",
-    "values-ta/android_ui_strings.xml",
-    "values-te/android_ui_strings.xml",
-    "values-th/android_ui_strings.xml",
-    "values-tl/android_ui_strings.xml",
-    "values-tr/android_ui_strings.xml",
-    "values-uk/android_ui_strings.xml",
-    "values-vi/android_ui_strings.xml",
-    "values-zh-rCN/android_ui_strings.xml",
-    "values-zh-rTW/android_ui_strings.xml",
-  ]
+  outputs = [ "values/android_ui_strings.xml" ] +
+            process_file_template(
+                android_bundle_locales_as_resources,
+                [ "values-{{source_name_part}}/android_ui_strings.xml" ])
 }
 
 android_resources("ui_java_resources") {
diff --git a/ui/android/java/strings/android_ui_strings.grd b/ui/android/java/strings/android_ui_strings.grd
index 591feab..a8ca321 100644
--- a/ui/android/java/strings/android_ui_strings.grd
+++ b/ui/android/java/strings/android_ui_strings.grd
@@ -1,10 +1,15 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
   <outputs>
+    <output filename="values-af/android_ui_strings.xml" lang="af" type="android" />
     <output filename="values-am/android_ui_strings.xml" lang="am" type="android" />
     <output filename="values-ar/android_ui_strings.xml" lang="ar" type="android" />
+    <output filename="values-as/android_ui_strings.xml" lang="as" type="android" />
+    <output filename="values-az/android_ui_strings.xml" lang="az" type="android" />
+    <output filename="values-be/android_ui_strings.xml" lang="be" type="android" />
     <output filename="values-bg/android_ui_strings.xml" lang="bg" type="android" />
     <output filename="values-bn/android_ui_strings.xml" lang="bn" type="android" />
+    <output filename="values-bs/android_ui_strings.xml" lang="bs" type="android" />
     <output filename="values-ca/android_ui_strings.xml" lang="ca" type="android" />
     <output filename="values-cs/android_ui_strings.xml" lang="cs" type="android" />
     <output filename="values-da/android_ui_strings.xml" lang="da" type="android" />
@@ -15,34 +20,52 @@
     <output filename="values-es/android_ui_strings.xml" lang="es" type="android" />
     <output filename="values-es-rUS/android_ui_strings.xml" lang="es-419" type="android" />
     <output filename="values-et/android_ui_strings.xml" lang="et" type="android" />
+    <output filename="values-eu/android_ui_strings.xml" lang="eu" type="android" />
     <output filename="values-fa/android_ui_strings.xml" lang="fa" type="android" />
     <output filename="values-fi/android_ui_strings.xml" lang="fi" type="android" />
     <output filename="values-tl/android_ui_strings.xml" lang="fil" type="android" />
     <output filename="values-fr/android_ui_strings.xml" lang="fr" type="android" />
+    <output filename="values-fr-rCA/android_ui_strings.xml" lang="fr-CA" type="android" />
+    <output filename="values-gl/android_ui_strings.xml" lang="gl" type="android" />
     <output filename="values-gu/android_ui_strings.xml" lang="gu" type="android" />
     <output filename="values-hi/android_ui_strings.xml" lang="hi" type="android" />
     <output filename="values-hr/android_ui_strings.xml" lang="hr" type="android" />
     <output filename="values-hu/android_ui_strings.xml" lang="hu" type="android" />
+    <output filename="values-hy/android_ui_strings.xml" lang="hy" type="android" />
     <output filename="values-in/android_ui_strings.xml" lang="id" type="android" />
+    <output filename="values-is/android_ui_strings.xml" lang="is" type="android" />
     <output filename="values-it/android_ui_strings.xml" lang="it" type="android" />
     <output filename="values-iw/android_ui_strings.xml" lang="iw" type="android" />
     <output filename="values-ja/android_ui_strings.xml" lang="ja" type="android" />
+    <output filename="values-ka/android_ui_strings.xml" lang="ka" type="android" />
+    <output filename="values-kk/android_ui_strings.xml" lang="kk" type="android" />
+    <output filename="values-km/android_ui_strings.xml" lang="km" type="android" />
     <output filename="values-kn/android_ui_strings.xml" lang="kn" type="android" />
     <output filename="values-ko/android_ui_strings.xml" lang="ko" type="android" />
+    <output filename="values-ky/android_ui_strings.xml" lang="ky" type="android" />
+    <output filename="values-lo/android_ui_strings.xml" lang="lo" type="android" />
     <output filename="values-lt/android_ui_strings.xml" lang="lt" type="android" />
     <output filename="values-lv/android_ui_strings.xml" lang="lv" type="android" />
+    <output filename="values-mk/android_ui_strings.xml" lang="mk" type="android" />
     <output filename="values-ml/android_ui_strings.xml" lang="ml" type="android" />
+    <output filename="values-mn/android_ui_strings.xml" lang="mn" type="android" />
     <output filename="values-mr/android_ui_strings.xml" lang="mr" type="android" />
     <output filename="values-ms/android_ui_strings.xml" lang="ms" type="android" />
+    <output filename="values-my/android_ui_strings.xml" lang="my" type="android" />
+    <output filename="values-ne/android_ui_strings.xml" lang="ne" type="android" />
     <output filename="values-nl/android_ui_strings.xml" lang="nl" type="android" />
     <output filename="values-nb/android_ui_strings.xml" lang="no" type="android" />
+    <output filename="values-or/android_ui_strings.xml" lang="or" type="android" />
+    <output filename="values-pa/android_ui_strings.xml" lang="pa" type="android" />
     <output filename="values-pl/android_ui_strings.xml" lang="pl" type="android" />
     <output filename="values-pt-rBR/android_ui_strings.xml" lang="pt-BR" type="android" />
     <output filename="values-pt-rPT/android_ui_strings.xml" lang="pt-PT" type="android" />
     <output filename="values-ro/android_ui_strings.xml" lang="ro" type="android" />
     <output filename="values-ru/android_ui_strings.xml" lang="ru" type="android" />
+    <output filename="values-si/android_ui_strings.xml" lang="si" type="android" />
     <output filename="values-sk/android_ui_strings.xml" lang="sk" type="android" />
     <output filename="values-sl/android_ui_strings.xml" lang="sl" type="android" />
+    <output filename="values-sq/android_ui_strings.xml" lang="sq" type="android" />
     <output filename="values-sr/android_ui_strings.xml" lang="sr" type="android" />
     <output filename="values-sv/android_ui_strings.xml" lang="sv" type="android" />
     <output filename="values-sw/android_ui_strings.xml" lang="sw" type="android" />
@@ -51,9 +74,13 @@
     <output filename="values-th/android_ui_strings.xml" lang="th" type="android" />
     <output filename="values-tr/android_ui_strings.xml" lang="tr" type="android" />
     <output filename="values-uk/android_ui_strings.xml" lang="uk" type="android" />
+    <output filename="values-ur/android_ui_strings.xml" lang="ur" type="android" />
+    <output filename="values-uz/android_ui_strings.xml" lang="uz" type="android" />
     <output filename="values-vi/android_ui_strings.xml" lang="vi" type="android" />
     <output filename="values-zh-rCN/android_ui_strings.xml" lang="zh-CN" type="android" />
+    <output filename="values-zh-rHK/android_ui_strings.xml" lang="zh-HK" type="android" />
     <output filename="values-zh-rTW/android_ui_strings.xml" lang="zh-TW" type="android" />
+    <output filename="values-zu/android_ui_strings.xml" lang="zu" type="android" />
   </outputs>
   <translations>
     <file lang="af" path="translations/android_ui_strings_af.xtb" />
diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc
index f21fee3..70cae720 100644
--- a/ui/base/l10n/l10n_util.cc
+++ b/ui/base/l10n/l10n_util.cc
@@ -888,12 +888,6 @@
   }
 }
 
-void GetAcceptLanguages(std::vector<std::string>* locale_codes) {
-  for (const char* accept_language : kAcceptLanguageList) {
-    locale_codes->push_back(accept_language);
-  }
-}
-
 bool IsLanguageAccepted(const std::string& display_locale,
                         const std::string& locale) {
   for (const char* accept_language : kAcceptLanguageList) {
diff --git a/ui/base/l10n/l10n_util.h b/ui/base/l10n/l10n_util.h
index 21de1482..a371dc42 100644
--- a/ui/base/l10n/l10n_util.h
+++ b/ui/base/l10n/l10n_util.h
@@ -212,9 +212,6 @@
     const std::string& display_locale,
     std::vector<std::string>* locale_codes);
 
-// Returns a vector of untranslated locale codes usable for accept-languages.
-UI_BASE_EXPORT void GetAcceptLanguages(std::vector<std::string>* locale_codes);
-
 // Returns true if |locale| is in a predefined AcceptLanguageList and
 // a display name for the |locale| is available in the locale |display_locale|.
 UI_BASE_EXPORT bool IsLanguageAccepted(const std::string& display_locale,
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index aa8eacc..73a00e8 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -265,9 +265,7 @@
      * @return {boolean}
      */
     get showingViewsLogin() {
-      return loadTimeData.valueExists('showViewsLogin') &&
-          loadTimeData.getString('showViewsLogin') == 'on' &&
-          (this.displayType_ == DISPLAY_TYPE.GAIA_SIGNIN);
+      return this.displayType_ == DISPLAY_TYPE.GAIA_SIGNIN;
     },
 
     /**
diff --git a/ui/native_theme/common_theme.cc b/ui/native_theme/common_theme.cc
index ea31f22..715883a 100644
--- a/ui/native_theme/common_theme.cc
+++ b/ui/native_theme/common_theme.cc
@@ -185,6 +185,9 @@
     case NativeTheme::kColorId_BubbleBorder:
       return gfx::kGoogleGrey800;
 
+    case NativeTheme::kColorId_FootnoteContainerBorder:
+      return gfx::kGoogleGrey900;
+
     // Alert icon colors
     case NativeTheme::kColorId_AlertSeverityLow:
       return gfx::kGoogleGreen300;
@@ -516,6 +519,9 @@
     case NativeTheme::kColorId_AlertSeverityHigh:
       return gfx::kGoogleRed600;
 
+    case NativeTheme::kColorId_FootnoteContainerBorder:
+      return gfx::kGoogleGrey200;
+
     case NativeTheme::kColorId_DefaultIconColor:
       return gfx::kGoogleGrey700;
 
diff --git a/ui/native_theme/native_theme_color_id.h b/ui/native_theme/native_theme_color_id.h
index 7e63aefa..2cbd3819 100644
--- a/ui/native_theme/native_theme_color_id.h
+++ b/ui/native_theme/native_theme_color_id.h
@@ -137,6 +137,8 @@
   OP(kColorId_ThrobberLightColor),                                             \
   /* Colors for Bubble Border */                                               \
   OP(kColorId_BubbleBorder),                                                   \
+  /* Colors for Footnote Container. */                                         \
+  OP(kColorId_FootnoteContainerBorder),                                        \
   /* Colors for icons that alert, e.g. upgrade reminders. */                   \
   OP(kColorId_AlertSeverityLow),                                               \
   OP(kColorId_AlertSeverityMedium),                                            \
diff --git a/ui/views/bubble/footnote_container_view.cc b/ui/views/bubble/footnote_container_view.cc
index 68c08db..1478fc8 100644
--- a/ui/views/bubble/footnote_container_view.cc
+++ b/ui/views/bubble/footnote_container_view.cc
@@ -57,7 +57,6 @@
   SetLayoutManager(std::make_unique<BoxLayout>(
       BoxLayout::Orientation::kVertical, margins, 0));
   SetCornerRadius(corner_radius);
-  ResetBorder();
   auto* child_view_ptr = AddChildView(std::move(child_view));
   SetVisible(child_view_ptr->GetVisible());
 }
@@ -88,10 +87,9 @@
 }
 
 void FootnoteContainerView::ResetBorder() {
-  SetBorder(CreateSolidSidedBorder(1, 0, 0, 0,
-                                   GetNativeTheme()->ShouldUseDarkColors()
-                                       ? gfx::kGoogleGrey900
-                                       : gfx::kGoogleGrey200));
+  SetBorder(CreateSolidSidedBorder(
+      1, 0, 0, 0, GetNativeTheme()->GetSystemColor(
+                ui::NativeTheme::kColorId_FootnoteContainerBorder)));
 }
 
 BEGIN_METADATA(FootnoteContainerView)
diff --git a/ui/views/controls/link.cc b/ui/views/controls/link.cc
index 5c292fc21..9a1b75c 100644
--- a/ui/views/controls/link.cc
+++ b/ui/views/controls/link.cc
@@ -22,9 +22,6 @@
 
 namespace views {
 
-// static
-constexpr gfx::Insets Link::kFocusBorderPadding;
-
 Link::Link(const base::string16& title, int text_context, int text_style)
     : Label(title, text_context, text_style) {
   RecalculateFont();
@@ -39,12 +36,6 @@
 
 Link::~Link() = default;
 
-Link::FocusStyle Link::GetFocusStyle() const {
-  // Use an underline to indicate focus unless the link is always drawn with an
-  // underline.
-  return underline_ ? FocusStyle::kRing : FocusStyle::kUnderline;
-}
-
 SkColor Link::GetColor() const {
   // TODO(tapted): Use style::GetColor().
   const ui::NativeTheme* theme = GetNativeTheme();
@@ -60,25 +51,6 @@
                : ui::NativeTheme::kColorId_LinkEnabled);
 }
 
-void Link::PaintFocusRing(gfx::Canvas* canvas) const {
-  if (GetFocusStyle() == FocusStyle::kRing) {
-    gfx::Rect focus_ring_bounds = GetTextBounds();
-    focus_ring_bounds.Inset(-kFocusBorderPadding);
-    focus_ring_bounds.Intersect(GetLocalBounds());
-    canvas->DrawFocusRect(focus_ring_bounds);
-  }
-}
-
-gfx::Insets Link::GetInsets() const {
-  gfx::Insets insets = Label::GetInsets();
-  if (GetFocusStyle() == FocusStyle::kRing &&
-      GetFocusBehavior() != FocusBehavior::NEVER) {
-    DCHECK(!GetText().empty());
-    insets += kFocusBorderPadding;
-  }
-  return insets;
-}
-
 gfx::NativeCursor Link::GetCursor(const ui::MouseEvent& event) {
   if (!GetEnabled())
     return gfx::kNullCursor;
@@ -214,18 +186,6 @@
   return false;
 }
 
-bool Link::GetUnderline() const {
-  return underline_;
-}
-
-void Link::SetUnderline(bool underline) {
-  if (underline_ == underline)
-    return;
-  underline_ = underline;
-  RecalculateFont();
-  OnPropertyChanged(&underline_, kPropertyEffectsPreferredSizeChanged);
-}
-
 void Link::SetPressed(bool pressed) {
   if (pressed_ != pressed) {
     pressed_ = pressed;
@@ -236,12 +196,8 @@
 }
 
 void Link::RecalculateFont() {
-  // Underline the link if it is enabled and |underline_| is true. Also
-  // underline to indicate focus when that's the style.
   const int style = font_list().GetFontStyle();
-  const bool underline =
-      underline_ || (HasFocus() && GetFocusStyle() == FocusStyle::kUnderline);
-  const int intended_style = (GetEnabled() && underline)
+  const int intended_style = (GetEnabled() && HasFocus())
                                  ? (style | gfx::Font::UNDERLINE)
                                  : (style & ~gfx::Font::UNDERLINE);
 
@@ -262,15 +218,9 @@
   }
 }
 
-DEFINE_ENUM_CONVERTERS(Link::FocusStyle,
-                       {Link::FocusStyle::kUnderline,
-                        base::ASCIIToUTF16("UNDERLINE")},
-                       {Link::FocusStyle::kRing, base::ASCIIToUTF16("RING")})
 BEGIN_METADATA(Link)
 METADATA_PARENT_CLASS(Label)
 ADD_READONLY_PROPERTY_METADATA(Link, SkColor, Color)
-ADD_READONLY_PROPERTY_METADATA(Link, Link::FocusStyle, FocusStyle)
-ADD_PROPERTY_METADATA(Link, bool, Underline)
 END_METADATA()
 
 }  // namespace views
diff --git a/ui/views/controls/link.h b/ui/views/controls/link.h
index 684e05d7..51b5a234 100644
--- a/ui/views/controls/link.h
+++ b/ui/views/controls/link.h
@@ -35,24 +35,11 @@
   using ClickedCallback =
       base::RepeatingCallback<void(Link* source, int event_flags)>;
 
-  // The padding for the focus ring border when rendering a focused Link with
-  // FocusStyle::kRing.
-  static constexpr gfx::Insets kFocusBorderPadding = gfx::Insets(1);
-
-  // How the Link is styled when focused.
-  enum class FocusStyle {
-    kUnderline,  // An underline style is added to the text only when focused.
-    kRing,       // A focus ring is drawn around the View.
-  };
-
   explicit Link(const base::string16& title,
                 int text_context = style::CONTEXT_LABEL,
                 int text_style = style::STYLE_LINK);
   ~Link() override;
 
-  // Returns the current FocusStyle of this Link.
-  FocusStyle GetFocusStyle() const;
-
   // Allow providing callbacks that expect either zero or two args, since many
   // callers don't care about the arguments and can avoid adapter functions this
   // way.
@@ -69,8 +56,6 @@
   SkColor GetColor() const;
 
   // Label:
-  void PaintFocusRing(gfx::Canvas* canvas) const override;
-  gfx::Insets GetInsets() const override;
   gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override;
   bool CanProcessEventsWithinSubtree() const override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
@@ -89,13 +74,6 @@
   void SetEnabledColor(SkColor color) override;
   bool IsSelectionSupported() const override;
 
-  bool GetUnderline() const;
-  // TODO(estade): almost all the places that call this pass false. With
-  // Harmony, false is already the default so those callsites can be removed.
-  // TODO(tapted): Then remove all callsites when client code sets a correct
-  // typography style and derives this from style::GetFont(STYLE_LINK).
-  void SetUnderline(bool underline);
-
  private:
   void SetPressed(bool pressed);
 
@@ -105,9 +83,6 @@
 
   ClickedCallback callback_;
 
-  // Whether the link should be underlined when enabled.
-  bool underline_ = false;
-
   // Whether the link is currently pressed.
   bool pressed_ = false;
 
diff --git a/ui/views/controls/styled_label.cc b/ui/views/controls/styled_label.cc
index 9004b93..5c915f9d 100644
--- a/ui/views/controls/styled_label.cc
+++ b/ui/views/controls/styled_label.cc
@@ -556,9 +556,6 @@
     // Note this ignores |default_text_style_|, in favor of style::STYLE_LINK.
     auto link = std::make_unique<Link>(text, text_context_);
 
-    // Links in a StyledLabel do not get underlines.
-    link->SetUnderline(false);
-
     layout_views_->link_targets[link.get()] = range;
 
     result = std::move(link);
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js
index 7f6b7b9..3c1f77f 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -990,7 +990,7 @@
 
   /** @private */
   updateVpnType_() {
-    if (this.configProperties_ === undefined) {
+    if (this.configProperties_ === undefined || this.vpnType_ === undefined) {
       return;
     }
 
diff --git a/weblayer/README.md b/weblayer/README.md
index df489b3b..db5bd0d1 100644
--- a/weblayer/README.md
+++ b/weblayer/README.md
@@ -76,20 +76,48 @@
 
 To run WPT on android against weblayer do the following:
 
-$ export WPT_TEST= test you want to run, relative to wpt directory.
-$ autoninja -C out/Default run_weblayer_shell weblayer_shell_wpt
-$ out/Default/bin/run_weblayer_shell
-$ testing/scripts/run_android_wpt.py --webdriver-binary=out/Default/clang_x64/chromedriver --product android_weblayer --isolated-script-test-output /tmp/weblayer_out.json --include ./third_party/blink/web_tests/external/wpt/$WPT_TEST
+    $ export WPT_TEST= test you want to run, relative to wpt directory.
+    $ autoninja -C out/Default run_weblayer_shell weblayer_shell_wpt
+    $ out/Default/bin/run_weblayer_shell
+    $ testing/scripts/run_android_wpt.py --webdriver-binary=out/Default/clang_x64/chromedriver --product android_weblayer --isolated-script-test-output /tmp/weblayer_out.json --include ./third_party/blink/web_tests/external/wpt/$WPT_TEST
 
 `run_android_wpt.py` does not install weblayer-shell, you need to do that
 yourself (executing run_weblayer_shell will do that).
 
 To run against clank:
 
-$ autoninja -C out/Default monochrome_public_apk
-$ out/Default/bin/monochrome_public_apk install
-$ testing/scripts/run_android_wpt.py --webdriver-binary=out/Default/clang_x64/chromedriver --product chrome_android --package-name org.chromium.chrome --isolated-script-test-output /tmp/weblayer_out.json --include ./third_party/blink/web_tests/external/wpt/$WPT_TEST
+    $ autoninja -C out/Default monochrome_public_apk
+    $ out/Default/bin/monochrome_public_apk install
+    $ testing/scripts/run_android_wpt.py --webdriver-binary=out/Default/clang_x64/chromedriver --product chrome_android --package-name org.chromium.chrome --isolated-script-test-output /tmp/weblayer_out.json --include ./third_party/blink/web_tests/external/wpt/$WPT_TEST
 
 Passing in `-vvvv` may be useful if you want to see loads of information about
 test execution.
 
+## Telemetry
+
+Telemetry is run against WebLayer, currently on the bot
+[android-pixel2_weblayer-perf]
+(https://ci.chromium.org/p/chrome/builders/ci/android-pixel2_weblayer-perf).
+
+Telemetry currently only runs on real hardware. Bug [1067712]
+(https://bugs.chromium.org/p/chromium/issues/detail?id=1067712) is for
+adding support for emulators.
+
+### Tricks:
+
+To see the set of stories executed, click on a successful run, search for
+`performance_weblayer_test_suite` and click on the `json.output`
+link.
+
+Googlers can submit jobs against your own patch using [pinpoint]
+(https://pinpoint-dot-chromeperf.appspot.com/). At the time of this
+writing, logcat is *not* captured for successful runs ([1067024]
+(https://bugs.chromium.org/p/chromium/issues/detail?id=1067024)). Submitting
+a pinpoint run against a patch with a CHECK will generate
+logcat. For such a run, the logcat is viewable by way of:
+
+1. Click on Id next to `task` under `Test`.
+2. Expand `+` (under `More Details`).
+3. Click on link next to `Isolated Outputs`.
+4. Click on `test_results.json`.
+5. Replace `gs://` with `https://pantheon.corp.google.com/storage/browser`.