diff --git a/.gitignore b/.gitignore
index baf86ec0..d4ea73c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -324,6 +324,7 @@
 /tools/tryserver
 /tools/win/link_limiter/build
 /ui/file_manager/internal
+/ui/file_manager/tsconfig.json
 /ui/keyboard/keyboard_mojom_bindings.xml
 /ui/surface/surface.xml
 /ui/surface/surface_gpu_tests.xml
diff --git a/DEPS b/DEPS
index cf4c6ce2..caedd10 100644
--- a/DEPS
+++ b/DEPS
@@ -297,7 +297,7 @@
   # 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': '7525ca09971982717161466016c07fabf9f267ed',
+  'skia_revision': '6df5d5f92381d963b15003fc3277ebe6bcd96ef2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -305,7 +305,7 @@
   # 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': 'c554b92b1751761abd2b2163571d8769c5d26a9d',
+  'angle_revision': '8474a95e39caee2595d33813d84cfe5fe55fad7c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -324,7 +324,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
-  'fuchsia_version': 'version:9.20220808.1.1',
+  'fuchsia_version': 'version:9.20220808.3.1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -368,7 +368,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': 'dd7b9e9e263ee40147814bbf38d7d2e2e0a914ba',
+  'catapult_revision': '4755386202b94643c997cca2b8b817f128fe3a63',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -376,7 +376,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '823a5cd09ca5871968a355b564b8bb106582dd48',
+  'devtools_frontend_revision': '6c2ac8af45af5dd244a355dfbd8dbe9c637489ab',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -480,7 +480,7 @@
 
   # If you change this, also update the libc++ revision in
   # //buildtools/deps_revisions.gni.
-  'libcxx_revision':       '75bbec9f6d4f06c91eaf94aadafe9ad6520b1b20',
+  'libcxx_revision':       'fe1bc75a460dccaceaab8013a3df47283379363d',
 
   # GN CIPD package version.
   'gn_version': 'git_revision:3d773bba0927e67eae8fdaee5e28b0f6203d3bee',
@@ -773,7 +773,7 @@
     Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248',
 
   'src/docs/website': {
-    'url': Var('chromium_git') + '/website.git' + '@' + '8612ce17027a0beafaaf284e3019ccfb88134444',
+    'url': Var('chromium_git') + '/website.git' + '@' + '47ba73287a73719d6f61024b639a86c09e0ba395',
   },
 
   'src/ios/third_party/earl_grey2/src': {
@@ -952,7 +952,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': '07PiAW_hVf8sSGw-hZzFrH-BkE6VY-a3pQZdU7pWjGAC',
+          'version': 'gAsD4l8EoP_W0IH5vzedZ1tyN3-wAP8-fqkaS_mX6rcC',
       },
     ],
     'condition': 'checkout_android',
@@ -1193,7 +1193,7 @@
     Var('chromium_git') + '/chromium/dom-distiller/dist.git' + '@' + '199de96b345ada7c6e7e6ba3d2fa7a6911b8767d',
 
   'src/third_party/eigen3/src':
-    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '0e187141679fdb91da33249d18cb79a011c0e2ea',
+    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '34780d8bd13d0af0cf17a22789ef286e8512594d',
 
   'src/third_party/emoji-metadata/src': {
     'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '8de89a7a36cd024dcd30ac9f67f3f02c37a7c8fb',
@@ -1613,7 +1613,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'IBW3UYermEa3GRA8TK8U8l7zQEPKBCQOt8d4K4QAHtsC',
+              'version': 'zwDsb_S9yBEwDeg6obeP11vhi8U_Hg82v-Fsv-90ifMC',
           },
       ],
       'condition': 'checkout_android',
@@ -1680,7 +1680,7 @@
     Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f',
 
   'src/third_party/tflite/src':
-    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '179fbbab3fc38152be53b519376f0067736fd934',
+    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '20bdb50879599c0e7a62036ee3fd8a644ced97f1',
 
   'src/third_party/turbine': {
       'packages': [
@@ -1693,7 +1693,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@4b211a6a98e61b2f9e45138498b17701b3062b95',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@5e532d83424e4cdfa5f14793c5dfb24cad57cace',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1729,7 +1729,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '44e4c8770158c505b03ee7feafa4859d083b0912',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '05b229fc27194034b3f408b59943085f48093f35',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '2c9134b2f50d02cff7fccd3bc2135bdf6be7e3ef',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '9801a93b08ae52a4f3043812a36f3b375181ac1b',
@@ -1805,7 +1805,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@92d3d7bf199265d15441ce41f1291e598ef7fc44',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@a1ff16942cb731d859030a8034fde038e6425148',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwPacProcessorTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwPacProcessorTest.java
index 834905f..a6b614b 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwPacProcessorTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwPacProcessorTest.java
@@ -3,6 +3,10 @@
 // found in the LICENSE file.
 
 package org.chromium.android_webview.test;
+
+import android.os.Build;
+
+import androidx.annotation.RequiresApi;
 import androidx.test.filters.SmallTest;
 
 import com.android.webview.chromium.WebViewChromiumFactoryProvider;
@@ -16,11 +20,14 @@
 import org.chromium.android_webview.AwPacProcessor;
 import org.chromium.base.JNIUtils;
 import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
 
 /**
  * Tests for AwPacProcessor class.
  */
 @RunWith(AwJUnit4ClassRunner.class)
+@MinAndroidSdkLevel(Build.VERSION_CODES.P)
+@RequiresApi(Build.VERSION_CODES.P)
 public class AwPacProcessorTest {
     private AwPacProcessor mProcessor;
 
@@ -59,4 +66,4 @@
         mProcessor.setNetwork(null);
         Assert.assertEquals(proxyResultNetworkIsNotSet, mProcessor.makeProxyRequest(mTestUrl));
     }
-}
\ No newline at end of file
+}
diff --git a/ash/components/arc/net/arc_net_host_impl.cc b/ash/components/arc/net/arc_net_host_impl.cc
index 22a52130..792dd05 100644
--- a/ash/components/arc/net/arc_net_host_impl.cc
+++ b/ash/components/arc/net/arc_net_host_impl.cc
@@ -83,7 +83,7 @@
   return chromeos::NetworkHandler::Get()->network_profile_handler();
 }
 
-const chromeos::NetworkProfile* GetNetworkProfile() {
+const ash::NetworkProfile* GetNetworkProfile() {
   return GetNetworkProfileHandler()->GetProfileForUserhash(
       chromeos::LoginState::Get()->primary_user_hash());
 }
diff --git a/ash/components/tether/synchronous_shutdown_object_container_impl.h b/ash/components/tether/synchronous_shutdown_object_container_impl.h
index 74cbc05d..71f4067 100644
--- a/ash/components/tether/synchronous_shutdown_object_container_impl.h
+++ b/ash/components/tether/synchronous_shutdown_object_container_impl.h
@@ -11,8 +11,6 @@
 // TODO(https://crbug.com/1164001): move to forward declaration
 #include "ash/services/secure_channel/public/cpp/client/secure_channel_client.h"
 // TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_connect.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
 #include "chromeos/ash/components/network/network_state_handler.h"
 
 class PrefService;
@@ -27,6 +25,7 @@
 class DeviceSyncClient;
 }
 
+class NetworkConnect;
 class NetworkConnectionHandler;
 
 namespace tether {
diff --git a/ash/components/tether/tether_component_impl.h b/ash/components/tether/tether_component_impl.h
index 2d6b880..07659792 100644
--- a/ash/components/tether/tether_component_impl.h
+++ b/ash/components/tether/tether_component_impl.h
@@ -13,8 +13,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 // TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_connect.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "device/bluetooth/bluetooth_adapter.h"
@@ -36,6 +34,7 @@
 }
 
 class ManagedNetworkConfigurationHandler;
+class NetworkConnect;
 class NetworkConnectionHandler;
 
 namespace tether {
diff --git a/ash/components/tether/wifi_hotspot_connector.h b/ash/components/tether/wifi_hotspot_connector.h
index 3ac989f..9926a06 100644
--- a/ash/components/tether/wifi_hotspot_connector.h
+++ b/ash/components/tether/wifi_hotspot_connector.h
@@ -14,10 +14,6 @@
 #include "base/timer/timer.h"
 #include "base/values.h"
 // TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_connect.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_state.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
 #include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/ash/components/network/network_state_handler_observer.h"
 
@@ -27,6 +23,9 @@
 
 namespace ash {
 
+class NetworkConnect;
+class NetworkState;
+
 namespace tether {
 
 // Connects to a Wi-Fi hotspot, given an SSID and password.
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 652478c..aae51979 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1294,6 +1294,9 @@
 const base::Feature kProjectorLocalPlayback("ProjectorLocalPlayback",
                                             base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enable or disable quick settings revamped view.
+const base::Feature kQsRevamp{"QsRevamp", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls whether the quick dim prototype is enabled.
 const base::Feature kQuickDim{"QuickDim", base::FEATURE_ENABLED_BY_DEFAULT};
 
@@ -2314,6 +2317,10 @@
   return base::FeatureList::IsEnabled(kProjectorLocalPlayback);
 }
 
+bool IsQsRevampEnabled() {
+  return base::FeatureList::IsEnabled(kQsRevamp);
+}
+
 bool IsQuickDimEnabled() {
   return base::FeatureList::IsEnabled(kQuickDim) && ash::switches::HasHps();
 }
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 953bcb8..c68186f 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -523,6 +523,8 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kProjectorLocalPlayback;
 COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kQsRevamp;
+COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kQuickDim;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kQuickSettingsNetworkRevamp;
diff --git a/ash/services/cellular_setup/esim_profile.h b/ash/services/cellular_setup/esim_profile.h
index 4a7bc69..6235e44 100644
--- a/ash/services/cellular_setup/esim_profile.h
+++ b/ash/services/cellular_setup/esim_profile.h
@@ -9,8 +9,6 @@
 #include "base/memory/weak_ptr.h"
 #include "chromeos/ash/components/dbus/hermes/hermes_profile_client.h"
 #include "chromeos/ash/components/dbus/hermes/hermes_response_status.h"
-// TODO(https://crbug.com/1164001): move to forward declaration.
-#include "chromeos/ash/components/network/cellular_esim_profile.h"
 #include "chromeos/ash/components/network/cellular_inhibitor.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 
@@ -18,7 +16,11 @@
 class ObjectPath;
 }
 
-namespace ash::cellular_setup {
+namespace ash {
+
+class CellularESimProfile;
+
+namespace cellular_setup {
 
 class Euicc;
 class ESimManager;
@@ -117,6 +119,7 @@
   base::WeakPtrFactory<ESimProfile> weak_ptr_factory_{this};
 };
 
-}  // namespace ash::cellular_setup
+}  // namespace cellular_setup
+}  // namespace ash
 
 #endif  // ASH_SERVICES_CELLULAR_SETUP_ESIM_PROFILE_H_
diff --git a/ash/services/cellular_setup/euicc.h b/ash/services/cellular_setup/euicc.h
index 7e475fd5..50818f0 100644
--- a/ash/services/cellular_setup/euicc.h
+++ b/ash/services/cellular_setup/euicc.h
@@ -9,8 +9,6 @@
 #include "base/gtest_prod_util.h"
 #include "chromeos/ash/components/dbus/hermes/hermes_euicc_client.h"
 #include "chromeos/ash/components/dbus/hermes/hermes_profile_client.h"
-// TODO(https://crbug.com/1164001): move to forward declaration.
-#include "chromeos/ash/components/network/cellular_esim_profile.h"
 #include "chromeos/ash/components/network/cellular_inhibitor.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 
@@ -18,7 +16,11 @@
 class ObjectPath;
 }
 
-namespace ash::cellular_setup {
+namespace ash {
+
+class CellularESimProfile;
+
+namespace cellular_setup {
 
 class ESimProfile;
 class ESimManager;
@@ -114,6 +116,7 @@
   base::WeakPtrFactory<Euicc> weak_ptr_factory_{this};
 };
 
-}  // namespace ash::cellular_setup
+}  // namespace cellular_setup
+}  // namespace ash
 
 #endif  // ASH_SERVICES_CELLULAR_SETUP_EUICC_H_
diff --git a/ash/shelf/login_shelf_widget.cc b/ash/shelf/login_shelf_widget.cc
index 123ff27..f1f5c8c 100644
--- a/ash/shelf/login_shelf_widget.cc
+++ b/ash/shelf/login_shelf_widget.cc
@@ -164,12 +164,18 @@
 
 void LoginShelfWidget::OnSessionStateChanged(
     session_manager::SessionState state) {
-  bool is_active = (state == session_manager::SessionState::ACTIVE);
+  // The login shelf should be hidden if:
+  // 1. the user session is active; or
+  // 2. the RMA app is active. The login shelf should be hidden to avoid
+  // blocking the RMA app controls or intercepting UI events.
+  bool hide_for_session_state =
+      (state == session_manager::SessionState::ACTIVE ||
+       state == session_manager::SessionState::RMA);
 
   // The visibility of `login_shelf_view_` is accessed in different places.
   // Therefore, ensure the consistency between the widget's visibility and the
   // view's visibility.
-  if (!is_active && !shelf_->ShouldHideOnSecondaryDisplay(state)) {
+  if (!hide_for_session_state && !shelf_->ShouldHideOnSecondaryDisplay(state)) {
     if (!IsVisible()) {
       Show();
       login_shelf_view_->SetVisible(true);
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 1a3dde2..a05d04c 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -1087,12 +1087,16 @@
 
 void ShelfWidget::OnSessionStateChanged(session_manager::SessionState state) {
   // Do not show shelf widget:
-  // * 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
-  bool unknown_state = state == session_manager::SessionState::UNKNOWN;
+  // 1. when views based shelf is disabled; or
+  // 2. in UNKNOWN state - it might be called before shelf was initialized; or
+  // 3. in RMA state - shelf should be hidden to avoid blocking the RMA app
+  // controls or intercepting UI events; or
+  // 4. on secondary screens in states other than ACTIVE.
+  bool hide_for_session_state =
+      state == session_manager::SessionState::UNKNOWN ||
+      state == session_manager::SessionState::RMA;
   bool hide_on_secondary_screen = shelf_->ShouldHideOnSecondaryDisplay(state);
-  if (unknown_state || hide_on_secondary_screen) {
+  if (hide_for_session_state || hide_on_secondary_screen) {
     HideIfShown();
   } else {
     bool show_hotseat = (state == session_manager::SessionState::ACTIVE);
diff --git a/ash/system/network/auto_connect_notifier_unittest.cc b/ash/system/network/auto_connect_notifier_unittest.cc
index a19309f..6ee0ffb 100644
--- a/ash/system/network/auto_connect_notifier_unittest.cc
+++ b/ash/system/network/auto_connect_notifier_unittest.cc
@@ -46,9 +46,9 @@
   ~AutoConnectNotifierTest() override = default;
 
   void SetUp() override {
-    chromeos::SystemTokenCertDbStorage::Initialize();
-    chromeos::NetworkCertLoader::Initialize();
-    chromeos::NetworkCertLoader::ForceAvailableForNetworkAuthForTesting();
+    SystemTokenCertDbStorage::Initialize();
+    NetworkCertLoader::Initialize();
+    NetworkCertLoader::ForceAvailableForNetworkAuthForTesting();
     network_handler_test_helper_ = std::make_unique<NetworkHandlerTestHelper>();
     CHECK(chromeos::NetworkHandler::Get()->auto_connect_handler());
     network_config_helper_ = std::make_unique<
@@ -75,8 +75,8 @@
     AshTestBase::TearDown();
     network_config_helper_.reset();
     network_handler_test_helper_.reset();
-    chromeos::NetworkCertLoader::Shutdown();
-    chromeos::SystemTokenCertDbStorage::Shutdown();
+    NetworkCertLoader::Shutdown();
+    SystemTokenCertDbStorage::Shutdown();
   }
 
   void NotifyConnectToNetworkRequested() {
diff --git a/ash/system/network/cellular_setup_notifier_unittest.cc b/ash/system/network/cellular_setup_notifier_unittest.cc
index 9ed79f2f..7d54995 100644
--- a/ash/system/network/cellular_setup_notifier_unittest.cc
+++ b/ash/system/network/cellular_setup_notifier_unittest.cc
@@ -43,8 +43,8 @@
   ~CellularSetupNotifierTest() override = default;
 
   void SetUp() override {
-    chromeos::SystemTokenCertDbStorage::Initialize();
-    chromeos::NetworkCertLoader::Initialize();
+    SystemTokenCertDbStorage::Initialize();
+    NetworkCertLoader::Initialize();
     chromeos::shill_clients::InitializeFakes();
     hermes_clients::InitializeFakes();
     chromeos::NetworkHandler::Initialize();
@@ -69,8 +69,8 @@
     chromeos::NetworkHandler::Shutdown();
     hermes_clients::Shutdown();
     chromeos::shill_clients::Shutdown();
-    chromeos::NetworkCertLoader::Shutdown();
-    chromeos::SystemTokenCertDbStorage::Shutdown();
+    NetworkCertLoader::Shutdown();
+    SystemTokenCertDbStorage::Shutdown();
   }
 
   // Returns the cellular setup notification if it is shown, and null if it is
diff --git a/ash/system/network/network_detailed_view_controller.cc b/ash/system/network/network_detailed_view_controller.cc
index cdccbbe..a49cc364 100644
--- a/ash/system/network/network_detailed_view_controller.cc
+++ b/ash/system/network/network_detailed_view_controller.cc
@@ -181,7 +181,7 @@
           UserMetricsAction("StatusArea_Network_ConnectConfigured"));
       LogUserNetworkEvent(*network.get());
       RecordNetworkRowClickedAction(NetworkRowClickedAction::kConnectToNetwork);
-      chromeos::NetworkConnect::Get()->ConnectToNetworkId(network->guid);
+      NetworkConnect::Get()->ConnectToNetworkId(network->guid);
       return;
     }
   }
diff --git a/ash/system/network/network_detailed_view_controller_unittest.cc b/ash/system/network/network_detailed_view_controller_unittest.cc
index 524e8b4b2..8b026ae 100644
--- a/ash/system/network/network_detailed_view_controller_unittest.cc
+++ b/ash/system/network/network_detailed_view_controller_unittest.cc
@@ -58,7 +58,7 @@
 const std::string kNetworkTechnologyWiFi = "WiFi";
 const std::string kNetworkTechnologyMobile = "Mobile";
 
-class NetworkConnectTestDelegate : public chromeos::NetworkConnect::Delegate {
+class NetworkConnectTestDelegate : public NetworkConnect::Delegate {
  public:
   NetworkConnectTestDelegate() {}
 
@@ -96,7 +96,7 @@
 
     // Creating a service here, since we would be testing that wifi,
     // networks which can be connected to are actually connected to. This
-    // checks that chromeos::NetworkConnect eventually connects us to the
+    // checks that NetworkConnect eventually connects us to the
     // network.
     wifi_service_path_ =
         network_state_helper()->ConfigureService(base::StringPrintf(
@@ -106,7 +106,7 @@
             kWifi));
 
     network_connect_delegate_ = std::make_unique<NetworkConnectTestDelegate>();
-    chromeos::NetworkConnect::Initialize(network_connect_delegate_.get());
+    NetworkConnect::Initialize(network_connect_delegate_.get());
     AshTestBase::SetUp();
 
     feature_list_.InitAndEnableFeature(features::kQuickSettingsNetworkRevamp);
@@ -119,7 +119,7 @@
   void TearDown() override {
     network_detailed_view_controller_.reset();
     AshTestBase::TearDown();
-    chromeos::NetworkConnect::Shutdown();
+    NetworkConnect::Shutdown();
     chromeos::NetworkHandler::Shutdown();
     network_connect_delegate_.reset();
   }
diff --git a/ash/system/network/network_state_list_detailed_view.cc b/ash/system/network/network_state_list_detailed_view.cc
index 94f3ab48..1fc710b0 100644
--- a/ash/system/network/network_state_list_detailed_view.cc
+++ b/ash/system/network/network_state_list_detailed_view.cc
@@ -297,7 +297,7 @@
         RecordNetworkRowClickedAction(
             NetworkRowClickedAction::kConnectToNetwork);
       }
-      chromeos::NetworkConnect::Get()->ConnectToNetworkId(network->guid);
+      NetworkConnect::Get()->ConnectToNetworkId(network->guid);
       return;
     }
   }
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc
index 1fad18f9..c3f32de 100644
--- a/ash/system/network/vpn_list_view.cc
+++ b/ash/system/network/vpn_list_view.cc
@@ -290,9 +290,8 @@
     if (IsVpnConfigAllowed()) {
       disconnect_button_ = TrayPopupUtils::CreateTrayPopupButton(
           // TODO(stevenjb): Replace with mojo API. https://crbug.com/862420.
-          base::BindRepeating(
-              &chromeos::NetworkConnect::DisconnectFromNetworkId,
-              base::Unretained(chromeos::NetworkConnect::Get()), guid_),
+          base::BindRepeating(&NetworkConnect::DisconnectFromNetworkId,
+                              base::Unretained(NetworkConnect::Get()), guid_),
           l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_DISCONNECT));
       disconnect_button_->SetAccessibleName(l10n_util::GetStringFUTF16(
           IDS_ASH_STATUS_TRAY_NETWORK_DISCONNECT_BUTTON_A11Y_LABEL, label));
diff --git a/ash/webui/diagnostics_ui/backend/BUILD.gn b/ash/webui/diagnostics_ui/backend/BUILD.gn
index 2eb8b3b..15aced3 100644
--- a/ash/webui/diagnostics_ui/backend/BUILD.gn
+++ b/ash/webui/diagnostics_ui/backend/BUILD.gn
@@ -28,6 +28,8 @@
     "power_manager_client_conversions.h",
     "routine_properties.cc",
     "routine_properties.h",
+    "session_log_async_helper.cc",
+    "session_log_async_helper.h",
     "session_log_handler.cc",
     "session_log_handler.h",
     "system_data_provider.cc",
@@ -77,6 +79,7 @@
     "network_health_provider_unittest.cc",
     "power_manager_client_conversions_unittest.cc",
     "routine_properties_unittest.cc",
+    "session_log_async_helper_unittest.cc",
     "session_log_handler_unittest.cc",
     "system_data_provider_unittest.cc",
     "system_routine_controller_unittest.cc",
diff --git a/ash/webui/diagnostics_ui/backend/session_log_async_helper.cc b/ash/webui/diagnostics_ui/backend/session_log_async_helper.cc
new file mode 100644
index 0000000..ace850d
--- /dev/null
+++ b/ash/webui/diagnostics_ui/backend/session_log_async_helper.cc
@@ -0,0 +1,89 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/webui/diagnostics_ui/backend/session_log_async_helper.h"
+
+#include <memory>
+#include <string>
+
+#include "ash/constants/ash_features.h"
+#include "ash/system/diagnostics/networking_log.h"
+#include "ash/system/diagnostics/routine_log.h"
+#include "ash/system/diagnostics/telemetry_log.h"
+#include "base/files/file_util.h"
+#include "base/strings/string_util.h"
+
+namespace ash::diagnostics {
+
+namespace {
+
+const char kRoutineLogSubsectionHeader[] = "--- Test Routines --- \n";
+const char kSystemLogSectionHeader[] = "=== System === \n";
+const char kNetworkingLogSectionHeader[] = "=== Networking === \n";
+const char kNoRoutinesRun[] =
+    "No routines of this type were run in the session.\n";
+
+std::string GetRoutineResultsString(const std::string& results) {
+  const std::string section_header =
+      std::string(kRoutineLogSubsectionHeader) + "\n";
+  if (results.empty()) {
+    return section_header + kNoRoutinesRun;
+  }
+
+  return section_header + results;
+}
+
+}  // namespace
+
+SessionLogAsyncHelper::SessionLogAsyncHelper() = default;
+SessionLogAsyncHelper::~SessionLogAsyncHelper() = default;
+
+bool SessionLogAsyncHelper::CreateSessionLogOnBlockingPool(
+    const base::FilePath file_path,
+    base::raw_ptr<TelemetryLog> telemetry_log,
+    base::raw_ptr<RoutineLog> routine_log,
+    base::raw_ptr<NetworkingLog> networking_log) {
+  // Fetch Routine logs
+  const std::string system_routines =
+      routine_log ? routine_log->GetContentsForCategory(
+                        RoutineLog::RoutineCategory::kSystem)
+                  : "";
+  const std::string network_routines =
+      routine_log ? routine_log->GetContentsForCategory(
+                        RoutineLog::RoutineCategory::kNetwork)
+                  : "";
+
+  // Fetch system data from TelemetryLog.
+  const std::string system_log_contents =
+      telemetry_log ? telemetry_log->GetContents() : "";
+
+  std::vector<std::string> pieces;
+  pieces.push_back(kSystemLogSectionHeader);
+  if (!system_log_contents.empty()) {
+    pieces.push_back(system_log_contents);
+  }
+
+  // Add the routine section for the system category.
+  pieces.push_back(GetRoutineResultsString(system_routines));
+
+  if (features::IsNetworkingInDiagnosticsAppEnabled()) {
+    // Add networking category.
+    pieces.push_back(kNetworkingLogSectionHeader);
+
+    // Add the network info section.
+    if (networking_log)
+      pieces.push_back(networking_log->GetNetworkInfo());
+
+    // Add the routine section for the network category.
+    pieces.push_back(GetRoutineResultsString(network_routines));
+
+    // Add the network events section.
+    if (networking_log)
+      pieces.push_back(networking_log->GetNetworkEvents());
+  }
+
+  return base::WriteFile(file_path, base::JoinString(pieces, "\n"));
+}
+
+}  // namespace ash::diagnostics
diff --git a/ash/webui/diagnostics_ui/backend/session_log_async_helper.h b/ash/webui/diagnostics_ui/backend/session_log_async_helper.h
new file mode 100644
index 0000000..b8aeefbd
--- /dev/null
+++ b/ash/webui/diagnostics_ui/backend/session_log_async_helper.h
@@ -0,0 +1,39 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WEBUI_DIAGNOSTICS_UI_BACKEND_SESSION_LOG_ASYNC_HELPER_H_
+#define ASH_WEBUI_DIAGNOSTICS_UI_BACKEND_SESSION_LOG_ASYNC_HELPER_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/raw_ptr.h"
+
+namespace ash::diagnostics {
+
+class TelemetryLog;
+class RoutineLog;
+class NetworkingLog;
+
+// Holds state related to current session to prevent UaF.
+class SessionLogAsyncHelper {
+ public:
+  SessionLogAsyncHelper();
+
+  SessionLogAsyncHelper(const SessionLogAsyncHelper&) = delete;
+  SessionLogAsyncHelper& operator=(const SessionLogAsyncHelper&) = delete;
+
+  virtual ~SessionLogAsyncHelper();
+
+  // Gathers session data from three log sources: TelemetryLog, RoutineLog, and
+  // NetworkingLog then writes the combined information to a location specified
+  // by |file_path|.
+  bool CreateSessionLogOnBlockingPool(
+      const base::FilePath file_path,
+      base::raw_ptr<TelemetryLog> telemetry_log,
+      base::raw_ptr<RoutineLog> routine_log,
+      base::raw_ptr<NetworkingLog> networking_log);
+};
+
+}  // namespace ash::diagnostics
+
+#endif  // ASH_WEBUI_DIAGNOSTICS_UI_BACKEND_SESSION_LOG_ASYNC_HELPER_H_
diff --git a/ash/webui/diagnostics_ui/backend/session_log_async_helper_unittest.cc b/ash/webui/diagnostics_ui/backend/session_log_async_helper_unittest.cc
new file mode 100644
index 0000000..b8739f0
--- /dev/null
+++ b/ash/webui/diagnostics_ui/backend/session_log_async_helper_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/webui/diagnostics_ui/backend/session_log_async_helper.h"
+
+#include <memory>
+
+#include "ash/system/diagnostics/log_test_helpers.h"
+#include "ash/system/diagnostics/networking_log.h"
+#include "ash/system/diagnostics/routine_log.h"
+#include "ash/system/diagnostics/telemetry_log.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash::diagnostics {
+
+namespace {
+
+constexpr char kFilePathName[] = "session_log.txt";
+constexpr char kRoutineLogSubsectionHeader[] = "--- Test Routines ---";
+constexpr char kSystemLogSectionHeader[] = "=== System ===";
+constexpr char kNetworkingLogSectionHeader[] = "=== Networking ===";
+constexpr char kNetworkInfoSectionHeader[] = "--- Network Info ---";
+constexpr char kNetworkEventsSectionHeader[] = "--- Network Events ---";
+constexpr char kNoRoutinesRun[] =
+    "No routines of this type were run in the session.";
+
+class SessionLogAsyncHelperTest : public testing::Test {
+ public:
+  SessionLogAsyncHelperTest() = default;
+  ~SessionLogAsyncHelperTest() override = default;
+
+  void SetUp() override { EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+
+  const base::FilePath GetTempPath() { return temp_dir_.GetPath(); }
+
+ private:
+  base::test::TaskEnvironment task_environment_{};
+  base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(SessionLogAsyncHelperTest, CreateSessionLogFile) {
+  auto helper = std::make_unique<SessionLogAsyncHelper>();
+  const base::FilePath path = GetTempPath();
+  const base::FilePath file_path = path.Append(kFilePathName);
+  helper->CreateSessionLogOnBlockingPool(
+      file_path, /*telemetry_log=*/new TelemetryLog(),
+      /*routine_log=*/new RoutineLog(path),
+      /*networking_log=*/new NetworkingLog(path));
+
+  EXPECT_TRUE(base::PathExists(file_path));
+  std::string contents;
+  EXPECT_TRUE(base::ReadFileToString(file_path, &contents));
+  std::vector<std::string> lines = GetLogLines(contents);
+  EXPECT_EQ(8u, lines.size());
+  EXPECT_EQ(kSystemLogSectionHeader, lines[0]);
+  EXPECT_EQ(kRoutineLogSubsectionHeader, lines[1]);
+  EXPECT_EQ(kNoRoutinesRun, lines[2]);
+  EXPECT_EQ(kNetworkingLogSectionHeader, lines[3]);
+  EXPECT_EQ(kNetworkInfoSectionHeader, lines[4]);
+  EXPECT_EQ(kRoutineLogSubsectionHeader, lines[5]);
+  EXPECT_EQ(kNoRoutinesRun, lines[6]);
+  EXPECT_EQ(kNetworkEventsSectionHeader, lines[7]);
+}
+
+TEST_F(SessionLogAsyncHelperTest, HandlesNullLogPointers) {
+  auto helper = std::make_unique<SessionLogAsyncHelper>();
+  const base::FilePath file_path = GetTempPath().Append(kFilePathName);
+  helper->CreateSessionLogOnBlockingPool(file_path, /*telemetry_log=*/nullptr,
+                                         /*routine_log=*/nullptr,
+                                         /*networking_log=*/nullptr);
+
+  EXPECT_TRUE(base::PathExists(file_path));
+  std::string contents;
+  EXPECT_TRUE(base::ReadFileToString(file_path, &contents));
+  std::vector<std::string> lines = GetLogLines(contents);
+  EXPECT_EQ(6u, lines.size());
+  EXPECT_EQ(kSystemLogSectionHeader, lines[0]);
+  EXPECT_EQ(kRoutineLogSubsectionHeader, lines[1]);
+  EXPECT_EQ(kNoRoutinesRun, lines[2]);
+  EXPECT_EQ(kNetworkingLogSectionHeader, lines[3]);
+  EXPECT_EQ(kRoutineLogSubsectionHeader, lines[4]);
+  EXPECT_EQ(kNoRoutinesRun, lines[5]);
+}
+
+}  // namespace
+}  // namespace ash::diagnostics
diff --git a/ash/webui/diagnostics_ui/backend/session_log_handler.cc b/ash/webui/diagnostics_ui/backend/session_log_handler.cc
index 675f772..d91a714f 100644
--- a/ash/webui/diagnostics_ui/backend/session_log_handler.cc
+++ b/ash/webui/diagnostics_ui/backend/session_log_handler.cc
@@ -4,16 +4,21 @@
 
 #include "ash/webui/diagnostics_ui/backend/session_log_handler.h"
 
+#include <memory>
+
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/holding_space/holding_space_client.h"
 #include "ash/system/diagnostics/diagnostics_log_controller.h"
 #include "ash/system/diagnostics/networking_log.h"
 #include "ash/system/diagnostics/routine_log.h"
 #include "ash/system/diagnostics/telemetry_log.h"
+#include "ash/webui/diagnostics_ui/backend/session_log_async_helper.h"
+#include "base/bind.h"
 #include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/values.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
@@ -26,23 +31,8 @@
 namespace diagnostics {
 namespace {
 
-const char kRoutineLogSubsectionHeader[] = "--- Test Routines --- \n";
-const char kSystemLogSectionHeader[] = "=== System === \n";
-const char kNetworkingLogSectionHeader[] = "=== Networking === \n";
-const char kNoRoutinesRun[] =
-    "No routines of this type were run in the session.\n";
 const char kDefaultSessionLogFileName[] = "session_log.txt";
 
-std::string GetRoutineResultsString(const std::string& results) {
-  const std::string section_header =
-      std::string(kRoutineLogSubsectionHeader) + "\n";
-  if (results.empty()) {
-    return section_header + kNoRoutinesRun;
-  }
-
-  return section_header + results;
-}
-
 }  // namespace
 
 SessionLogHandler::SessionLogHandler(
@@ -66,13 +56,19 @@
       routine_log_(std::move(routine_log)),
       networking_log_(std::move(networking_log)),
       holding_space_client_(holding_space_client),
-      task_runner_(
-          base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})) {
+      task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
+      async_helper_(std::unique_ptr<ash::diagnostics::SessionLogAsyncHelper,
+                                    base::OnTaskRunnerDeleter>(
+          new SessionLogAsyncHelper(),
+          base::OnTaskRunnerDeleter(task_runner_))) {
   DCHECK(holding_space_client_);
   weak_ptr_ = weak_factory_.GetWeakPtr();
+  DETACH_FROM_SEQUENCE(session_log_handler_sequence_checker_);
 }
 
 SessionLogHandler::~SessionLogHandler() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(session_log_handler_sequence_checker_);
   if (select_file_dialog_) {
     /* Lifecycle for SelectFileDialog is responsibility of calling code. */
     select_file_dialog_->ListenerDestroyed();
@@ -92,6 +88,7 @@
 void SessionLogHandler::FileSelected(const base::FilePath& path,
                                      int index,
                                      void* params) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(session_log_handler_sequence_checker_);
   // TODO(b/226574520): Remove SessionLogHandler::CreateSessionLog and
   // condition as part of flag clean up.
   if (ash::features::IsLogControllerForDiagnosticsAppEnabled()) {
@@ -99,14 +96,21 @@
         FROM_HERE,
         base::BindOnce(
             &DiagnosticsLogController::GenerateSessionLogOnBlockingPool,
+            // base::Unretained safe here because ~DiagnosticsLogController is
+            // called during shutdown of ash::Shell and will out-live
+            // SessionLogHandler.
             base::Unretained(DiagnosticsLogController::Get()), path),
         base::BindOnce(&SessionLogHandler::OnSessionLogCreated, weak_ptr_,
                        path));
   } else {
     task_runner_->PostTaskAndReplyWithResult(
         FROM_HERE,
-        base::BindOnce(&SessionLogHandler::CreateSessionLog,
-                       base::Unretained(this), path),
+        base::BindOnce(&SessionLogAsyncHelper::CreateSessionLogOnBlockingPool,
+                       // base::Unretained safe because lifetime is managed by
+                       // base::OnTaskRunnerDeleter.
+                       base::Unretained(async_helper_.get()), path,
+                       telemetry_log_.get(), routine_log_.get(),
+                       networking_log_.get()),
         base::BindOnce(&SessionLogHandler::OnSessionLogCreated, weak_ptr_,
                        path));
   }
@@ -115,6 +119,7 @@
 
 void SessionLogHandler::OnSessionLogCreated(const base::FilePath& file_path,
                                             bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(session_log_handler_sequence_checker_);
   if (success) {
     holding_space_client_->AddDiagnosticsLog(file_path);
   }
@@ -159,44 +164,9 @@
   log_created_closure_ = std::move(closure);
 }
 
-bool SessionLogHandler::CreateSessionLog(const base::FilePath& file_path) {
-  // Fetch Routine logs
-  const std::string system_routines = routine_log_->GetContentsForCategory(
-      RoutineLog::RoutineCategory::kSystem);
-  const std::string network_routines = routine_log_->GetContentsForCategory(
-      RoutineLog::RoutineCategory::kNetwork);
-
-  // Fetch system data from TelemetryLog.
-  const std::string system_log_contents = telemetry_log_->GetContents();
-
-  std::vector<std::string> pieces;
-  pieces.push_back(kSystemLogSectionHeader);
-  if (!system_log_contents.empty()) {
-    pieces.push_back(system_log_contents);
-  }
-
-  // Add the routine section for the system category.
-  pieces.push_back(GetRoutineResultsString(system_routines));
-
-  if (features::IsNetworkingInDiagnosticsAppEnabled()) {
-    // Add networking category.
-    pieces.push_back(kNetworkingLogSectionHeader);
-
-    // Add the network info section.
-    pieces.push_back(networking_log_->GetNetworkInfo());
-
-    // Add the routine section for the network category.
-    pieces.push_back(GetRoutineResultsString(network_routines));
-
-    // Add the network events section.
-    pieces.push_back(networking_log_->GetNetworkEvents());
-  }
-
-  return base::WriteFile(file_path, base::JoinString(pieces, "\n"));
-}
-
 void SessionLogHandler::HandleSaveSessionLogRequest(
     const base::Value::List& args) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(session_log_handler_sequence_checker_);
   CHECK_EQ(1U, args.size());
   DCHECK(save_session_log_callback_id_.empty());
   save_session_log_callback_id_ = args[0].GetString();
@@ -222,6 +192,7 @@
 }
 
 void SessionLogHandler::HandleInitialize(const base::Value::List& args) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(session_log_handler_sequence_checker_);
   DCHECK(args.empty());
   AllowJavascript();
 }
diff --git a/ash/webui/diagnostics_ui/backend/session_log_handler.h b/ash/webui/diagnostics_ui/backend/session_log_handler.h
index 6c263c24..393192a 100644
--- a/ash/webui/diagnostics_ui/backend/session_log_handler.h
+++ b/ash/webui/diagnostics_ui/backend/session_log_handler.h
@@ -8,9 +8,12 @@
 #include <memory>
 #include <string>
 
+#include "ash/webui/diagnostics_ui/backend/session_log_async_helper.h"
 #include "base/callback.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 #include "ui/shell_dialogs/select_file_policy.h"
@@ -79,11 +82,6 @@
   void SetLogCreatedClosureForTest(base::OnceClosure closure);
 
  private:
-  // Creates a session log at `file_path`. The session log includes the contents
-  // of both `telemetry_log_` and `routine_log_`. Returns true if the file was
-  // successfully written. Retrns false otherwise.
-  bool CreateSessionLog(const base::FilePath& file_path);
-
   // Opens the select dialog.
   void HandleSaveSessionLogRequest(const base::Value::List& args);
 
@@ -102,6 +100,9 @@
   // posted tasks are handled while SessionLogHandler is in scope to stop
   // heap-use-after-free error.
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  std::unique_ptr<SessionLogAsyncHelper, base::OnTaskRunnerDeleter>
+      async_helper_;
+  SEQUENCE_CHECKER(session_log_handler_sequence_checker_);
 
   base::WeakPtr<SessionLogHandler> weak_ptr_;
   base::WeakPtrFactory<SessionLogHandler> weak_factory_{this};
diff --git a/ash/webui/diagnostics_ui/backend/session_log_handler_unittest.cc b/ash/webui/diagnostics_ui/backend/session_log_handler_unittest.cc
index ea8fa7b..8abfc01d 100644
--- a/ash/webui/diagnostics_ui/backend/session_log_handler_unittest.cc
+++ b/ash/webui/diagnostics_ui/backend/session_log_handler_unittest.cc
@@ -25,6 +25,7 @@
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/test/test_simple_task_runner.h"
@@ -423,5 +424,28 @@
   EXPECT_NO_FATAL_FAILURE(run_loop.RunUntilIdle());
 }
 
+// Validates CreateSessionLog task does not trigger a Use-After-Free error
+// when SessionLogHandler is destroyed before task is run. See crbug/1328708.
+TEST_F(SessionLogHandlerTest, NoUseAfterFree) {
+  base::test::ScopedFeatureList features;
+  features.InitAndDisableFeature(
+      ash::features::kEnableLogControllerForDiagnosticsApp);
+  base::FilePath log_path = temp_dir_.GetPath().AppendASCII("test_path");
+  ui::SelectFileDialog::SetFactory(new TestSelectFileDialogFactory(log_path));
+  base::ListValue args;
+  args.Append(kHandlerFunctionName);
+  base::RunLoop run_loop;
+
+  session_log_handler_->SetLogCreatedClosureForTest(
+      base::BindLambdaForTesting([]() { NOTREACHED(); }));
+  EXPECT_EQ(0u, task_runner_->NumPendingTasks());
+  web_ui_.HandleReceivedMessage("saveSessionLog", &args);
+  EXPECT_EQ(1u, task_runner_->NumPendingTasks());
+  EXPECT_NO_FATAL_FAILURE(session_log_handler_.reset());
+  task_runner_->RunUntilIdle();
+  EXPECT_EQ(0u, task_runner_->NumPendingTasks());
+  EXPECT_NO_FATAL_FAILURE(task_runner_->RunUntilIdle());
+}
+
 }  // namespace diagnostics
 }  // namespace ash
diff --git a/ash/webui/os_feedback_ui/os_feedback_ui.cc b/ash/webui/os_feedback_ui/os_feedback_ui.cc
index c80f3cb..a05c276 100644
--- a/ash/webui/os_feedback_ui/os_feedback_ui.cc
+++ b/ash/webui/os_feedback_ui/os_feedback_ui.cc
@@ -67,6 +67,7 @@
       {"addFileLabel", IDS_FEEDBACK_TOOL_ADD_FILE_LABEL},
       {"replaceFileLabel", IDS_FEEDBACK_TOOL_REPLACE_FILE_LABEL},
       {"replaceFileArialLabel", IDS_FEEDBACK_TOOL_REPLACE_FILE_ARIA_LABEL},
+      {"attachFileLabelTooltip", IDS_FEEDBACK_TOOL_ATTACH_FILE_LABEL_TOOLTIP},
       {"attachFileCheckboxArialLabel",
        IDS_FEEDBACK_TOOL_ATTACH_FILE_CHECKBOX_ARIA_LABEL},
       {"userEmailLabel", IDS_FEEDBACK_TOOL_USER_EMAIL_LABEL},
diff --git a/ash/webui/os_feedback_ui/resources/file_attachment.html b/ash/webui/os_feedback_ui/resources/file_attachment.html
index eacfa6cc..ce2b2ac 100644
--- a/ash/webui/os_feedback_ui/resources/file_attachment.html
+++ b/ash/webui/os_feedback_ui/resources/file_attachment.html
@@ -131,8 +131,9 @@
       [[i18n('replaceFileLabel')]]
     </button>
   </div>
-  <button id="selectedImageButton" on-click="handleSelectedImageClick_">
-    <img id="selectedFileImage" src="[[selectedImageUrl_]]" hidden="[[!selectedImageUrl_]]">
+  <button id="selectedImageButton" on-click="handleSelectedImageClick_"
+      hidden="[[!selectedImageUrl_]]">
+    <img id="selectedFileImage" src="[[selectedImageUrl_]]">
   </button>
 </div>
 <cr-toast id="fileTooBigErrorMessage" duration="5000">
diff --git a/ash/webui/os_feedback_ui/resources/help_content.html b/ash/webui/os_feedback_ui/resources/help_content.html
index 2f633385..f3d657da 100644
--- a/ash/webui/os_feedback_ui/resources/help_content.html
+++ b/ash/webui/os_feedback_ui/resources/help_content.html
@@ -57,7 +57,7 @@
 <div id="helpContentContainer">
   <div id="helpContentLabelContainer">
     <h2 class="help-content-label">[[getLabel_(searchResult, isOnline_)]]</h2>
-    <cr-tooltip-icon icon-class="help-content:info" id="helpContentIcon"
+    <cr-tooltip-icon icon-class="os-feedback:info" id="helpContentIcon"
         hidden$="[[!hasSuggestedHelpContent_(searchResult, isOnline_)]]"
         tooltip-text="[[i18n('helpContentLabelTooltip')]]"
         icon-aria-label="[[i18n('helpContentLabelTooltip')]]">
diff --git a/ash/webui/os_feedback_ui/resources/help_resources_icons.html b/ash/webui/os_feedback_ui/resources/help_resources_icons.html
index c47122d..8bbd84e6 100644
--- a/ash/webui/os_feedback_ui/resources/help_resources_icons.html
+++ b/ash/webui/os_feedback_ui/resources/help_resources_icons.html
@@ -324,7 +324,7 @@
   </svg>
 </iron-iconset-svg>
 
-<iron-iconset-svg name="help-content" size="20">
+<iron-iconset-svg name="os-feedback" size="20">
   <svg width="20" height="20"
       xmlns="http://www.w3org/2000/svg">
     <defs>
diff --git a/ash/webui/os_feedback_ui/resources/share_data_page.html b/ash/webui/os_feedback_ui/resources/share_data_page.html
index cee3c65..9564624 100644
--- a/ash/webui/os_feedback_ui/resources/share_data_page.html
+++ b/ash/webui/os_feedback_ui/resources/share_data_page.html
@@ -9,6 +9,20 @@
     text-justify: inter-word;
   }
 
+  #attachFilesLabelContainer {
+    align-items: center;
+    display: inline-flex;
+  }
+
+  #attachFilesIcon {
+    --iron-icon-fill-color: var(--cros-icon-color-secondary);
+    display: inline-block;
+    height: 20px;
+    margin-bottom: 8px;
+    margin-inline-start: 6px;
+    width: 20px;
+  }
+
   #attachFiles {
     display: flex;
     flex-direction: column;
@@ -138,7 +152,15 @@
   <div id="content">
     <!-- Attach files -->
     <div id="attachFiles">
-      <h2 id="attachFilesLabel">[[i18n('attachFilesLabel')]]</h2>
+      <div id="attachFilesLabelContainer">
+        <h2 id="attachFilesLabel">[[i18n('attachFilesLabel')]]</h2>
+        <iron-icon icon="os-feedback:info" id="attachFilesIcon"></iron-icon>
+        <paper-tooltip for="attachFilesIcon" position="top" offset="0" fit-to-visible-bounds>
+          <div id="attachFilesTooltipContent">
+            [[i18n('attachFileLabelTooltip')]]
+          </div>
+        </paper-tooltip>
+      </div>
       <div id="attachFilesContainer">
         <!-- Attach a screenshot -->
         <div id="screenshotContainer" class="card-frame">
diff --git a/ash/webui/os_feedback_ui/resources/share_data_page.js b/ash/webui/os_feedback_ui/resources/share_data_page.js
index 3c5ddbb..9b58f96 100644
--- a/ash/webui/os_feedback_ui/resources/share_data_page.js
+++ b/ash/webui/os_feedback_ui/resources/share_data_page.js
@@ -7,7 +7,7 @@
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
 import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js';
-import 'chrome://resources/polymer/v3_0/paper-tooltip/paper-tooltip.js';
+import 'chrome://resources/cr_elements/policy/cr_tooltip_icon.m.js';
 
 import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js';
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.html b/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.html
index d7add02..521166f2 100644
--- a/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.html
+++ b/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.html
@@ -38,7 +38,8 @@
       border: 1px solid;
       border-color: var(--google-grey-200);
       border-radius: 8px;
-      width: 268px;
+      padding: 10px;
+      width: 180px;
     }
 
   #qrCodeWrapper {
diff --git a/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.js b/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.js
index 4baf731..c8b574c 100644
--- a/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.js
+++ b/ash/webui/shimless_rma/resources/onboarding_enter_rsu_wp_disable_code_page.js
@@ -17,8 +17,6 @@
 
 // The size of each tile in pixels.
 const QR_CODE_TILE_SIZE = 5;
-// Amount of padding around the QR code in pixels.
-const QR_CODE_PADDING = 4 * QR_CODE_TILE_SIZE;
 // Styling for filled tiles in the QR code.
 const QR_CODE_FILL_STYLE = '#000000';
 
@@ -167,8 +165,7 @@
     if (!response || !response.qrCode) {
       return;
     }
-    this.canvasSize_ =
-        response.qrCode.size * QR_CODE_TILE_SIZE + 2 * QR_CODE_PADDING;
+    this.canvasSize_ = response.qrCode.size * QR_CODE_TILE_SIZE;
     const context = this.getCanvasContext_();
     context.clearRect(0, 0, this.canvasSize_, this.canvasSize_);
     context.fillStyle = QR_CODE_FILL_STYLE;
@@ -177,8 +174,7 @@
       for (let y = 0; y < response.qrCode.size; y++) {
         if (response.qrCode.data[index]) {
           context.fillRect(
-              x * QR_CODE_TILE_SIZE + QR_CODE_PADDING,
-              y * QR_CODE_TILE_SIZE + QR_CODE_PADDING, QR_CODE_TILE_SIZE,
+              x * QR_CODE_TILE_SIZE, y * QR_CODE_TILE_SIZE, QR_CODE_TILE_SIZE,
               QR_CODE_TILE_SIZE);
         }
         index++;
diff --git a/ash/webui/shimless_rma/resources/reimaging_provisioning_page.js b/ash/webui/shimless_rma/resources/reimaging_provisioning_page.js
index b91661f..ed24dfe2 100644
--- a/ash/webui/shimless_rma/resources/reimaging_provisioning_page.js
+++ b/ash/webui/shimless_rma/resources/reimaging_provisioning_page.js
@@ -13,7 +13,7 @@
 import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getShimlessRmaService} from './mojo_interface_provider.js';
-import {ProvisioningError, ProvisioningObserverInterface, ProvisioningObserverReceiver, ProvisioningStatus, ShimlessRmaServiceInterface, StateResult} from './shimless_rma_types.js';
+import {ProvisioningError, ProvisioningObserverInterface, ProvisioningObserverReceiver, ProvisioningStatus, RmadErrorCode, ShimlessRmaServiceInterface, StateResult} from './shimless_rma_types.js';
 import {disableNextButton, enableNextButton, executeThenTransitionState} from './shimless_rma_util.js';
 
 /**
@@ -88,6 +88,14 @@
         status === ProvisioningStatus.kFailedNonBlocking;
     const isWpError = isErrorStatus && error === ProvisioningError.kWpEnabled;
 
+    if (isErrorStatus && !isWpError) {
+      this.dispatchEvent(new CustomEvent('fatal-hardware-error', {
+        bubbles: true,
+        composed: true,
+        detail: RmadErrorCode.kProvisioningFailed,
+      }));
+    }
+
     this.status_ = status;
 
     // Transition to next state when provisioning is complete.
diff --git a/base/allocator/partition_allocator/glossary.md b/base/allocator/partition_allocator/glossary.md
index 63e5535..5dd37bf 100644
--- a/base/allocator/partition_allocator/glossary.md
+++ b/base/allocator/partition_allocator/glossary.md
@@ -107,6 +107,22 @@
   other metadata (e.g. StarScan bitmaps) can bump the starting offset
   forward. While this term is entrenched in the code, the team
   considers it suboptimal and is actively looking for a replacement.
+* **Allocation Fast Path**: A path taken during an allocation that is
+  considered fast.  Usually means that an allocation request can be
+  immediately satisfied by grabbing a slot from the freelist of the
+  first active slot span in the bucket.
+* **Allocation Slow Path**: Anything which is not fast (see above).
+  Can involve
+  * finding another active slot span in the list,
+  * provisioning more slots in a slot span,
+  * bringing back a free (or decommitted) slot span,
+  * allocating a new slot span, or even
+  * allocating a new super page.
+
+*** aside
+By "slow" we may mean something as simple as extra logic (`if`
+statements etc.), or something as costly as system calls.
+***
 
 ## PartitionAlloc-Everywhere
 
diff --git a/base/task/sequence_manager/atomic_flag_set.cc b/base/task/sequence_manager/atomic_flag_set.cc
index 7ff2fe5..a2aad0bc 100644
--- a/base/task/sequence_manager/atomic_flag_set.cc
+++ b/base/task/sequence_manager/atomic_flag_set.cc
@@ -73,8 +73,9 @@
 
   // If |group_| has become empty delete it.
   if (group_->IsEmpty()) {
-    outer_->RemoveFromPartiallyFreeList(group_);
-    outer_->RemoveFromAllocList(group_);
+    auto ptr = group_.ExtractAsDangling();
+    outer_->RemoveFromPartiallyFreeList(ptr);
+    outer_->RemoveFromAllocList(ptr);
   }
 
   outer_ = nullptr;
diff --git a/base/task/sequence_manager/atomic_flag_set.h b/base/task/sequence_manager/atomic_flag_set.h
index 06e9222..add5380 100644
--- a/base/task/sequence_manager/atomic_flag_set.h
+++ b/base/task/sequence_manager/atomic_flag_set.h
@@ -68,8 +68,7 @@
     AtomicFlag(AtomicFlagSet* outer, Group* element, size_t flag_bit);
 
     raw_ptr<AtomicFlagSet, DanglingUntriaged> outer_ = nullptr;
-    raw_ptr<Group, DanglingUntriaged> group_ =
-        nullptr;           // Null when AtomicFlag is invalid.
+    raw_ptr<Group> group_ = nullptr;  // Null when AtomicFlag is invalid.
     size_t flag_bit_ = 0;  // This is 1 << index of this flag within the group.
   };
 
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h
index 436b259..56654cf7 100644
--- a/base/task/sequence_manager/task_queue_impl.h
+++ b/base/task/sequence_manager/task_queue_impl.h
@@ -317,6 +317,10 @@
 
     void ShutdownAndWaitForZeroOperations() {
       operations_controller_.ShutdownAndWaitForZeroOperations();
+      // `operations_controller_` won't let any more operations here, and
+      // `outer_` might get destroyed before `this` does, so clearing `outer_`
+      // avoids a potential dangling pointer.
+      outer_ = nullptr;
     }
 
    private:
@@ -326,7 +330,7 @@
 
     base::internal::OperationsController operations_controller_;
     // Pointer might be stale, access guarded by |operations_controller_|
-    const raw_ptr<TaskQueueImpl, DanglingUntriaged> outer_;
+    raw_ptr<TaskQueueImpl> outer_;
   };
 
   class TaskRunner final : public SingleThreadTaskRunner {
diff --git a/build/android/apk_operations.py b/build/android/apk_operations.py
index 532d012..0a44ee5 100755
--- a/build/android/apk_operations.py
+++ b/build/android/apk_operations.py
@@ -926,10 +926,9 @@
     with simpleperf.RunSimpleperf(device, device_simpleperf_path, package_name,
                                   process_specifier, thread_specifier,
                                   extra_args, host_simpleperf_out_path):
-      sys.stdout.write('Profiler is running; press Enter to stop...')
+      sys.stdout.write('Profiler is running; press Enter to stop...\n')
       sys.stdin.read(1)
-      sys.stdout.write('Post-processing data...')
-      sys.stdout.flush()
+      sys.stdout.write('Post-processing data...\n')
 
     simpleperf.ConvertSimpleperfToPprof(host_simpleperf_out_path,
                                         host_build_directory, pprof_out_path)
diff --git a/build/linux/sysroot_scripts/reversion_glibc.py b/build/linux/sysroot_scripts/reversion_glibc.py
index d2947f6..2f2593e 100755
--- a/build/linux/sysroot_scripts/reversion_glibc.py
+++ b/build/linux/sysroot_scripts/reversion_glibc.py
@@ -60,12 +60,17 @@
   # The default version will have '@@' in the name.
   is_default = len(name) > 2
 
-  match = re.match(VERSION_PATTERN, version)
-  # Ignore symbols versioned with GLIBC_PRIVATE.
-  if not match:
-    continue
+  if version.startswith('XCRYPT_'):
+    # Prefer GLIBC_* versioned symbols over XCRYPT_* ones.  Set the version to
+    # something > MAX_ALLOWED_GLIBC_VERSION so this symbol will not be picked.
+    version = [float('inf')]
+  else:
+    match = re.match(VERSION_PATTERN, version)
+    # Ignore symbols versioned with GLIBC_PRIVATE.
+    if not match:
+      continue
+    version = [int(part) for part in match.group(1).split('.')]
 
-  version = [int(part) for part in match.group(1).split('.')]
   if version < MAX_ALLOWED_GLIBC_VERSION:
     old_supported_version = supported_version.get(base_name, ([-1], -1))
     supported_version[base_name] = max((version, index), old_supported_version)
diff --git a/build/linux/sysroot_scripts/sysroot-creator.sh b/build/linux/sysroot_scripts/sysroot-creator.sh
index fb854cb..d7b62337 100644
--- a/build/linux/sysroot_scripts/sysroot-creator.sh
+++ b/build/linux/sysroot_scripts/sysroot-creator.sh
@@ -399,6 +399,8 @@
     "${INSTALL_ROOT}/lib/${arch}-${os}/libc.so.6"
   "${SCRIPT_DIR}/reversion_glibc.py" \
     "${INSTALL_ROOT}/lib/${arch}-${os}/libm.so.6"
+  "${SCRIPT_DIR}/reversion_glibc.py" \
+    "${INSTALL_ROOT}/lib/${arch}-${os}/libcrypt.so.1"
 }
 
 
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni
index 8e1e6505..9dc982e 100644
--- a/buildtools/deps_revisions.gni
+++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@
 declare_args() {
   # Used to cause full rebuilds on libc++ rolls. This should be kept in sync
   # with the libcxx_revision vars in //DEPS.
-  libcxx_revision = "75bbec9f6d4f06c91eaf94aadafe9ad6520b1b20"
+  libcxx_revision = "fe1bc75a460dccaceaab8013a3df47283379363d"
 }
diff --git a/chrome/VERSION b/chrome/VERSION
index d1b52d3..cfe296f 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=106
 MINOR=0
-BUILD=5228
+BUILD=5229
 PATCH=0
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
index b39b875c..fd79a9d 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceConfiguration.java
@@ -33,9 +33,6 @@
     public static final BooleanCachedFieldTrialParameter START_SURFACE_EXCLUDE_MV_TILES =
             new BooleanCachedFieldTrialParameter(
                     ChromeFeatureList.START_SURFACE_ANDROID, "exclude_mv_tiles", false);
-    public static final BooleanCachedFieldTrialParameter START_SURFACE_EXCLUDE_QUERY_TILES =
-            new BooleanCachedFieldTrialParameter(
-                    ChromeFeatureList.START_SURFACE_ANDROID, "exclude_query_tiles", true);
     public static final BooleanCachedFieldTrialParameter
             START_SURFACE_HIDE_INCOGNITO_SWITCH_NO_TAB =
                     new BooleanCachedFieldTrialParameter(ChromeFeatureList.START_SURFACE_ANDROID,
diff --git a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
index bbc29f1..ea79e28 100644
--- a/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -274,10 +274,8 @@
         mTabSwitcherCustomViewManagerSupplier = new OneshotSupplierImpl<>();
         boolean excludeMVTiles = StartSurfaceConfiguration.START_SURFACE_EXCLUDE_MV_TILES.getValue()
                 || !mIsStartSurfaceEnabled;
-        boolean excludeQueryTiles =
-                StartSurfaceConfiguration.START_SURFACE_EXCLUDE_QUERY_TILES.getValue()
-                || !mIsStartSurfaceEnabled
-                || !CachedFeatureFlags.isEnabled(ChromeFeatureList.QUERY_TILES);
+        boolean excludeQueryTiles = !mIsStartSurfaceEnabled
+                || !CachedFeatureFlags.isEnabled(ChromeFeatureList.QUERY_TILES_ON_START);
         if (!mIsStartSurfaceEnabled) {
             // Create Tab switcher directly to save one layer in the view hierarchy.
             mTabSwitcher = TabManagementModuleProvider.getDelegate().createGridTabSwitcher(activity,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index 467b54902..72310c7c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -1716,6 +1716,14 @@
 
         super.finishNativeInitialization();
 
+        if (RequestDesktopUtils.maybeDefaultEnableGlobalSetting(
+                    getPrimaryDisplaySizeInInches(), Profile.getLastUsedRegularProfile())) {
+            // TODO(crbug.com/1350274): Remove this explicit load when this bug is addressed.
+            if (getActivityTab() != null) {
+                getActivityTab().loadIfNeeded(LoadIfNeededCaller.OTHER);
+            }
+        }
+
         mManualFillingComponentSupplier.get().initialize(getWindowAndroid(),
                 mRootUiCoordinator.getBottomSheetController(),
                 (ChromeKeyboardVisibilityDelegate) getWindowAndroid().getKeyboardDelegate(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
index 47536d82..026d681e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
@@ -105,6 +105,7 @@
                 add(ChromeFeatureList.sPaintPreviewDemo);
                 add(ChromeFeatureList.sPaintPreviewShowOnStartup);
                 add(ChromeFeatureList.sQueryTiles);
+                add(ChromeFeatureList.sQueryTilesOnStart);
                 add(ChromeFeatureList.sReadLater);
                 add(ChromeFeatureList.sStartSurfaceAndroid);
                 add(ChromeFeatureList.sStartSurfaceRefactor);
@@ -151,7 +152,6 @@
                         add(StartSurfaceConfiguration.SIGNIN_PROMO_NTP_RESET_AFTER_HOURS);
                         add(StartSurfaceConfiguration.SPARE_RENDERER_DELAY_MS);
                         add(StartSurfaceConfiguration.START_SURFACE_EXCLUDE_MV_TILES);
-                        add(StartSurfaceConfiguration.START_SURFACE_EXCLUDE_QUERY_TILES);
                         add(StartSurfaceConfiguration.START_SURFACE_HIDE_INCOGNITO_SWITCH_NO_TAB);
                         add(StartSurfaceConfiguration.START_SURFACE_LAST_ACTIVE_TAB_ONLY);
                         add(StartSurfaceConfiguration.START_SURFACE_OPEN_NTP_INSTEAD_OF_START);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
index 1725e1c..54abf69 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
@@ -8,9 +8,14 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 
+import org.chromium.base.SysUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.components.browser_ui.site_settings.SingleCategorySettings;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge;
 import org.chromium.components.content_settings.ContentSettingValues;
 import org.chromium.components.content_settings.ContentSettingsType;
@@ -26,13 +31,15 @@
  * Utilities for requesting desktop sites support.
  */
 public class RequestDesktopUtils {
-    private static final String PARAM_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES =
-            "default_on_display_size_threshold_inches";
-    private static final double DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES =
-            12.0;
     private static final String ANY_SUBDOMAIN_PATTERN = "[*.]";
     private static final String SITE_WILDCARD = "*";
 
+    static final String PARAM_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES =
+            "default_on_display_size_threshold_inches";
+    static final double DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES = 12.0;
+    static final String PARAM_GLOBAL_SETTING_DEFAULT_ON_ON_LOW_END_DEVICES =
+            "default_on_on_low_end_devices";
+
     // Note: these values must match the UserAgentRequestType enum in enums.xml.
     @IntDef({UserAgentRequestType.REQUEST_DESKTOP, UserAgentRequestType.REQUEST_MOBILE})
     @Retention(RetentionPolicy.SOURCE)
@@ -142,12 +149,43 @@
             return false;
         }
 
-        // TODO(crbug.com/1343916): Also check new SharedPreferences for REQUEST_DESKTOP_SITE to
-        // determine if the setting should be updated. Also nice to have a Finch configurable
-        // boolean to disable default-enabling this setting on low RAM devices.
-        return displaySizeInInches >= ChromeFeatureList.getFieldTrialParamByFeatureAsDouble(
-                       ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS,
-                       PARAM_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
-                       DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES);
+        // Check whether default-on for low end devices is disabled.
+        if (!ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
+                    ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS,
+                    PARAM_GLOBAL_SETTING_DEFAULT_ON_ON_LOW_END_DEVICES, true)
+                && SysUtils.isLowEndDevice()) {
+            return false;
+        }
+
+        boolean previouslyDefaultEnabled = SharedPreferencesManager.getInstance().readBoolean(
+                ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING, false);
+        boolean previouslyUpdatedByUser = SharedPreferencesManager.getInstance().contains(
+                SingleCategorySettings.USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY);
+
+        return !previouslyDefaultEnabled && !previouslyUpdatedByUser
+                && displaySizeInInches >= ChromeFeatureList.getFieldTrialParamByFeatureAsDouble(
+                           ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS,
+                           PARAM_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
+                           DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES);
+    }
+
+    /**
+     * Default-enables the desktop site global setting if {@code shouldDefaultEnableGlobalSetting}
+     * returns true.
+     * @param displaySizeInInches The device primary display size, in inches.
+     * @param profile The current {@link Profile}.
+     * @return Whether the desktop site global setting was default-enabled.
+     */
+    public static boolean maybeDefaultEnableGlobalSetting(
+            double displaySizeInInches, Profile profile) {
+        if (!shouldDefaultEnableGlobalSetting(displaySizeInInches)) {
+            return false;
+        }
+
+        WebsitePreferenceBridge.setCategoryEnabled(
+                profile, ContentSettingsType.REQUEST_DESKTOP_SITE, true);
+        SharedPreferencesManager.getInstance().writeBoolean(
+                ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING, true);
+        return true;
     }
 }
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
index 56d1698..2cf3786 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/SiteSettingsTest.java
@@ -30,6 +30,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CallbackHelper;
@@ -152,6 +153,11 @@
         LocationProviderOverrider.setLocationProviderImpl(null);
         NfcSystemLevelSetting.resetNfcForTesting();
         IncognitoUtils.setEnabledForTesting(null);
+        ContextUtils.getAppSharedPreferences()
+                .edit()
+                .remove(SingleCategorySettings
+                                .USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY)
+                .apply();
     }
 
     @AfterClass
@@ -1082,6 +1088,11 @@
     public void testOnlyExpectedPreferencesRequestDesktopSite() {
         testExpectedPreferences(
                 SiteSettingsCategory.Type.REQUEST_DESKTOP_SITE, BINARY_TOGGLE, BINARY_TOGGLE);
+        Assert.assertTrue(
+                "SharedPreference USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY should be updated.",
+                ContextUtils.getAppSharedPreferences().contains(
+                        SingleCategorySettings
+                                .USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY));
     }
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java
index 79ade91..64435c255 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java
@@ -11,17 +11,30 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
 
+import org.chromium.base.FeatureList;
+import org.chromium.base.FeatureList.TestValues;
+import org.chromium.base.SysUtils;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tab.RequestDesktopUtilsUnitTest.ShadowSysUtils;
+import org.chromium.components.browser_ui.site_settings.SingleCategorySettings;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge;
 import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridgeJni;
 import org.chromium.components.content_settings.ContentSettingValues;
@@ -35,12 +48,13 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 
 /**
  * Unit tests for {@link RequestDesktopUtils}.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, shadows = {ShadowGURL.class})
+@Config(manifest = Config.NONE, shadows = {ShadowGURL.class, ShadowSysUtils.class})
 public class RequestDesktopUtilsUnitTest {
     @Rule
     public JniMocker mJniMocker = new JniMocker();
@@ -53,9 +67,28 @@
     private BrowserContextHandle mBrowserContextHandleMock;
 
     private @ContentSettingValues int mRdsDefaultValue;
+    private SharedPreferencesManager mSharedPreferencesManager;
+
     private final Map<String, Integer> mContentSettingMap = new HashMap<>();
     private final GURL mGoogleUrl = new GURL(JUnitTestGURLs.GOOGLE_URL);
     private final GURL mMapsUrl = new GURL(JUnitTestGURLs.MAPS_URL);
+
+    private final TestValues mTestValues = new TestValues();
+
+    @Implements(SysUtils.class)
+    static class ShadowSysUtils {
+        private static boolean sLowEndDevice;
+
+        public static void setLowEndDevice(boolean lowEndDevice) {
+            sLowEndDevice = lowEndDevice;
+        }
+
+        @Implementation
+        public static boolean isLowEndDevice() {
+            return sLowEndDevice;
+        }
+    }
+
     private static final String GOOGLE_COM = "[*.]google.com/";
 
     @Before
@@ -68,6 +101,16 @@
         doAnswer(invocation -> mRdsDefaultValue)
                 .when(mWebsitePreferenceBridgeJniMock)
                 .getDefaultContentSetting(any(), eq(ContentSettingsType.REQUEST_DESKTOP_SITE));
+
+        doAnswer(invocation -> {
+            mRdsDefaultValue = invocation.getArgument(2) ? ContentSettingValues.ALLOW
+                                                         : ContentSettingValues.BLOCK;
+            return null;
+        })
+                .when(mWebsitePreferenceBridgeJniMock)
+                .setContentSettingEnabled(
+                        any(), eq(ContentSettingsType.REQUEST_DESKTOP_SITE), anyBoolean());
+
         doAnswer(invocation -> {
             mContentSettingMap.put(invocation.getArgument(2), invocation.getArgument(4));
             return null;
@@ -78,6 +121,19 @@
         doAnswer(invocation -> getDomainAndRegistry(invocation.getArgument(0)))
                 .when(mUrlUtilitiesJniMock)
                 .getDomainAndRegistry(anyString(), anyBoolean());
+
+        mSharedPreferencesManager = SharedPreferencesManager.getInstance();
+        mSharedPreferencesManager.disableKeyCheckerForTesting();
+    }
+
+    @After
+    public void tearDown() {
+        FeatureList.setTestValues(null);
+        ShadowSysUtils.setLowEndDevice(false);
+        mSharedPreferencesManager.removeKey(
+                ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING);
+        mSharedPreferencesManager.removeKey(
+                SingleCategorySettings.USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY);
     }
 
     @Test
@@ -166,4 +222,87 @@
     private String getDomainAndRegistry(String origin) {
         return origin.replaceAll(".*\\.(.+\\.[^.]+$)", "$1");
     }
+
+    @Test
+    public void testShouldDefaultEnableGlobalSetting_DisableOnLowEndDevice() {
+        Map<String, String> params = new HashMap<>();
+        params.put(RequestDesktopUtils.PARAM_GLOBAL_SETTING_DEFAULT_ON_ON_LOW_END_DEVICES, "false");
+        enableFeatureRequestDesktopSiteDefaults(params);
+        ShadowSysUtils.setLowEndDevice(true);
+        boolean shouldDefaultEnable = RequestDesktopUtils.shouldDefaultEnableGlobalSetting(
+                RequestDesktopUtils
+                        .DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES);
+        Assert.assertFalse(
+                "Desktop site global setting should not be default-enabled on low memory devices.",
+                shouldDefaultEnable);
+    }
+
+    @Test
+    public void testShouldDefaultEnableGlobalSetting_CustomScreenSizeThreshold() {
+        Map<String, String> params = new HashMap<>();
+        params.put(
+                RequestDesktopUtils.PARAM_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
+                "10.0");
+        enableFeatureRequestDesktopSiteDefaults(params);
+        boolean shouldDefaultEnable = RequestDesktopUtils.shouldDefaultEnableGlobalSetting(11.0);
+        Assert.assertTrue("Desktop site global setting should be default-enabled on 10\"+ devices.",
+                shouldDefaultEnable);
+    }
+
+    @Test
+    public void testShouldDefaultEnableGlobalSetting_UserPreviouslyUpdatedSetting() {
+        enableFeatureRequestDesktopSiteDefaults(null);
+        // This SharedPreference key will ideally be updated when the user explicitly requests for
+        // an update to the desktop site global setting.
+        mSharedPreferencesManager.writeBoolean(
+                SingleCategorySettings.USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY,
+                true);
+        boolean shouldDefaultEnable = RequestDesktopUtils.shouldDefaultEnableGlobalSetting(
+                RequestDesktopUtils
+                        .DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES);
+        Assert.assertFalse(
+                "Desktop site global setting should not be default-enabled if it has been previously updated by the user.",
+                shouldDefaultEnable);
+    }
+
+    @Test
+    public void testMaybeDefaultEnableGlobalSetting() {
+        enableFeatureRequestDesktopSiteDefaults(null);
+        boolean didDefaultEnable = RequestDesktopUtils.maybeDefaultEnableGlobalSetting(
+                RequestDesktopUtils.DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
+                Mockito.mock(Profile.class));
+        Assert.assertTrue(
+                "Desktop site global setting should be default-enabled on big screen devices.",
+                didDefaultEnable);
+        Assert.assertEquals("Desktop site content setting should be set correctly.",
+                ContentSettingValues.ALLOW, mRdsDefaultValue);
+        Assert.assertTrue(
+                "SharedPreference DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING should be true.",
+                mSharedPreferencesManager.contains(
+                        ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING)
+                        && mSharedPreferencesManager.readBoolean(
+                                ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING,
+                                false));
+
+        // Check whether the desktop site global setting should be default-enabled after the first
+        // attempt.
+        boolean shouldDefaultEnable = RequestDesktopUtils.shouldDefaultEnableGlobalSetting(
+                RequestDesktopUtils
+                        .DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES);
+        Assert.assertFalse(
+                "Desktop site global setting should not be default-enabled more than once.",
+                shouldDefaultEnable);
+    }
+
+    private void enableFeatureRequestDesktopSiteDefaults(Map<String, String> params) {
+        mTestValues.addFeatureFlagOverride(ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS, true);
+        if (params != null) {
+            for (Entry<String, String> param : params.entrySet()) {
+                mTestValues.addFieldTrialParamOverride(
+                        ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS, param.getKey(),
+                        param.getValue());
+            }
+        }
+        FeatureList.setTestValues(mTestValues);
+    }
 }
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp
index 8ec5afd6..d2a5b6d 100644
--- a/chrome/app/os_settings_strings.grdp
+++ b/chrome/app/os_settings_strings.grdp
@@ -2357,6 +2357,9 @@
   <message name="IDS_SETTINGS_AUDIO_VOLUME_TITLE" desc="In Device Settings, the title of the volume row under the output section in audio settings subpage.">
     Volume
   </message>
+  <message name="IDS_SETTINGS_AUDIO_DEVICE_TITLE" desc="In Device Settings, the title of the device row under the output section in audio settings subpage.">
+    Device
+  </message>
 
   <!-- Device pointer page (OS settings) -->
   <message name="IDS_SETTINGS_MOUSE_TITLE" desc="In Device Settings, the title of the mouse settings subpage.">
diff --git a/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_AUDIO_DEVICE_TITLE.png.sha1 b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_AUDIO_DEVICE_TITLE.png.sha1
new file mode 100644
index 0000000..71c49aa
--- /dev/null
+++ b/chrome/app/os_settings_strings_grdp/IDS_SETTINGS_AUDIO_DEVICE_TITLE.png.sha1
@@ -0,0 +1 @@
+4e72aff93ce3370b9157df42e2a4948da33dbfd0
\ No newline at end of file
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index c078732e..33d3b1c 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -319,9 +319,15 @@
   <message name="IDS_AUTOFILL_EDIT_SERVER_CREDIT_CARD" desc="The text shown in the secondary action menu button to direct users to pay.google.com to edit the information of credit cards stored in Google Payments.">
     Edit in Google Pay
   </message>
+  <message name="IDS_AUTOFILL_VIRTUAL_CARD_AVAILABLE_LABEL" desc="The text shown next to the card summary to indicate that a virtual card is available for enrollment for the credit card. Virtual cards are credit cards generated from the actual cards and provide extra security.">
+    Virtual card available
+  </message>
   <message name="IDS_AUTOFILL_VIRTUAL_CARD_ENABLED_LABEL" desc="The text shown next to the card summary to indicate that a virtual card has been generated for the credit card and is enabled. Virtual cards are credit cards generated from the actual cards and provide extra security.">
     (Virtual card enabled)
   </message>
+  <message name="IDS_AUTOFILL_VIRTUAL_CARD_TURNED_ON_LABEL" desc="The text shown next to the card summary to indicate that a virtual card has been enabled for the credit card. Virtual cards are credit cards generated from the actual cards and provide extra security.">
+    Virtual card turned on
+  </message>
   <message name="IDS_AUTOFILL_VIRTUAL_CARD_UNENROLL_DIALOG_TITLE" desc="The text shown as the title of the virtual card unenroll dialog.">
     Remove your virtual card
   </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_AVAILABLE_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_AVAILABLE_LABEL.png.sha1
new file mode 100644
index 0000000..52baadf
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_AVAILABLE_LABEL.png.sha1
@@ -0,0 +1 @@
+4d6c5c769876d5c0bb2674edd62cea0af6555ac3
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_TURNED_ON_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_TURNED_ON_LABEL.png.sha1
new file mode 100644
index 0000000..52baadf
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_TURNED_ON_LABEL.png.sha1
@@ -0,0 +1 @@
+4d6c5c769876d5c0bb2674edd62cea0af6555ac3
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4078492..d7f3c38d 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -5688,6 +5688,8 @@
       "chromeos/extensions/login_screen/login_state/login_state_api.h",
       "chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.cc",
       "chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.h",
+      "chromeos/reporting/network/network_bandwidth_sampler.cc",
+      "chromeos/reporting/network/network_bandwidth_sampler.h",
       "chromeos/tablet_mode/chrome_content_browser_client_tablet_mode_part.cc",
       "chromeos/tablet_mode/chrome_content_browser_client_tablet_mode_part.h",
       "chromeos/tablet_mode/tablet_mode_page_behavior.cc",
@@ -5758,6 +5760,8 @@
       "//components/arc/common:arc_intent_helper_constants",
       "//components/pref_registry:pref_registry",
       "//components/prefs:prefs",
+      "//components/reporting/metrics:metrics_data_collection",
+      "//components/reporting/proto:metric_data_proto",
       "//components/webapk:proto",
       "//third_party/smhasher:murmurhash2",
       "//ui/wm/public",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index cc717b16..c833caef 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3659,6 +3659,9 @@
      flag_descriptions::kOobeHidDetectionRevampName,
      flag_descriptions::kOobeHidDetectionRevampDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kOobeHidDetectionRevamp)},
+    {"qs-revamp", flag_descriptions::kQsRevampName,
+     flag_descriptions::kQsRevampDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(chromeos::features::kQsRevamp)},
     {"quick-settings-network-revamp",
      flag_descriptions::kQuickSettingsNetworkRevampName,
      flag_descriptions::kQuickSettingsNetworkRevampDescription, kOsCrOS,
diff --git a/chrome/browser/apps/app_service/intent_util.cc b/chrome/browser/apps/app_service/intent_util.cc
index 506054d..78780b7 100644
--- a/chrome/browser/apps/app_service/intent_util.cc
+++ b/chrome/browser/apps/app_service/intent_util.cc
@@ -27,11 +27,9 @@
 #include "build/build_config.h"
 #include "chrome/browser/apps/app_service/file_utils.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
-#include "components/services/app_service/public/cpp/file_handler.h"
 #include "components/services/app_service/public/cpp/file_handler_info.h"
 #include "components/services/app_service/public/cpp/intent_filter_util.h"
 #include "components/services/app_service/public/cpp/intent_util.h"
-#include "components/services/app_service/public/cpp/share_target.h"
 #include "components/services/app_service/public/mojom/types.mojom-shared.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "extensions/common/api/app_runtime.h"
@@ -55,8 +53,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/components/arc/mojom/intent_common.mojom.h"
 #include "ash/components/arc/mojom/intent_helper.mojom-shared.h"
-#include "ash/constants/ash_features.h"
-#include "ash/webui/projector_app/public/cpp/projector_app_constants.h"
 #include "chrome/browser/ui/app_list/arc/intent.h"
 #include "chrome/browser/web_applications/web_app_id.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
@@ -70,8 +66,6 @@
 
 namespace {
 
-constexpr char kTextPlain[] = "text/plain";
-
 #if BUILDFLAG(IS_CHROMEOS)
 apps::mojom::IntentFilterPtr CreateFileURLFilter(
     const std::vector<std::string>& patterns,
@@ -122,141 +116,6 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
-apps::mojom::IntentFilterPtr CreateMimeTypeShareFilter(
-    const std::vector<std::string>& mime_types) {
-  DCHECK(!mime_types.empty());
-  auto intent_filter = apps::mojom::IntentFilter::New();
-
-  std::vector<apps::mojom::ConditionValuePtr> action_condition_values;
-  action_condition_values.push_back(MakeConditionValue(
-      kIntentActionSend, apps::mojom::PatternMatchType::kLiteral));
-  auto action_condition = MakeCondition(apps::mojom::ConditionType::kAction,
-                                        std::move(action_condition_values));
-  intent_filter->conditions.push_back(std::move(action_condition));
-
-  std::vector<apps::mojom::ConditionValuePtr> condition_values;
-  for (auto& mime_type : mime_types) {
-    condition_values.push_back(MakeConditionValue(
-        mime_type, apps::mojom::PatternMatchType::kMimeType));
-  }
-  auto mime_condition = MakeCondition(apps::mojom::ConditionType::kMimeType,
-                                      std::move(condition_values));
-  intent_filter->conditions.push_back(std::move(mime_condition));
-
-  return intent_filter;
-}
-
-apps::IntentFilters CreateShareIntentFiltersFromShareTarget(
-    const apps::ShareTarget& share_target) {
-  apps::IntentFilters filters;
-
-  if (!share_target.params.text.empty()) {
-    // The share target accepts navigator.share() calls with text.
-    filters.push_back(apps::ConvertMojomIntentFilterToIntentFilter(
-        CreateMimeTypeShareFilter({kTextPlain})));
-  }
-
-  std::vector<std::string> content_types;
-  for (const auto& files_entry : share_target.params.files) {
-    for (const auto& file_type : files_entry.accept) {
-      // Skip any file_type that is not a MIME type.
-      if (file_type.empty() || file_type[0] == '.' ||
-          std::count(file_type.begin(), file_type.end(), '/') != 1) {
-        continue;
-      }
-
-      content_types.push_back(file_type);
-    }
-  }
-
-  if (!content_types.empty()) {
-    const std::vector<std::string> intent_actions(
-        {kIntentActionSend, kIntentActionSendMultiple});
-    filters.push_back(CreateFileFilter(intent_actions, content_types, {}));
-  }
-
-  return filters;
-}
-
-// TODO(crbug.com/1253250): Remove after migrating to non-mojo AppService.
-std::vector<apps::mojom::IntentFilterPtr> CreateWebAppShareIntentFilters(
-    const apps::ShareTarget& share_target) {
-  std::vector<apps::mojom::IntentFilterPtr> filters;
-
-  if (!share_target.params.text.empty()) {
-    // The share target accepts navigator.share() calls with text.
-    filters.push_back(CreateMimeTypeShareFilter({kTextPlain}));
-  }
-
-  std::vector<std::string> content_types;
-  for (const auto& files_entry : share_target.params.files) {
-    for (const auto& file_type : files_entry.accept) {
-      // Skip any file_type that is not a MIME type.
-      if (file_type.empty() || file_type[0] == '.' ||
-          std::count(file_type.begin(), file_type.end(), '/') != 1) {
-        continue;
-      }
-
-      content_types.push_back(file_type);
-    }
-  }
-
-  if (!content_types.empty()) {
-    const std::vector<std::string> intent_actions(
-        {kIntentActionSend, kIntentActionSendMultiple});
-    filters.push_back(apps::ConvertIntentFilterToMojomIntentFilter(
-        CreateFileFilter(intent_actions, content_types, {})));
-  }
-
-  return filters;
-}
-
-apps::IntentFilters CreateIntentFiltersFromFileHandlers(
-    const apps::FileHandlers& file_handlers) {
-  apps::IntentFilters filters;
-  for (const apps::FileHandler& handler : file_handlers) {
-    std::vector<std::string> mime_types;
-    std::vector<std::string> file_extensions;
-    std::string action_url = handler.action.spec();
-    // TODO(petermarshall): Use GetFileExtensionsFromFileHandlers /
-    // GetMimeTypesFromFileHandlers?
-    for (const apps::FileHandler::AcceptEntry& accept_entry : handler.accept) {
-      mime_types.push_back(accept_entry.mime_type);
-      for (const std::string& extension : accept_entry.file_extensions) {
-        file_extensions.push_back(extension);
-      }
-    }
-    filters.push_back(CreateFileFilter({kIntentActionView}, mime_types,
-                                       file_extensions, action_url));
-  }
-
-  return filters;
-}
-
-// TODO(crbug.com/1253250): Remove after migrating to non-mojo AppService.
-std::vector<apps::mojom::IntentFilterPtr> CreateWebAppFileHandlerIntentFilters(
-    const apps::FileHandlers& file_handlers) {
-  std::vector<apps::mojom::IntentFilterPtr> filters;
-  for (const apps::FileHandler& handler : file_handlers) {
-    std::vector<std::string> mime_types;
-    std::vector<std::string> file_extensions;
-    std::string action_url = handler.action.spec();
-    // TODO(petermarshall): Use GetFileExtensionsFromFileHandlers /
-    // GetMimeTypesFromFileHandlers?
-    for (const apps::FileHandler::AcceptEntry& accept_entry : handler.accept) {
-      mime_types.push_back(accept_entry.mime_type);
-      for (const std::string& extension : accept_entry.file_extensions) {
-        file_extensions.push_back(extension);
-      }
-    }
-    filters.push_back(
-        apps::ConvertIntentFilterToMojomIntentFilter(CreateFileFilter(
-            {kIntentActionView}, mime_types, file_extensions, action_url)));
-  }
-
-  return filters;
-}
-
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 constexpr char kIntentExtraText[] = "S.android.intent.extra.TEXT";
 constexpr char kIntentExtraSubject[] = "S.android.intent.extra.SUBJECT";
@@ -429,71 +288,6 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-apps::IntentFilters CreateIntentFiltersForWebApp(
-    const web_app::AppId& app_id,
-    const GURL& app_scope,
-    const apps::ShareTarget* app_share_target,
-    const apps::FileHandlers* enabled_file_handlers) {
-  apps::IntentFilters filters;
-
-  if (!app_scope.is_empty()) {
-    filters.push_back(apps::ConvertMojomIntentFilterToIntentFilter(
-        CreateIntentFilterForUrlScope(app_scope)));
-  }
-
-  if (app_share_target) {
-    base::Extend(filters,
-                 CreateShareIntentFiltersFromShareTarget(*app_share_target));
-  }
-
-  if (enabled_file_handlers) {
-    base::Extend(filters,
-                 CreateIntentFiltersFromFileHandlers(*enabled_file_handlers));
-  }
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (ash::features::IsProjectorEnabled() &&
-      app_id == ash::kChromeUITrustedProjectorSwaAppId) {
-    filters.push_back(apps::ConvertMojomIntentFilterToIntentFilter(
-        CreateIntentFilterForUrlScope(
-            GURL(ash::kChromeUIUntrustedProjectorPwaUrl))));
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
-  return filters;
-}
-
-std::vector<apps::mojom::IntentFilterPtr> CreateWebAppIntentFilters(
-    const web_app::AppId& app_id,
-    const GURL& app_scope,
-    const apps::ShareTarget* app_share_target,
-    const apps::FileHandlers* enabled_file_handlers) {
-  std::vector<apps::mojom::IntentFilterPtr> filters;
-
-  if (!app_scope.is_empty()) {
-    filters.push_back(CreateIntentFilterForUrlScope(app_scope));
-  }
-
-  if (app_share_target) {
-    base::Extend(filters, CreateWebAppShareIntentFilters(*app_share_target));
-  }
-
-  if (enabled_file_handlers) {
-    base::Extend(filters,
-                 CreateWebAppFileHandlerIntentFilters(*enabled_file_handlers));
-  }
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (ash::features::IsProjectorEnabled() &&
-      app_id == ash::kChromeUITrustedProjectorSwaAppId) {
-    filters.push_back(CreateIntentFilterForUrlScope(
-        GURL(ash::kChromeUIUntrustedProjectorPwaUrl)));
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
-  return filters;
-}
-
 apps::IntentFilters CreateIntentFiltersForChromeApp(
     const extensions::Extension* extension) {
   apps::IntentFilters filters;
diff --git a/chrome/browser/apps/app_service/intent_util.h b/chrome/browser/apps/app_service/intent_util.h
index 6cd7843..a612682 100644
--- a/chrome/browser/apps/app_service/intent_util.h
+++ b/chrome/browser/apps/app_service/intent_util.h
@@ -31,11 +31,6 @@
 }
 #endif
 
-namespace apps {
-struct ShareTarget;
-}
-
-class GURL;
 class Profile;
 
 namespace base {
@@ -63,25 +58,6 @@
     arc::ArcIntentHelperBridge* intent_helper_bridge);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-// Create intent filters for `app_id`. The `app_scope` is needed because
-// currently the correct app scope is not provided through WebApp API for
-// shortcuts.
-apps::IntentFilters CreateIntentFiltersForWebApp(
-    const web_app::AppId& app_id,
-    const GURL& app_scope,
-    const apps::ShareTarget* app_share_target,
-    const apps::FileHandlers* enabled_file_handlers);
-
-// Create intent filters for |web_app|.
-// The |scope| is needed because currently the correct app scope is not
-// provided through WebApp API for shortcuts.
-// TODO(crbug.com/1253250): Remove after migrating to non-mojo AppService.
-std::vector<apps::mojom::IntentFilterPtr> CreateWebAppIntentFilters(
-    const web_app::AppId& app_id,
-    const GURL& app_scope,
-    const apps::ShareTarget* app_share_target,
-    const apps::FileHandlers* enabled_file_handlers);
-
 // Create intent filters for a Chrome app (extension-based) e.g. for
 // file_handlers.
 apps::IntentFilters CreateIntentFiltersForChromeApp(
diff --git a/chrome/browser/apps/app_service/intent_util_unittest.cc b/chrome/browser/apps/app_service/intent_util_unittest.cc
index a5ccf99..c800b0f 100644
--- a/chrome/browser/apps/app_service/intent_util_unittest.cc
+++ b/chrome/browser/apps/app_service/intent_util_unittest.cc
@@ -223,210 +223,6 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-TEST_F(IntentUtilsTest, CreateIntentFiltersForWebApp_WebApp_HasUrlFilter) {
-  auto web_app = web_app::test::CreateWebApp();
-  DCHECK(web_app->start_url().is_valid());
-  GURL scope = web_app->start_url().GetWithoutFilename();
-  web_app->SetScope(scope);
-
-  IntentFilters filters = apps_util::CreateIntentFiltersForWebApp(
-      web_app->app_id(), scope,
-      /*app_share_target*/ nullptr, /*enabled_file_handlers*/ nullptr);
-
-  ASSERT_EQ(filters.size(), 1u);
-  IntentFilterPtr& filter = filters[0];
-  EXPECT_FALSE(filter->activity_name.has_value());
-  EXPECT_FALSE(filter->activity_label.has_value());
-  ASSERT_EQ(filter->conditions.size(), 4U);
-
-  {
-    const Condition& condition = *filter->conditions[0];
-    EXPECT_EQ(condition.condition_type, ConditionType::kAction);
-    ASSERT_EQ(condition.condition_values.size(), 1U);
-    EXPECT_EQ(condition.condition_values[0]->match_type,
-              PatternMatchType::kLiteral);
-    EXPECT_EQ(condition.condition_values[0]->value,
-              apps_util::kIntentActionView);
-  }
-
-  {
-    const Condition& condition = *filter->conditions[1];
-    EXPECT_EQ(condition.condition_type, ConditionType::kScheme);
-    ASSERT_EQ(condition.condition_values.size(), 1U);
-    EXPECT_EQ(condition.condition_values[0]->match_type,
-              PatternMatchType::kLiteral);
-    EXPECT_EQ(condition.condition_values[0]->value, scope.scheme());
-  }
-
-  {
-    const Condition& condition = *filter->conditions[2];
-    EXPECT_EQ(condition.condition_type, ConditionType::kHost);
-    ASSERT_EQ(condition.condition_values.size(), 1U);
-    EXPECT_EQ(condition.condition_values[0]->match_type,
-              PatternMatchType::kLiteral);
-    EXPECT_EQ(condition.condition_values[0]->value, scope.host());
-  }
-
-  {
-    const Condition& condition = *filter->conditions[3];
-    EXPECT_EQ(condition.condition_type, ConditionType::kPath);
-    ASSERT_EQ(condition.condition_values.size(), 1U);
-    EXPECT_EQ(condition.condition_values[0]->match_type,
-              PatternMatchType::kPrefix);
-    EXPECT_EQ(condition.condition_values[0]->value, scope.path());
-  }
-}
-
-// TODO(crbug.com/1253250): Remove after migrating to non-mojo AppService.
-TEST_F(IntentUtilsTest, CreateWebAppIntentFilters_WebApp_HasUrlFilter) {
-  auto web_app = web_app::test::CreateWebApp();
-  DCHECK(web_app->start_url().is_valid());
-  GURL scope = web_app->start_url().GetWithoutFilename();
-  web_app->SetScope(scope);
-
-  std::vector<apps::mojom::IntentFilterPtr> filters =
-      apps_util::CreateWebAppIntentFilters(web_app->app_id(), scope,
-                                           /*app_share_target*/ nullptr,
-                                           /*enabled_file_handlers*/ nullptr);
-
-  ASSERT_EQ(filters.size(), 1u);
-  apps::mojom::IntentFilterPtr& filter = filters[0];
-  EXPECT_FALSE(filter->activity_name.has_value());
-  EXPECT_FALSE(filter->activity_label.has_value());
-  ASSERT_EQ(filter->conditions.size(), 4U);
-
-  {
-    const apps::mojom::Condition& condition = *filter->conditions[0];
-    EXPECT_EQ(condition.condition_type, apps::mojom::ConditionType::kAction);
-    ASSERT_EQ(condition.condition_values.size(), 1U);
-    EXPECT_EQ(condition.condition_values[0]->match_type,
-              apps::mojom::PatternMatchType::kLiteral);
-    EXPECT_EQ(condition.condition_values[0]->value,
-              apps_util::kIntentActionView);
-  }
-
-  {
-    const apps::mojom::Condition& condition = *filter->conditions[1];
-    EXPECT_EQ(condition.condition_type, apps::mojom::ConditionType::kScheme);
-    ASSERT_EQ(condition.condition_values.size(), 1U);
-    EXPECT_EQ(condition.condition_values[0]->match_type,
-              apps::mojom::PatternMatchType::kLiteral);
-    EXPECT_EQ(condition.condition_values[0]->value, scope.scheme());
-  }
-
-  {
-    const apps::mojom::Condition& condition = *filter->conditions[2];
-    EXPECT_EQ(condition.condition_type, apps::mojom::ConditionType::kHost);
-    ASSERT_EQ(condition.condition_values.size(), 1U);
-    EXPECT_EQ(condition.condition_values[0]->match_type,
-              apps::mojom::PatternMatchType::kLiteral);
-    EXPECT_EQ(condition.condition_values[0]->value, scope.host());
-  }
-
-  {
-    const apps::mojom::Condition& condition = *filter->conditions[3];
-    EXPECT_EQ(condition.condition_type, apps::mojom::ConditionType::kPath);
-    ASSERT_EQ(condition.condition_values.size(), 1U);
-    EXPECT_EQ(condition.condition_values[0]->match_type,
-              apps::mojom::PatternMatchType::kPrefix);
-    EXPECT_EQ(condition.condition_values[0]->value, scope.path());
-  }
-
-  EXPECT_TRUE(apps_util::IntentMatchesFilter(
-      apps_util::CreateIntentFromUrl(web_app->start_url()), filter));
-
-  EXPECT_FALSE(apps_util::IntentMatchesFilter(
-      apps_util::CreateIntentFromUrl(GURL("https://bar.com")), filter));
-}
-
-TEST_F(IntentUtilsTest, CreateIntentFiltersForWebApp_FileHandlers) {
-  auto web_app = web_app::test::CreateWebApp();
-  DCHECK(web_app->start_url().is_valid());
-  GURL scope = web_app->start_url().GetWithoutFilename();
-  web_app->SetScope(scope);
-
-  apps::FileHandler::AcceptEntry accept_entry;
-  accept_entry.mime_type = "text/plain";
-  accept_entry.file_extensions.insert(".txt");
-  apps::FileHandler file_handler;
-  file_handler.action = GURL("https://example.com/path/handler.html");
-  file_handler.accept.push_back(std::move(accept_entry));
-  apps::FileHandlers file_handlers;
-  file_handlers.push_back(std::move(file_handler));
-  web_app->SetFileHandlers(file_handlers);
-
-  IntentFilters filters = apps_util::CreateIntentFiltersForWebApp(
-      web_app->app_id(), scope,
-      /*app_share_target*/ nullptr, &file_handlers);
-
-  ASSERT_EQ(filters.size(), 2u);
-  // 1st filter is URL filter.
-
-  // File filter - View action
-  const IntentFilterPtr& file_filter = filters[1];
-  ASSERT_EQ(file_filter->conditions.size(), 2u);
-  const Condition& view_cond = *file_filter->conditions[0];
-  EXPECT_EQ(view_cond.condition_type, ConditionType::kAction);
-  ASSERT_EQ(view_cond.condition_values.size(), 1u);
-  EXPECT_EQ(view_cond.condition_values[0]->value, apps_util::kIntentActionView);
-
-  // File filter - mime & file extension match
-  const Condition& file_cond = *file_filter->conditions[1];
-  EXPECT_EQ(file_cond.condition_type, ConditionType::kFile);
-  ASSERT_EQ(file_cond.condition_values.size(), 2u);
-  EXPECT_EQ(file_cond.condition_values[0]->match_type,
-            PatternMatchType::kMimeType);
-  EXPECT_EQ(file_cond.condition_values[0]->value, "text/plain");
-  EXPECT_EQ(file_cond.condition_values[1]->match_type,
-            PatternMatchType::kFileExtension);
-  EXPECT_EQ(file_cond.condition_values[1]->value, ".txt");
-}
-
-// TODO(crbug.com/1253250): Remove after migrating to non-mojo AppService.
-TEST_F(IntentUtilsTest, CreateWebAppIntentFilters_FileHandlers) {
-  auto web_app = web_app::test::CreateWebApp();
-  DCHECK(web_app->start_url().is_valid());
-  GURL scope = web_app->start_url().GetWithoutFilename();
-  web_app->SetScope(scope);
-
-  apps::FileHandler::AcceptEntry accept_entry;
-  accept_entry.mime_type = "text/plain";
-  accept_entry.file_extensions.insert(".txt");
-  apps::FileHandler file_handler;
-  file_handler.action = GURL("https://example.com/path/handler.html");
-  file_handler.accept.push_back(std::move(accept_entry));
-  apps::FileHandlers file_handlers;
-  file_handlers.push_back(std::move(file_handler));
-  web_app->SetFileHandlers(file_handlers);
-
-  std::vector<apps::mojom::IntentFilterPtr> filters =
-      apps_util::CreateWebAppIntentFilters(web_app->app_id(), scope,
-                                           /*app_share_target*/ nullptr,
-                                           &file_handlers);
-
-  ASSERT_EQ(filters.size(), 2u);
-  // 1st filter is URL filter.
-
-  // File filter - View action
-  const apps::mojom::IntentFilterPtr& file_filter = filters[1];
-  ASSERT_EQ(file_filter->conditions.size(), 2u);
-  const apps::mojom::Condition& view_cond = *file_filter->conditions[0];
-  EXPECT_EQ(view_cond.condition_type, apps::mojom::ConditionType::kAction);
-  ASSERT_EQ(view_cond.condition_values.size(), 1u);
-  EXPECT_EQ(view_cond.condition_values[0]->value, apps_util::kIntentActionView);
-
-  // File filter - mime & file extension match
-  const apps::mojom::Condition& file_cond = *file_filter->conditions[1];
-  EXPECT_EQ(file_cond.condition_type, apps::mojom::ConditionType::kFile);
-  ASSERT_EQ(file_cond.condition_values.size(), 2u);
-  EXPECT_EQ(file_cond.condition_values[0]->match_type,
-            apps::mojom::PatternMatchType::kMimeType);
-  EXPECT_EQ(file_cond.condition_values[0]->value, "text/plain");
-  EXPECT_EQ(file_cond.condition_values[1]->match_type,
-            apps::mojom::PatternMatchType::kFileExtension);
-  EXPECT_EQ(file_cond.condition_values[1]->value, ".txt");
-}
-
 TEST_F(IntentUtilsTest, CreateNoteTakingFilter) {
   IntentFilterPtr filter = apps_util::CreateNoteTakingFilter();
 
diff --git a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
index de9ecba..ab23c60 100644
--- a/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
+++ b/chrome/browser/ash/arc/enterprise/cert_store/cert_store_service_browsertest.cc
@@ -546,7 +546,7 @@
       std::string hex_encoded_id =
           base::HexEncode(cert_id.data(), cert_id.size());
       EXPECT_EQ(hex_encoded_id,
-                chromeos::NetworkCertLoader::GetPkcs11IdAndSlotForCert(
+                ash::NetworkCertLoader::GetPkcs11IdAndSlotForCert(
                     nss_cert.get(), &slot_id));
       EXPECT_TRUE(PlaceholdersContainIdAndSlot(cert_id, cert.test_data.slot));
       break;
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
index e3a7287..0b5162b 100644
--- a/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
+++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service.cc
@@ -568,7 +568,7 @@
 // multi-network support so we should sync per-network proxy configuration.
 void ArcSettingsServiceImpl::SyncProxySettings() const {
   std::unique_ptr<ProxyConfigDictionary> proxy_config_dict =
-      chromeos::ProxyConfigServiceImpl::GetActiveProxyConfigDictionary(
+      ash::ProxyConfigServiceImpl::GetActiveProxyConfigDictionary(
           GetPrefs(), g_browser_process->local_state());
 
   ProxyPrefs::ProxyMode mode;
diff --git a/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc b/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc
index 6da39bab..ff305f9 100644
--- a/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc
+++ b/chrome/browser/ash/arc/intent_helper/arc_settings_service_browsertest.cc
@@ -306,8 +306,7 @@
                                            ->network_state_handler()
                                            ->GetNetworkState(service_path);
     ASSERT_TRUE(network);
-    chromeos::proxy_config::SetProxyConfigForNetwork(proxy_config_dict,
-                                                     *network);
+    ash::proxy_config::SetProxyConfigForNetwork(proxy_config_dict, *network);
   }
 
   std::unique_ptr<FakeIntentHelperInstance> fake_intent_helper_instance_;
@@ -608,7 +607,7 @@
                                          ->network_state_handler()
                                          ->DefaultNetwork();
   ASSERT_TRUE(network);
-  chromeos::proxy_config::SetProxyConfigForNetwork(proxy_config_dict, *network);
+  ash::proxy_config::SetProxyConfigForNetwork(proxy_config_dict, *network);
   RunUntilIdle();
 
   base::Value expected_proxy_config(base::Value::Type::DICTIONARY);
diff --git a/chrome/browser/ash/chrome_browser_main_parts_ash.cc b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
index ab5fd5d..60e94081 100644
--- a/chrome/browser/ash/chrome_browser_main_parts_ash.cc
+++ b/chrome/browser/ash/chrome_browser_main_parts_ash.cc
@@ -915,7 +915,8 @@
 
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
-      base::BindOnce(&version_loader::GetVersion, version_loader::VERSION_FULL),
+      base::BindOnce(&chromeos::version_loader::GetVersion,
+                     chromeos::version_loader::VERSION_FULL),
       base::BindOnce(&ChromeOSVersionCallback));
 
   arc_kiosk_app_manager_ = std::make_unique<ArcKioskAppManager>();
diff --git a/chrome/browser/ash/crosapi/network_settings_service_ash.cc b/chrome/browser/ash/crosapi/network_settings_service_ash.cc
index 3b9dc30a..bfa4bab 100644
--- a/chrome/browser/ash/crosapi/network_settings_service_ash.cc
+++ b/chrome/browser/ash/crosapi/network_settings_service_ash.cc
@@ -194,8 +194,8 @@
   if (!pref_service)
     return;
   crosapi::mojom::ProxyConfigPtr new_proxy_config = ProxyConfigToCrosapiProxy(
-      chromeos::ProxyConfigServiceImpl::GetActiveProxyConfigDictionary(
-          pref_service, local_state_)
+      ash::ProxyConfigServiceImpl::GetActiveProxyConfigDictionary(pref_service,
+                                                                  local_state_)
           .get(),
       cached_wpad_url_);
 
diff --git a/chrome/browser/ash/crosapi/vpn_service_ash.cc b/chrome/browser/ash/crosapi/vpn_service_ash.cc
index bad20b0..de3ae59 100644
--- a/chrome/browser/ash/crosapi/vpn_service_ash.cc
+++ b/chrome/browser/ash/crosapi/vpn_service_ash.cc
@@ -208,7 +208,7 @@
 
   // Since the API is only designed to be used with the primary profile, it's
   // safe to get the hash of the primary profile here.
-  const chromeos::NetworkProfile* profile =
+  const ash::NetworkProfile* profile =
       chromeos::NetworkHandler::Get()
           ->network_profile_handler()
           ->GetProfileForUserhash(ash::ProfileHelper::GetUserIdHashFromProfile(
diff --git a/chrome/browser/ash/crostini/crostini_manager.cc b/chrome/browser/ash/crostini/crostini_manager.cc
index de51ddb..705b1ab 100644
--- a/chrome/browser/ash/crostini/crostini_manager.cc
+++ b/chrome/browser/ash/crostini/crostini_manager.cc
@@ -335,6 +335,15 @@
 
   mojom::InstallerState stage_ = mojom::InstallerState::kStart;
 
+  base::ScopedObservation<chromeos::SchedulerConfigurationManagerBase,
+                          chromeos::SchedulerConfigurationManagerBase::Observer>
+      scheduler_configuration_manager_observation_{this};
+  base::ScopedObservation<CrostiniManager,
+                          ash::VmShutdownObserver,
+                          &CrostiniManager::AddVmShutdownObserver,
+                          &CrostiniManager::RemoveVmShutdownObserver>
+      vm_shutdown_observation_{this};
+
   base::WeakPtrFactory<CrostiniRestarter> weak_ptr_factory_{this};
 };
 
@@ -350,7 +359,6 @@
 }
 
 CrostiniManager::CrostiniRestarter::~CrostiniRestarter() {
-  crostini_manager_->RemoveVmShutdownObserver(this);
   if (!requests_.empty()) {
     // This is triggered by logging out when restarts are in progress.
     LOG(WARNING) << "Destroying with outstanding requests.";
@@ -369,7 +377,7 @@
     return;
   }
 
-  crostini_manager_->AddVmShutdownObserver(this);
+  vm_shutdown_observation_.Observe(crostini_manager_);
   // TODO(b/205650706): It is possible to invoke a CrostiniRestarter to install
   // Crostini without using the actual installer. We should handle these better.
   RestartSource restart_source = requests_[0].options.restart_source;
@@ -718,7 +726,8 @@
   if (!scheduler_configuration) {
     // Wait for the configuration to become available.
     LOG(WARNING) << "Scheduler configuration is not yet ready";
-    scheduler_configuration_manager->AddObserver(this);
+    scheduler_configuration_manager_observation_.Observe(
+        scheduler_configuration_manager);
     return;
   }
   OnConfigurationSet(scheduler_configuration->first,
@@ -729,13 +738,15 @@
 void CrostiniManager::CrostiniRestarter::OnConfigurationSet(
     bool success,
     size_t num_cores_disabled) {
+  if (ReturnEarlyIfNeeded()) {
+    return;
+  }
+
   // Note: On non-x86_64 devices, the configuration request to debugd always
   // fails. It is WAI, and to support that case, don't log anything even when
   // |success| is false. |num_cores_disabled| is always set regardless of
   // whether the call is successful.
-  g_browser_process->platform_part()
-      ->scheduler_configuration_manager()
-      ->RemoveObserver(this);
+  scheduler_configuration_manager_observation_.Reset();
   num_cores_disabled_ = num_cores_disabled;
 
   guest_os::GuestOsServiceFactory::GetForProfile(profile_)
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index 1a07f40..925e3d5 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -2058,9 +2058,7 @@
     FilesAppBrowserTest,
     ::testing::Values(
         TestCase("breadcrumbsNavigate"),
-        TestCase("breadcrumbsNavigate").FilesExperimental(),
         TestCase("breadcrumbsNavigate").FilesSwa(),
-        TestCase("breadcrumbsNavigate").FilesSwa().FilesExperimental(),
         TestCase("breadcrumbsDownloadsTranslation"),
         TestCase("breadcrumbsDownloadsTranslation").FilesSwa(),
         TestCase("breadcrumbsRenderShortPath"),
@@ -2069,7 +2067,6 @@
         TestCase("breadcrumbsEliderButtonHidden").FilesSwa(),
         TestCase("breadcrumbsRenderLongPath"),
         TestCase("breadcrumbsRenderLongPath").FilesSwa(),
-        TestCase("breadcrumbsRenderLongPath").FilesSwa().FilesExperimental(),
         TestCase("breadcrumbsMainButtonClick"),
         TestCase("breadcrumbsMainButtonClick").FilesSwa(),
         TestCase("breadcrumbsMainButtonEnterKey"),
@@ -2153,6 +2150,16 @@
         TestCase("trashDoubleClickOnFileInTrashRootShowsDialog").EnableTrash(),
         TestCase("trashDoubleClickOnFileInTrashRootShowsDialog")
             .EnableTrash()
+            .FilesSwa(),
+        TestCase("trashDragDropRootAcceptsEntries").EnableTrash().FilesSwa(),
+        TestCase("trashDragDropFromDisallowedRootsFails")
+            .EnableTrash()
+            .FilesSwa(),
+        TestCase("trashDragDropNonModifiableEntriesCantBeTrashed")
+            .EnableTrash()
+            .FilesSwa(),
+        TestCase("trashDragDropRootPerformsTrashAction")
+            .EnableTrash()
             .FilesSwa()));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/ash/file_manager/restore_io_task.cc b/chrome/browser/ash/file_manager/restore_io_task.cc
index d7e3e4e..961ee5c3 100644
--- a/chrome/browser/ash/file_manager/restore_io_task.cc
+++ b/chrome/browser/ash/file_manager/restore_io_task.cc
@@ -34,10 +34,6 @@
   return base::File::FILE_OK;
 }
 
-base::File GetReadOnlyFileFromPath(const base::FilePath& path) {
-  return base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
-}
-
 }  // namespace
 
 RestoreIOTask::RestoreIOTask(
@@ -77,15 +73,18 @@
   progress_callback_ = std::move(progress_callback);
   complete_callback_ = std::move(complete_callback);
 
+  if (progress_.sources.size() == 0) {
+    Complete(State::kSuccess);
+    return;
+  }
+
   enabled_trash_locations_ =
       GenerateEnabledTrashLocationsForProfile(profile_, base_path_);
   progress_.state = State::kInProgress;
 
-  auto trash_pending_remote = chromeos::trash_service::LaunchTrashService();
-  trash_service_ = mojo::Remote<chromeos::trash_service::mojom::TrashService>(
-      std::move(trash_pending_remote));
-  trash_service_.set_disconnect_handler(base::BindOnce(
-      &RestoreIOTask::Complete, weak_ptr_factory_.GetWeakPtr(), State::kError));
+  parser_ = std::make_unique<chromeos::trash_service::TrashInfoParser>(
+      base::BindOnce(&RestoreIOTask::Complete, weak_ptr_factory_.GetWeakPtr(),
+                     State::kError));
 
   ValidateTrashInfo(0);
 }
@@ -164,24 +163,8 @@
           ? progress_.sources[idx].url.path()
           : base_path_.Append(progress_.sources[idx].url.path());
 
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock()},
-      base::BindOnce(&GetReadOnlyFileFromPath, trashinfo_path),
-      base::BindOnce(&RestoreIOTask::OnGotFile, weak_ptr_factory_.GetWeakPtr(),
-                     std::move(complete_callback), idx));
-}
-
-void RestoreIOTask::OnGotFile(
-    chromeos::trash_service::ParseTrashInfoCallback callback,
-    size_t idx,
-    base::File file) {
-  if (!file.IsValid()) {
-    LOG(ERROR) << "Supplied file is not valid: " << file.error_details();
-    progress_.sources[idx].error = file.error_details();
-    Complete(State::kError);
-    return;
-  }
-  trash_service_->ParseTrashInfoFile(std::move(file), std::move(callback));
+  parser_->ParseTrashInfoFile(std::move(trashinfo_path),
+                              std::move(complete_callback));
 }
 
 void RestoreIOTask::EnsureParentRestorePathExists(
diff --git a/chrome/browser/ash/file_manager/restore_io_task.h b/chrome/browser/ash/file_manager/restore_io_task.h
index 1eaebed..ac9b6b28 100644
--- a/chrome/browser/ash/file_manager/restore_io_task.h
+++ b/chrome/browser/ash/file_manager/restore_io_task.h
@@ -11,9 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/file_manager/io_task.h"
 #include "chrome/browser/ash/file_manager/trash_common_util.h"
-#include "chromeos/ash/components/trash_service/public/cpp/trash_service.h"
-#include "chromeos/ash/components/trash_service/public/mojom/trash_service.mojom.h"
-#include "mojo/public/cpp/bindings/remote.h"
+#include "chromeos/ash/components/trash_service/public/cpp/trash_info_parser.h"
 #include "storage/browser/file_system/file_system_context.h"
 #include "storage/browser/file_system/file_system_operation_runner.h"
 #include "storage/browser/file_system/file_system_url.h"
@@ -48,10 +46,6 @@
   // Finalises the RestoreIOTask with the `state`.
   void Complete(State state);
 
-  void OnGotFile(chromeos::trash_service::ParseTrashInfoCallback callback,
-                 size_t idx,
-                 base::File file);
-
   // Ensure the metadata file conforms to the following:
   //   - Has a .trashinfo suffix
   //   - Resides in an enabled trash directory
@@ -122,7 +116,7 @@
 
   // Holds the connection open to the `TrashService`. This is a sandboxed
   // process that performs parsing of the trashinfo files.
-  mojo::Remote<chromeos::trash_service::mojom::TrashService> trash_service_;
+  std::unique_ptr<chromeos::trash_service::TrashInfoParser> parser_ = nullptr;
 
   ProgressCallback progress_callback_;
   CompleteCallback complete_callback_;
diff --git a/chrome/browser/ash/file_manager/restore_io_task_unittest.cc b/chrome/browser/ash/file_manager/restore_io_task_unittest.cc
index d9e6d45..ef9f35c4 100644
--- a/chrome/browser/ash/file_manager/restore_io_task_unittest.cc
+++ b/chrome/browser/ash/file_manager/restore_io_task_unittest.cc
@@ -74,6 +74,25 @@
       trash_service_impl_;
 };
 
+TEST_F(RestoreIOTaskTest, NoSourceUrlsShouldReturnSuccess) {
+  base::RunLoop run_loop;
+  std::vector<storage::FileSystemURL> source_urls;
+
+  base::MockRepeatingCallback<void(const ProgressStatus&)> progress_callback;
+  base::MockOnceCallback<void(ProgressStatus)> complete_callback;
+
+  // We should get one complete callback when the size check of `source_urls`
+  // finds none.
+  EXPECT_CALL(complete_callback,
+              Run(Field(&ProgressStatus::state, State::kSuccess)))
+      .WillOnce(RunClosure(run_loop.QuitClosure()));
+
+  RestoreIOTask task(source_urls, profile_.get(), file_system_context_,
+                     temp_dir_.GetPath());
+  task.Execute(progress_callback.Get(), complete_callback.Get());
+  run_loop.Run();
+}
+
 TEST_F(RestoreIOTaskTest, URLsWithInvalidSuffixShouldError) {
   std::string foo_contents = base::RandBytesAsString(kTestFileSize);
   const base::FilePath file_path = temp_dir_.GetPath().Append("foo.txt");
diff --git a/chrome/browser/ash/file_manager/trash_io_task.cc b/chrome/browser/ash/file_manager/trash_io_task.cc
index a006b787..79e08e2a 100644
--- a/chrome/browser/ash/file_manager/trash_io_task.cc
+++ b/chrome/browser/ash/file_manager/trash_io_task.cc
@@ -119,6 +119,11 @@
   progress_callback_ = std::move(progress_callback);
   complete_callback_ = std::move(complete_callback);
 
+  if (progress_.sources.size() == 0) {
+    Complete(State::kSuccess);
+    return;
+  }
+
   // Build the list of known paths that are enabled, for now Downloads is a bind
   // mount at MyFiles/Downloads so treat them as separate volumes.
   free_space_map_ =
diff --git a/chrome/browser/ash/file_manager/trash_io_task_unittest.cc b/chrome/browser/ash/file_manager/trash_io_task_unittest.cc
index d125b479..3f3b366 100644
--- a/chrome/browser/ash/file_manager/trash_io_task_unittest.cc
+++ b/chrome/browser/ash/file_manager/trash_io_task_unittest.cc
@@ -82,6 +82,25 @@
   EXPECT_EQ(expected, contents);
 }
 
+TEST_F(TrashIOTaskTest, NoSourceUrlsShouldReturnSuccess) {
+  base::RunLoop run_loop;
+  std::vector<storage::FileSystemURL> source_urls;
+
+  base::MockRepeatingCallback<void(const ProgressStatus&)> progress_callback;
+  base::MockOnceCallback<void(ProgressStatus)> complete_callback;
+
+  // We should get one complete callback when the size check of `source_urls`
+  // finds none.
+  EXPECT_CALL(complete_callback,
+              Run(Field(&ProgressStatus::state, State::kSuccess)))
+      .WillOnce(RunClosure(run_loop.QuitClosure()));
+
+  TrashIOTask task(source_urls, profile_.get(), file_system_context_,
+                   temp_dir_.GetPath());
+  task.Execute(progress_callback.Get(), complete_callback.Get());
+  run_loop.Run();
+}
+
 TEST_F(TrashIOTaskTest, FileInUnsupportedDirectoryShouldError) {
   std::string foo_contents = base::RandBytesAsString(kTestFileSize);
   const base::FilePath file_path = temp_dir_.GetPath().Append("foo.txt");
diff --git a/chrome/browser/ash/hats/hats_dialog.cc b/chrome/browser/ash/hats/hats_dialog.cc
index abd80bf..ef91d79 100644
--- a/chrome/browser/ash/hats/hats_dialog.cc
+++ b/chrome/browser/ash/hats/hats_dialog.cc
@@ -97,10 +97,11 @@
       version_info::GetVersionNumber();
 
   context[KeyEnumToString(DeviceInfoKey::PLATFORM)] =
-      version_loader::GetVersion(version_loader::VERSION_FULL);
+      chromeos::version_loader::GetVersion(
+          chromeos::version_loader::VERSION_FULL);
 
   context[KeyEnumToString(DeviceInfoKey::FIRMWARE)] =
-      version_loader::GetFirmware();
+      chromeos::version_loader::GetFirmware();
 
   context[KeyEnumToString(DeviceInfoKey::LOCALE)] = user_locale;
 
diff --git a/chrome/browser/ash/input_method/assistive_suggester.cc b/chrome/browser/ash/input_method/assistive_suggester.cc
index 9bcc639..3d2a696 100644
--- a/chrome/browser/ash/input_method/assistive_suggester.cc
+++ b/chrome/browser/ash/input_method/assistive_suggester.cc
@@ -97,6 +97,12 @@
   base::UmaHistogramBoolean("InputMethod.Assistive.UserPref.MultiWord", value);
 }
 
+void RecordAssistiveUserPrefForDiacriticsOnLongpress(bool value) {
+  base::UmaHistogramBoolean(
+      "InputMethod.Assistive.UserPref.PhysicalKeyboardDiacriticsOnLongpress",
+      value);
+}
+
 void RecordAssistiveNotAllowed(AssistiveType type) {
   base::UmaHistogramEnumeration("InputMethod.Assistive.NotAllowed", type);
 }
@@ -644,6 +650,12 @@
     RecordAssistiveUserPrefForMultiWord(
         IsPredictiveWritingPrefEnabled(profile_->GetPrefs(), engine_id));
   }
+  if (base::FeatureList::IsEnabled(
+          features::kDiacriticsOnPhysicalKeyboardLongpress) &&
+      IsUsEnglishEngine(active_engine_id_)) {
+    RecordAssistiveUserPrefForDiacriticsOnLongpress(
+        IsDiacriticsOnLongpressPrefEnabled(profile_->GetPrefs(), engine_id));
+  }
 }
 
 }  // namespace input_method
diff --git a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
index 76c3c6e..849d6a6 100644
--- a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
@@ -321,6 +321,34 @@
   EXPECT_FALSE(assistive_suggester_->IsAssistiveFeatureEnabled());
 }
 
+TEST_F(AssistiveSuggesterTest, RecordPKDiacriticsPrefEnabledOnActivate) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      features::kDiacriticsOnPhysicalKeyboardLongpress);
+
+  SetInputMethodOptions(*profile_, /*predictive_writing_enabled=*/false,
+                        /*diacritics_on_longpress_enabled=*/true);
+  assistive_suggester_->OnActivate(kUsEnglishEngineId);
+
+  histogram_tester_.ExpectUniqueSample(
+      "InputMethod.Assistive.UserPref.PhysicalKeyboardDiacriticsOnLongpress",
+      true, 1);
+}
+
+TEST_F(AssistiveSuggesterTest, RecordPKDiacriticsPrefDisabledOnActivate) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      features::kDiacriticsOnPhysicalKeyboardLongpress);
+
+  SetInputMethodOptions(*profile_, /*predictive_writing_enabled=*/false,
+                        /*diacritics_on_longpress_enabled=*/false);
+  assistive_suggester_->OnActivate(kUsEnglishEngineId);
+
+  histogram_tester_.ExpectUniqueSample(
+      "InputMethod.Assistive.UserPref.PhysicalKeyboardDiacriticsOnLongpress",
+      false, 1);
+}
+
 TEST_F(AssistiveSuggesterTest, RecordPredictiveWritingPrefOnActivate) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
@@ -469,7 +497,7 @@
   task_environment_.FastForwardBy(base::Seconds(1));
 
   EXPECT_TRUE(suggestion_handler_->GetShowingSuggestion());
-  EXPECT_EQ(suggestion_handler_->GetSuggestionText(), u"à;á;â;ã;ã;ä;å;ā");
+  EXPECT_EQ(suggestion_handler_->GetSuggestionText(), u"à;á;â;ä;æ;ã;å;ā");
 }
 
 TEST_F(AssistiveSuggesterTest, DiacriticsSuggestionOnKeyDownRecordsSuccess) {
@@ -541,7 +569,7 @@
   EXPECT_FALSE(assistive_suggester_->OnKeyEvent(ReleaseKey(ui::DomCode::US_O)));
   task_environment_.FastForwardBy(base::Seconds(1));
   EXPECT_TRUE(suggestion_handler_->GetShowingSuggestion());
-  EXPECT_EQ(suggestion_handler_->GetSuggestionText(), u"à;á;â;ã;ã;ä;å;ā");
+  EXPECT_EQ(suggestion_handler_->GetSuggestionText(), u"à;á;â;ä;æ;ã;å;ā");
 }
 
 TEST_F(AssistiveSuggesterTest,
diff --git a/chrome/browser/ash/input_method/longpress_diacritics_suggester.h b/chrome/browser/ash/input_method/longpress_diacritics_suggester.h
index 5937c14..18119a4a 100644
--- a/chrome/browser/ash/input_method/longpress_diacritics_suggester.h
+++ b/chrome/browser/ash/input_method/longpress_diacritics_suggester.h
@@ -29,24 +29,26 @@
 
 // TODO(b/217560706): Replace diacritics with final set after research is
 // done (on a per input method engine basis).
+// Current diacritics ordering is based on the Gboard ordering so it keeps
+// distance from target key consistent.
 constexpr auto kDefaultDiacriticsMap =
     base::MakeFixedFlatMap<char, base::StringPiece16>(
-        {{'a', u"à;á;â;ã;ã;ä;å;ā"},
-         {'A', u"À;Á;Â;Ã;Ä;Å;Æ;Ā"},
+        {{'a', u"à;á;â;ä;æ;ã;å;ā"},
+         {'A', u"À;Á;Â;Ä;Æ;Ã;Å;Ā"},
          {'c', u"ç"},
          {'C', u"Ç"},
-         {'e', u"è;é;ê;ë;ē"},
-         {'E', u"È;É;Ê;Ë;Ē"},
-         {'i', u"ì;í;î;ï;ī"},
-         {'I', u"Ì;Í;Î;Ï;Ī"},
+         {'e', u"é;è;ê;ë;ē"},
+         {'E', u"É;È;Ê;Ë;Ē"},
+         {'i', u"í;î;ï;ī;ì"},
+         {'I', u"Í;Î;Ï;Ī;Ì"},
          {'n', u"ñ"},
          {'N', u"Ñ"},
-         {'o', u"ò;ó;ô;õ;ö;ø;ō;œ"},
-         {'O', u"Ò;Ò;Ó;Ô;Ö;Ø;Ō;Œ"},
+         {'o', u"ó;ô;ö;ò;œ;ø;ō;õ"},
+         {'O', u"Ó;Ô;Ö;Ò;Œ;Ø;Ō;Õ"},
          {'s', u"ß"},
          {'S', u"ẞ"},
-         {'u', u"ù;ú;û;ü;ū"},
-         {'U', u"Ù;Ú;Û;Ü;Ū"}});
+         {'u', u"ú;û;ü;ù;ū"},
+         {'U', u"Ú;Û;Ü;Ù;Ū"}});
 
 class LongpressDiacriticsSuggester : public Suggester {
  public:
diff --git a/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc b/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc
index 57117b52..ecb879e 100644
--- a/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/longpress_diacritics_suggester_unittest.cc
@@ -632,13 +632,13 @@
           false,
           u"ca",
           u"caf",
-          {u"à", u"á", u"â", u"ã", u"ã", u"ä", u"å", u"ā"}},
+          {u"à", u"á", u"â", u"ä", u"æ", u"ã", u"å", u"ā"}},
          {'A',
           ui::DomCode::US_A,
           true,
           u"cA",
           u"cAf",
-          {u"À", u"Á", u"Â", u"Ã", u"Ä", u"Å", u"Æ", u"Ā"}},
+          {u"À", u"Á", u"Â", u"Ä", u"Æ", u"Ã", u"Å", u"Ā"}},
          {'c', ui::DomCode::US_C, false, u"c", u"ca", {u"ç"}},
          {'C', ui::DomCode::US_C, true, u"C", u"Ca", {u"Ç"}},
          {'e',
@@ -646,13 +646,13 @@
           false,
           u"soufle",
           u"soufles",
-          {u"è", u"é", u"ê", u"ë", u"ē"}},
+          {u"é", u"è", u"ê", u"ë", u"ē"}},
          {'E',
           ui::DomCode::US_E,
           true,
           u"SOUFLE",
           u"SOUFLES",
-          {u"È", u"É", u"Ê", u"Ë", u"Ē"}}}),
+          {u"É", u"È", u"Ê", u"Ë", u"Ē"}}}),
     [](const testing::TestParamInfo<
         LongpressDiacriticsSuggesterTest::ParamType>& info) {
       return std::string(1, info.param.longpress_char);
diff --git a/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc b/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc
index b80fcb6..89da72e 100644
--- a/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc
+++ b/chrome/browser/ash/login/saml/saml_lockscreen_browsertest.cc
@@ -722,8 +722,7 @@
     ASSERT_EQ(network->guid(),
               FakeShillManagerClient::kFakeEthernetNetworkGuid);
 
-    chromeos::proxy_config::SetProxyConfigForNetwork(proxy_config_dict,
-                                                     *network);
+    proxy_config::SetProxyConfigForNetwork(proxy_config_dict, *network);
     base::RunLoop().RunUntilIdle();
   }
 
diff --git a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
index 985e283..acdc3ac807 100644
--- a/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/ash/login/users/chrome_user_manager_impl.cc
@@ -119,8 +119,6 @@
 namespace ash {
 namespace {
 
-// TODO(https://crbug.com/1164001): remove after the class is migrated
-using ::chromeos::ProxyConfigServiceImpl;
 using ::content::BrowserThread;
 
 // A string pref that gets set when a device local account is removed but a
diff --git a/chrome/browser/ash/login/version_info_updater.cc b/chrome/browser/ash/login/version_info_updater.cc
index 392c251..9ab4c0b 100644
--- a/chrome/browser/ash/login/version_info_updater.cc
+++ b/chrome/browser/ash/login/version_info_updater.cc
@@ -69,10 +69,10 @@
   if (base::SysInfo::IsRunningOnChromeOS()) {
     base::ThreadPool::PostTaskAndReplyWithResult(
         FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
-        base::BindOnce(&version_loader::GetVersion,
+        base::BindOnce(&chromeos::version_loader::GetVersion,
                        is_chrome_branded
-                           ? version_loader::VERSION_SHORT_WITH_DATE
-                           : version_loader::VERSION_FULL),
+                           ? chromeos::version_loader::VERSION_SHORT_WITH_DATE
+                           : chromeos::version_loader::VERSION_FULL),
         base::BindOnce(&VersionInfoUpdater::OnVersion,
                        weak_pointer_factory_.GetWeakPtr()));
   } else {
diff --git a/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc b/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc
index d194be96..0d66e62 100644
--- a/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc
+++ b/chrome/browser/ash/policy/core/browser_policy_connector_ash.cc
@@ -257,8 +257,8 @@
           ash::CrosSettings::Get(),
           DeviceNetworkConfigurationUpdaterAsh::DeviceAssetIDFetcher());
   // NetworkCertLoader may be not initialized in tests.
-  if (chromeos::NetworkCertLoader::IsInitialized()) {
-    chromeos::NetworkCertLoader::Get()->SetDevicePolicyCertificateProvider(
+  if (ash::NetworkCertLoader::IsInitialized()) {
+    ash::NetworkCertLoader::Get()->SetDevicePolicyCertificateProvider(
         device_network_configuration_updater_.get());
   }
 
@@ -345,9 +345,8 @@
   system_proxy_handler_.reset();
 
   // NetworkCertLoader may be not initialized in tests.
-  if (chromeos::NetworkCertLoader::IsInitialized()) {
-    chromeos::NetworkCertLoader::Get()->SetDevicePolicyCertificateProvider(
-        nullptr);
+  if (ash::NetworkCertLoader::IsInitialized()) {
+    ash::NetworkCertLoader::Get()->SetDevicePolicyCertificateProvider(nullptr);
   }
   device_network_configuration_updater_.reset();
 
diff --git a/chrome/browser/ash/policy/core/device_local_account_browsertest.cc b/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
index eb675e36..6f5f87c0 100644
--- a/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
+++ b/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
@@ -2163,7 +2163,7 @@
 
 class ManagedSessionsTest : public DeviceLocalAccountTest {
  protected:
-  class CertsObserver : public chromeos::PolicyCertificateProvider::Observer {
+  class CertsObserver : public ash::PolicyCertificateProvider::Observer {
    public:
     explicit CertsObserver(base::OnceClosure on_change)
         : on_change_(std::move(on_change)) {}
diff --git a/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc b/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc
index 5c3deee..df5e984 100644
--- a/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc
+++ b/chrome/browser/ash/policy/networking/network_policy_application_browsertest.cc
@@ -217,14 +217,14 @@
 };
 
 class ScopedNetworkCertLoaderRefreshWaiter
-    : public chromeos::NetworkCertLoader::Observer {
+    : public ash::NetworkCertLoader::Observer {
  public:
   ScopedNetworkCertLoaderRefreshWaiter() {
-    chromeos::NetworkCertLoader::Get()->AddObserver(this);
+    ash::NetworkCertLoader::Get()->AddObserver(this);
   }
 
   ~ScopedNetworkCertLoaderRefreshWaiter() override {
-    chromeos::NetworkCertLoader::Get()->RemoveObserver(this);
+    ash::NetworkCertLoader::Get()->RemoveObserver(this);
   }
 
   void OnCertificatesLoaded() override { run_loop_.Quit(); }
@@ -339,8 +339,7 @@
                   const std::string& key_filename) {
     // Before importing, configure NetworkCertLoader to assume that all
     // certificates can be used for network authentication.
-    chromeos::NetworkCertLoader::Get()
-        ->ForceAvailableForNetworkAuthForTesting();
+    ash::NetworkCertLoader::Get()->ForceAvailableForNetworkAuthForTesting();
 
     net::ScopedCERTCertificate cert;
     // Import testing key pair and certificate.
diff --git a/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc b/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc
index 6fa6292..3ae8edd3 100644
--- a/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc
+++ b/chrome/browser/ash/policy/networking/policy_certs_browsertest.cc
@@ -119,7 +119,7 @@
 // Allows waiting until the list of policy-pushed web-trusted certificates
 // changes.
 class WebTrustedCertsChangedObserver
-    : public chromeos::PolicyCertificateProvider::Observer {
+    : public ash::PolicyCertificateProvider::Observer {
  public:
   WebTrustedCertsChangedObserver() = default;
 
@@ -128,7 +128,7 @@
   WebTrustedCertsChangedObserver& operator=(
       const WebTrustedCertsChangedObserver&) = delete;
 
-  // chromeos::PolicyCertificateProvider::Observer
+  // ash::PolicyCertificateProvider::Observer
   void OnPolicyProvidedCertsChanged() override { run_loop_.Quit(); }
 
   void Wait() { run_loop_.Run(); }
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc
index 5f0085b..2b23f7e1 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc
+++ b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc
@@ -9,13 +9,13 @@
 #include "base/logging.h"
 #include "chrome/browser/ash/policy/reporting/metrics_reporting/audio/audio_events_observer.h"
 #include "chrome/browser/ash/policy/reporting/metrics_reporting/network/https_latency_sampler.h"
-#include "chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.h"
 #include "chrome/browser/ash/policy/reporting/metrics_reporting/network/network_events_observer.h"
 #include "chrome/browser/ash/policy/reporting/metrics_reporting/network/network_info_sampler.h"
 #include "chrome/browser/ash/policy/reporting/metrics_reporting/network/network_telemetry_sampler.h"
 #include "chrome/browser/ash/policy/reporting/metrics_reporting/usb/usb_events_observer.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.h"
 #include "components/reporting/client/report_queue.h"
 #include "components/reporting/client/report_queue_configuration.h"
 #include "components/reporting/client/report_queue_factory.h"
diff --git a/chrome/browser/ash/smb_client/discovery/netbios_client.h b/chrome/browser/ash/smb_client/discovery/netbios_client.h
index 590bc0e..21730ee 100644
--- a/chrome/browser/ash/smb_client/discovery/netbios_client.h
+++ b/chrome/browser/ash/smb_client/discovery/netbios_client.h
@@ -10,8 +10,6 @@
 
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/smb_client/discovery/netbios_client_interface.h"
-// TODO(https://crbug.com/1164001): remove and use forward declaration.
-#include "chromeos/ash/components/network/firewall_hole.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
@@ -28,6 +26,9 @@
 }  // namespace network
 
 namespace ash {
+
+class FirewallHole;
+
 namespace smb_client {
 
 // NetBiosClient handles a NetBios Name Query Request.
diff --git a/chrome/browser/ash/tether/tether_service.cc b/chrome/browser/ash/tether/tether_service.cc
index 3f49a16..b6ff1b2e 100644
--- a/chrome/browser/ash/tether/tether_service.cc
+++ b/chrome/browser/ash/tether/tether_service.cc
@@ -108,7 +108,7 @@
       notification_presenter_(
           std::make_unique<chromeos::tether::TetherNotificationPresenter>(
               profile_,
-              chromeos::NetworkConnect::Get())),
+              NetworkConnect::Get())),
       gms_core_notifications_state_tracker_(
           std::make_unique<GmsCoreNotificationsStateTrackerImpl>()),
       tether_host_fetcher_(
@@ -156,7 +156,7 @@
       gms_core_notifications_state_tracker_.get(), profile_->GetPrefs(),
       network_state_handler_,
       chromeos::NetworkHandler::Get()->managed_network_configuration_handler(),
-      chromeos::NetworkConnect::Get(),
+      NetworkConnect::Get(),
       chromeos::NetworkHandler::Get()->network_connection_handler(), adapter_,
       session_manager_);
 }
diff --git a/chrome/browser/ash/tether/tether_service_unittest.cc b/chrome/browser/ash/tether/tether_service_unittest.cc
index 2c58dcfb..11a9101 100644
--- a/chrome/browser/ash/tether/tether_service_unittest.cc
+++ b/chrome/browser/ash/tether/tether_service_unittest.cc
@@ -155,7 +155,7 @@
       PrefService* pref_service,
       chromeos::NetworkStateHandler* network_state_handler,
       ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
-      chromeos::NetworkConnect* network_connect,
+      NetworkConnect* network_connect,
       NetworkConnectionHandler* network_connection_handler,
       scoped_refptr<device::BluetoothAdapter> adapter,
       session_manager::SessionManager* session_manager) override {
@@ -297,7 +297,7 @@
     fake_notification_presenter_ = nullptr;
     mock_timer_ = nullptr;
 
-    chromeos::NetworkConnect::Initialize(nullptr);
+    NetworkConnect::Initialize(nullptr);
 
     TestingProfile::Builder builder;
     profile_ = builder.Build();
@@ -391,7 +391,7 @@
               shutdown_reason_verified_);
 
     chromeos::PowerManagerClient::Shutdown();
-    chromeos::NetworkConnect::Shutdown();
+    NetworkConnect::Shutdown();
   }
 
   void SetPrimaryUserLoggedIn() {
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index a6a57bd..9c385fb 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -219,14 +219,16 @@
        // TODO(crbug.com/1150895) Remove once launched.
        features::kAutofillParsingPatternProvider,
        features::kAutofillPageLanguageDetection,
-       // TODO(crbug/1165780): Remove once shared labels are launched.
+       // TODO(crbug.com/1165780): Remove once shared labels are launched.
        features::kAutofillEnableSupportForParsingWithSharedLabels,
        // TODO(crbug.com/1277480): Remove once launched.
        features::kAutofillEnableNameSurenameParsing,
        // TODO(crbug.com/1190334): Remove once launched.
        features::kAutofillParseMerchantPromoCodeFields,
        // TODO(crbug.com/1113970): Remove once launched.
-       features::kAutofillSectionUponRedundantNameInfo},
+       features::kAutofillSectionUponRedundantNameInfo,
+       // TODO(crbug.com/1335549): Remove once launched.
+       features::kAutofillParseIBANFields},
       // Disabled
       {});
 }
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc
index 8f049847..bf594177 100644
--- a/chrome/browser/certificate_manager_model.cc
+++ b/chrome/browser/certificate_manager_model.cc
@@ -304,7 +304,7 @@
 #if BUILDFLAG(IS_CHROMEOS)
 // Provides certificates installed through enterprise policy.
 class CertsSourcePolicy : public CertificateManagerModel::CertsSource,
-                          chromeos::PolicyCertificateProvider::Observer {
+                          ash::PolicyCertificateProvider::Observer {
  public:
   // Defines which policy-provided certificates this CertsSourcePolicy instance
   // should yield.
@@ -318,7 +318,7 @@
   };
 
   CertsSourcePolicy(base::RepeatingClosure certs_source_updated_callback,
-                    chromeos::PolicyCertificateProvider* policy_certs_provider,
+                    ash::PolicyCertificateProvider* policy_certs_provider,
                     Mode mode)
       : CertsSource(certs_source_updated_callback),
         policy_certs_provider_(policy_certs_provider),
@@ -333,7 +333,7 @@
     policy_certs_provider_->RemovePolicyProvidedCertsObserver(this);
   }
 
-  // chromeos::PolicyCertificateProvider::Observer
+  // ash::PolicyCertificateProvider::Observer
   void OnPolicyProvidedCertsChanged() override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     Refresh();
@@ -400,7 +400,7 @@
     SetCertInfos(std::move(cert_infos));
   }
 
-  raw_ptr<chromeos::PolicyCertificateProvider> policy_certs_provider_;
+  raw_ptr<ash::PolicyCertificateProvider> policy_certs_provider_;
   Mode mode_;
 };
 
diff --git a/chrome/browser/certificate_manager_model.h b/chrome/browser/certificate_manager_model.h
index 1b7236b0..5f7a7f1 100644
--- a/chrome/browser/certificate_manager_model.h
+++ b/chrome/browser/certificate_manager_model.h
@@ -24,10 +24,13 @@
 }  // namespace content
 
 #if BUILDFLAG(IS_CHROMEOS)
+namespace ash {
+class PolicyCertificateProvider;
+}
+
 namespace chromeos {
 class CertificateProvider;
-class PolicyCertificateProvider;
-}  // namespace chromeos
+}
 #endif
 
 // CertificateManagerModel provides the data to be displayed in the certificate
@@ -126,8 +129,7 @@
   struct Params {
 #if BUILDFLAG(IS_CHROMEOS)
     // May be nullptr.
-    raw_ptr<chromeos::PolicyCertificateProvider> policy_certs_provider =
-        nullptr;
+    raw_ptr<ash::PolicyCertificateProvider> policy_certs_provider = nullptr;
     // May be nullptr.
     std::unique_ptr<chromeos::CertificateProvider>
         extension_certificate_provider;
diff --git a/chrome/browser/certificate_manager_model_unittest.cc b/chrome/browser/certificate_manager_model_unittest.cc
index 9a89095..4ce8c12 100644
--- a/chrome/browser/certificate_manager_model_unittest.cc
+++ b/chrome/browser/certificate_manager_model_unittest.cc
@@ -207,8 +207,7 @@
 #if BUILDFLAG(IS_CHROMEOS)
 namespace {
 
-class FakePolicyCertificateProvider
-    : public chromeos::PolicyCertificateProvider {
+class FakePolicyCertificateProvider : public ash::PolicyCertificateProvider {
  public:
   void AddPolicyProvidedCertsObserver(Observer* observer) override {
     observer_list_.AddObserver(observer);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 297d79b7..0b229d3 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -6494,10 +6494,14 @@
     return true;
   } else if (sandbox_type == sandbox::mojom::Sandbox::kScreenAI) {
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
-    base::FilePath screen_ai_component_path =
-        screen_ai::GetLatestLibraryFilePath();
-    if (screen_ai_component_path.empty())
+    // ScreenAI service needs read access to ScreenAI component path, so that it
+    // would be able to find the latest downloaded version, and load its binary
+    // and all enclosed model files.
+    base::FilePath screen_ai_component_path = screen_ai::GetComponentPath();
+    if (screen_ai_component_path.empty()) {
+      VLOG(1) << "Screen AI library not found.";
       return false;
+    }
 
     CHECK(client->SetParameter(sandbox::policy::kParamScreenAiComponentPath,
                                screen_ai_component_path.value()));
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 34c97cd..9b1f52f 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1391,8 +1391,6 @@
     "../ash/policy/reporting/metrics_reporting/metric_reporting_manager.h",
     "../ash/policy/reporting/metrics_reporting/network/https_latency_sampler.cc",
     "../ash/policy/reporting/metrics_reporting/network/https_latency_sampler.h",
-    "../ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.cc",
-    "../ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.h",
     "../ash/policy/reporting/metrics_reporting/network/network_events_observer.cc",
     "../ash/policy/reporting/metrics_reporting/network/network_events_observer.h",
     "../ash/policy/reporting/metrics_reporting/network/network_info_sampler.cc",
@@ -3274,7 +3272,6 @@
     "../ash/policy/reporting/metrics_reporting/cros_reporting_settings_unittest.cc",
     "../ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc",
     "../ash/policy/reporting/metrics_reporting/network/https_latency_sampler_unittest.cc",
-    "../ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler_unittest.cc",
     "../ash/policy/reporting/metrics_reporting/network/network_events_observer_unittest.cc",
     "../ash/policy/reporting/metrics_reporting/network/network_info_sampler_unittest.cc",
     "../ash/policy/reporting/metrics_reporting/network/network_telemetry_sampler_unittest.cc",
diff --git a/chrome/browser/chromeos/launcher_search/search_util.cc b/chrome/browser/chromeos/launcher_search/search_util.cc
index 1affc5c..647bf24 100644
--- a/chrome/browser/chromeos/launcher_search/search_util.cc
+++ b/chrome/browser/chromeos/launcher_search/search_util.cc
@@ -89,6 +89,7 @@
     case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
     case AutocompleteMatchType::TILE_SUGGESTION:
     case AutocompleteMatchType::TILE_NAVSUGGEST:
+    case AutocompleteMatchType::NULL_RESULT_MESSAGE:
     case AutocompleteMatchType::NUM_TYPES:
       // Not reached.
       return SearchResult::OmniboxType::kDomain;
diff --git a/chrome/browser/chromeos/reporting/OWNERS b/chrome/browser/chromeos/reporting/OWNERS
new file mode 100644
index 0000000..28e4985
--- /dev/null
+++ b/chrome/browser/chromeos/reporting/OWNERS
@@ -0,0 +1 @@
+file://components/reporting/OWNERS
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.cc b/chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.cc
similarity index 93%
rename from chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.cc
rename to chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.cc
index 798ab24..a0859619 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.cc
+++ b/chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.h"
+#include "chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.h"
 
 #include <limits>
 
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.h b/chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.h
similarity index 81%
rename from chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.h
rename to chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.h
index f6fd307a..5aed788 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.h
+++ b/chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.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_ASH_POLICY_REPORTING_METRICS_REPORTING_NETWORK_NETWORK_BANDWIDTH_SAMPLER_H_
-#define CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_NETWORK_NETWORK_BANDWIDTH_SAMPLER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_REPORTING_NETWORK_NETWORK_BANDWIDTH_SAMPLER_H_
+#define CHROME_BROWSER_CHROMEOS_REPORTING_NETWORK_NETWORK_BANDWIDTH_SAMPLER_H_
 
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/profiles/profile.h"
@@ -37,4 +37,4 @@
 
 }  // namespace reporting
 
-#endif  // CHROME_BROWSER_ASH_POLICY_REPORTING_METRICS_REPORTING_NETWORK_NETWORK_BANDWIDTH_SAMPLER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_REPORTING_NETWORK_NETWORK_BANDWIDTH_SAMPLER_H_
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler_unittest.cc b/chrome/browser/chromeos/reporting/network/network_bandwidth_sampler_unittest.cc
similarity index 97%
rename from chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler_unittest.cc
rename to chrome/browser/chromeos/reporting/network/network_bandwidth_sampler_unittest.cc
index 072b2f2..23ebc41 100644
--- a/chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler_unittest.cc
+++ b/chrome/browser/chromeos/reporting/network/network_bandwidth_sampler_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ash/policy/reporting/metrics_reporting/network/network_bandwidth_sampler.h"
+#include "chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.h"
 
 #include "base/test/task_environment.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc b/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc
index ad2d9dd..4f231bd 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc
@@ -17,7 +17,7 @@
 
 void NetworkingPrivateUIDelegateChromeOS::ShowAccountDetails(
     const std::string& guid) const {
-  chromeos::NetworkConnect::Get()->ShowCarrierAccountDetail(guid);
+  ash::NetworkConnect::Get()->ShowCarrierAccountDetail(guid);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java
index d8ec0d8..6cd1962 100644
--- a/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java
+++ b/chrome/browser/feature_engagement/java/src/org/chromium/chrome/browser/feature_engagement/TrackerFactory.java
@@ -29,7 +29,9 @@
      */
     public static Tracker getTrackerForProfile(Profile profile) {
         if (sTestTracker != null) return sTestTracker;
-        if (profile == null) return null;
+        if (profile == null) {
+            throw new IllegalArgumentException("Profile is required for retrieving tracker.");
+        }
 
         return TrackerFactoryJni.get().getTrackerForProfile(profile);
     }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 1afb375f..2045ce9 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -5309,6 +5309,11 @@
     "expiry_milestone": 110
   },
   {
+    "name": "qs-revamp",
+    "owners": ["jiamingc","amehfooz", "newcomer"],
+    "expiry_milestone" : 116
+  },
+  {
     "name": "query-tiles",
     "owners": [ "shaktisahu", "qinmin" ],
     "expiry_milestone": 120
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 3c7fe532..aec7349 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -5588,6 +5588,10 @@
 const char kProjectorExcludeTranscriptDescription[] =
     "Support excluding segment of Projector recording by excluding transcript";
 
+const char kQsRevampName[] = "Quick Settings Revamp";
+const char kQsRevampDescription[] =
+    "Enable QS UI revamp with separated message center.";
+
 const char kReleaseNotesNotificationAllChannelsName[] =
     "Release Notes Notification All Channels";
 const char kReleaseNotesNotificationAllChannelsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 4163b8a..46c2ef0 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -3199,6 +3199,9 @@
 extern const char kProjectorExcludeTranscriptName[];
 extern const char kProjectorExcludeTranscriptDescription[];
 
+extern const char kQsRevampName[];
+extern const char kQsRevampDescription[];
+
 extern const char kReleaseNotesNotificationAllChannelsName[];
 extern const char kReleaseNotesNotificationAllChannelsDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 1200872f..a27fa642 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -378,6 +378,7 @@
     &privacy_sandbox::kPrivacySandboxSettings3,
     &query_tiles::features::kQueryTiles,
     &query_tiles::features::kQueryTilesInNTP,
+    &query_tiles::features::kQueryTilesOnStart,
     &query_tiles::features::kQueryTilesSegmentation,
     &reading_list::switches::kReadLater,
     &safe_browsing::kCreateSafebrowsingOnStartup,
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
index ff0ecfd..29f9f01 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
@@ -86,6 +86,7 @@
                     .put(ChromeFeatureList.PAINT_PREVIEW_DEMO, false)
                     .put(ChromeFeatureList.PAINT_PREVIEW_SHOW_ON_STARTUP, false)
                     .put(ChromeFeatureList.QUERY_TILES, false)
+                    .put(ChromeFeatureList.QUERY_TILES_ON_START, false)
                     .put(ChromeFeatureList.PREFETCH_NOTIFICATION_SCHEDULING_INTEGRATION, false)
                     .put(ChromeFeatureList.READ_LATER, false)
                     .put(ChromeFeatureList.START_SURFACE_ANDROID, false)
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index b83c738..b725687 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -484,6 +484,7 @@
     public static final String PWA_UPDATE_DIALOG_FOR_NAME = "PwaUpdateDialogForName";
     public static final String QUERY_TILES = "QueryTiles";
     public static final String QUERY_TILES_IN_NTP = "QueryTilesInNTP";
+    public static final String QUERY_TILES_ON_START = "QueryTilesOnStart";
     public static final String QUERY_TILES_SEGMENTATION = "QueryTilesSegmentation";
     public static final String QUICK_ACTION_SEARCH_WIDGET = "QuickActionSearchWidgetAndroid";
     public static final String QUIET_NOTIFICATION_PROMPTS = "QuietNotificationPrompts";
@@ -663,6 +664,7 @@
     public static final CachedFlag sPrefetchNotificationSchedulingIntegration =
             new CachedFlag(PREFETCH_NOTIFICATION_SCHEDULING_INTEGRATION, false);
     public static final CachedFlag sQueryTiles = new CachedFlag(QUERY_TILES, false);
+    public static final CachedFlag sQueryTilesOnStart = new CachedFlag(QUERY_TILES_ON_START, false);
     public static final CachedFlag sReadLater = new CachedFlag(READ_LATER, false);
     public static final CachedFlag sStartSurfaceAndroid =
             new CachedFlag(START_SURFACE_ANDROID, false);
diff --git a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.cc b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.cc
index 0761ee8..c50043b 100644
--- a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.cc
+++ b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.cc
@@ -7,7 +7,7 @@
 #include "chromeos/ash/components/network/firewall_hole.h"
 
 NearbyConnectionsFirewallHole::NearbyConnectionsFirewallHole(
-    std::unique_ptr<chromeos::FirewallHole> firewall_hole)
+    std::unique_ptr<ash::FirewallHole> firewall_hole)
     : firewall_hole_(std::move(firewall_hole)) {}
 
 NearbyConnectionsFirewallHole::~NearbyConnectionsFirewallHole() = default;
diff --git a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.h b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.h
index d93dce17..2f8b060 100644
--- a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.h
+++ b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole.h
@@ -9,24 +9,24 @@
 
 #include "ash/services/nearby/public/mojom/firewall_hole.mojom.h"
 
-namespace chromeos {
+namespace ash {
 class FirewallHole;
-}  // namespace chromeos
+}
 
 // An implementation of the mojo interface representing a firewall hole for
 // Nearby Connections WifiLan TCP sockets. This implementation is essentially a
-// wrapper around a chromeos::FirewallHole.
+// wrapper around a ash::FirewallHole.
 class NearbyConnectionsFirewallHole : public sharing::mojom::FirewallHole {
  public:
   explicit NearbyConnectionsFirewallHole(
-      std::unique_ptr<chromeos::FirewallHole> firewall_hole);
+      std::unique_ptr<ash::FirewallHole> firewall_hole);
   NearbyConnectionsFirewallHole(const NearbyConnectionsFirewallHole&) = delete;
   NearbyConnectionsFirewallHole& operator=(
       const NearbyConnectionsFirewallHole&) = delete;
   ~NearbyConnectionsFirewallHole() override;
 
  private:
-  std::unique_ptr<chromeos::FirewallHole> firewall_hole_;
+  std::unique_ptr<ash::FirewallHole> firewall_hole_;
 };
 
 #endif  // CHROME_BROWSER_NEARBY_SHARING_FIREWALL_HOLE_NEARBY_CONNECTIONS_FIREWALL_HOLE_H_
diff --git a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.cc b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.cc
index 4f7a416..d6daf93 100644
--- a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.cc
+++ b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.cc
@@ -23,8 +23,8 @@
 void NearbyConnectionsFirewallHoleFactory::OpenFirewallHole(
     const ash::nearby::TcpServerSocketPort& port,
     OpenFirewallHoleCallback callback) {
-  chromeos::FirewallHole::Open(
-      chromeos::FirewallHole::PortType::TCP, port.port(),
+  ash::FirewallHole::Open(
+      ash::FirewallHole::PortType::TCP, port.port(),
       /*interface=*/std::string(),
       base::BindOnce(
           &NearbyConnectionsFirewallHoleFactory::OnFirewallHoleOpened,
@@ -34,7 +34,7 @@
 void NearbyConnectionsFirewallHoleFactory::OnFirewallHoleOpened(
     const ash::nearby::TcpServerSocketPort& port,
     OpenFirewallHoleCallback callback,
-    std::unique_ptr<chromeos::FirewallHole> firewall_hole) {
+    std::unique_ptr<ash::FirewallHole> firewall_hole) {
   if (!firewall_hole) {
     LOG(ERROR) << "NearbyConnectionsFirewallHoleFactory::" << __func__
                << ": Failed to open TCP firewall hole on port " << port.port();
diff --git a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h
index d52c981..6641dbe 100644
--- a/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h
+++ b/chrome/browser/nearby_sharing/firewall_hole/nearby_connections_firewall_hole_factory.h
@@ -12,18 +12,15 @@
 #include "mojo/public/cpp/bindings/unique_receiver_set.h"
 
 namespace ash {
+class FirewallHole;
 namespace nearby {
 class TcpServerSocketPort;
 }  // namespace nearby
 }  // namespace ash
 
-namespace chromeos {
-class FirewallHole;
-}  // namespace chromeos
-
 // An implementation of the mojo service used to open firewall holes for Nearby
 // Connections WifiLan TCP sockets. This implementation is essentially a wrapper
-// around chromeos::FirewallHole::Open(). The lifetime of a firewall hole
+// around ash::FirewallHole::Open(). The lifetime of a firewall hole
 // mirrors the lifetime of the mojo remote provided by OpenFirewallHole(); the
 // corresponding mojo receivers are owned by |firewall_hole_receivers_|.
 class NearbyConnectionsFirewallHoleFactory
@@ -40,10 +37,9 @@
                         OpenFirewallHoleCallback callback) override;
 
  private:
-  void OnFirewallHoleOpened(
-      const ash::nearby::TcpServerSocketPort& port,
-      OpenFirewallHoleCallback callback,
-      std::unique_ptr<chromeos::FirewallHole> firewall_hole);
+  void OnFirewallHoleOpened(const ash::nearby::TcpServerSocketPort& port,
+                            OpenFirewallHoleCallback callback,
+                            std::unique_ptr<ash::FirewallHole> firewall_hole);
 
   mojo::UniqueReceiverSet<sharing::mojom::FirewallHole>
       firewall_hole_receivers_;
diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc
index 3ff2b45..4eae261 100644
--- a/chrome/browser/net/proxy_service_factory.cc
+++ b/chrome/browser/net/proxy_service_factory.cc
@@ -46,7 +46,7 @@
         std::make_unique<chromeos::ProxyConfigServiceLacros>(profile);
   }
 #elif !BUILDFLAG(IS_CHROMEOS_ASH)
-  // On Ash-Chrome, base service is NULL; chromeos::ProxyConfigServiceImpl
+  // On Ash-Chrome, base service is NULL; ash::ProxyConfigServiceImpl
   // determines the effective proxy config to take effect in the network layer,
   // be it from prefs or system (which is network shill on chromeos).
 
@@ -67,7 +67,7 @@
     PrefService* profile_prefs,
     PrefService* local_state_prefs) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  return std::make_unique<chromeos::ProxyConfigServiceImpl>(
+  return std::make_unique<ash::ProxyConfigServiceImpl>(
       profile_prefs, local_state_prefs, nullptr);
 #else
   return std::make_unique<PrefProxyConfigTrackerImpl>(profile_prefs, nullptr);
@@ -79,7 +79,7 @@
 ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
     PrefService* local_state_prefs) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  return std::make_unique<chromeos::ProxyConfigServiceImpl>(
+  return std::make_unique<ash::ProxyConfigServiceImpl>(
       nullptr, local_state_prefs, nullptr);
 #else
   return std::make_unique<PrefProxyConfigTrackerImpl>(local_state_prefs,
diff --git a/chrome/browser/page_load_metrics/observers/README.md b/chrome/browser/page_load_metrics/observers/README.md
index 837fece..f10e551 100644
--- a/chrome/browser/page_load_metrics/observers/README.md
+++ b/chrome/browser/page_load_metrics/observers/README.md
@@ -9,6 +9,7 @@
 For a quick introduction, you may wish to read the [implementation basics](#implementation-basics)
 section below, browse the [`PageLoadMetricsObserver`](/components/page_load_metrics/browser/page_load_metrics_observer.h)
 interface, and look over [existing `PageLoadMetricsObserver` implementations](/chrome/browser/page_load_metrics/observers/).
+You can refer [`AssertPageLoadMetricsObserver`](/components/page_load_metrics/browser/observers/assert_page_load_metrics_observer.h) for context and assumptions that callbacks can be rely on.
 
 `PageLoadMetricsObserver`s can track [web vitals](https://web.dev/vitals/) like time to [Largest Contentful Paint](https://web.dev/lcp) and other per-page metrics such as time to first user input in [UMA](/tools/metrics/histograms/README.md) or [UKM](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/services/metrics/ukm_api.md).
 
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index ea65825b..78c7a7e 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -46,6 +46,7 @@
 #include "components/no_state_prefetch/browser/no_state_prefetch_contents.h"
 #include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
 #include "components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h"
+#include "components/page_load_metrics/browser/observers/assert_page_load_metrics_observer.h"
 #include "components/page_load_metrics/browser/page_load_metrics_embedder_base.h"
 #include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h"
 #include "components/page_load_metrics/browser/page_load_tracker.h"
@@ -109,6 +110,10 @@
 
 void PageLoadMetricsEmbedder::RegisterEmbedderObservers(
     page_load_metrics::PageLoadTracker* tracker) {
+#if DCHECK_IS_ON()
+  tracker->AddObserver(std::make_unique<AssertPageLoadMetricsObserver>());
+#endif
+
   // TODO(crbug.com/1299103): Integrate side panel metrics with UKM.
   if (IsSidePanel(web_contents())) {
 #if defined(TOOLKIT_VIEWS)
diff --git a/chrome/browser/policy/networking/network_configuration_updater.cc b/chrome/browser/policy/networking/network_configuration_updater.cc
index f651f05..1120a3e 100644
--- a/chrome/browser/policy/networking/network_configuration_updater.cc
+++ b/chrome/browser/policy/networking/network_configuration_updater.cc
@@ -81,12 +81,12 @@
 }
 
 void NetworkConfigurationUpdater::AddPolicyProvidedCertsObserver(
-    chromeos::PolicyCertificateProvider::Observer* observer) {
+    ash::PolicyCertificateProvider::Observer* observer) {
   observer_list_.AddObserver(observer);
 }
 
 void NetworkConfigurationUpdater::RemovePolicyProvidedCertsObserver(
-    chromeos::PolicyCertificateProvider::Observer* observer) {
+    ash::PolicyCertificateProvider::Observer* observer) {
   observer_list_.RemoveObserver(observer);
 }
 
diff --git a/chrome/browser/policy/networking/network_configuration_updater.h b/chrome/browser/policy/networking/network_configuration_updater.h
index 7850762..8bbe949 100644
--- a/chrome/browser/policy/networking/network_configuration_updater.h
+++ b/chrome/browser/policy/networking/network_configuration_updater.h
@@ -34,7 +34,7 @@
 // (that will be propagated to the network service). Provides entry points for
 // handling client certificates and network configurations in subclasses.
 // Does not handle proxy settings.
-class NetworkConfigurationUpdater : public chromeos::PolicyCertificateProvider,
+class NetworkConfigurationUpdater : public ash::PolicyCertificateProvider,
                                     public PolicyService::Observer {
  public:
   NetworkConfigurationUpdater(const NetworkConfigurationUpdater&) = delete;
@@ -51,11 +51,11 @@
 
   // The observer interface sends notifications about changes in server and
   // authority certificates.
-  // chromeos::PolicyCertificateProvider:
+  // ash::PolicyCertificateProvider:
   void AddPolicyProvidedCertsObserver(
-      chromeos::PolicyCertificateProvider::Observer* observer) override;
+      ash::PolicyCertificateProvider::Observer* observer) override;
   void RemovePolicyProvidedCertsObserver(
-      chromeos::PolicyCertificateProvider::Observer* observer) override;
+      ash::PolicyCertificateProvider::Observer* observer) override;
   net::CertificateList GetAllServerAndAuthorityCertificates(
       const chromeos::onc::CertificateScope& scope) const override;
   net::CertificateList GetAllAuthorityCertificates(
@@ -149,8 +149,8 @@
 
   // Observer list for notifying about ONC-provided server and CA certificate
   // changes.
-  base::ObserverList<chromeos::PolicyCertificateProvider::Observer,
-                     true>::Unchecked observer_list_;
+  base::ObserverList<ash::PolicyCertificateProvider::Observer, true>::Unchecked
+      observer_list_;
 };
 
 }  // namespace policy
diff --git a/chrome/browser/policy/networking/network_configuration_updater_ash_unittest.cc b/chrome/browser/policy/networking/network_configuration_updater_ash_unittest.cc
index cb92023d..df7ab93 100644
--- a/chrome/browser/policy/networking/network_configuration_updater_ash_unittest.cc
+++ b/chrome/browser/policy/networking/network_configuration_updater_ash_unittest.cc
@@ -88,7 +88,7 @@
 };
 
 class MockPolicyProvidedCertsObserver
-    : public chromeos::PolicyCertificateProvider::Observer {
+    : public ash::PolicyCertificateProvider::Observer {
  public:
   MockPolicyProvidedCertsObserver() = default;
 
diff --git a/chrome/browser/policy/networking/network_configuration_updater_unittest.cc b/chrome/browser/policy/networking/network_configuration_updater_unittest.cc
index 55a990e..4623f33a5 100644
--- a/chrome/browser/policy/networking/network_configuration_updater_unittest.cc
+++ b/chrome/browser/policy/networking/network_configuration_updater_unittest.cc
@@ -37,7 +37,7 @@
 namespace {
 
 class MockPolicyProvidedCertsObserver
-    : public chromeos::PolicyCertificateProvider::Observer {
+    : public ash::PolicyCertificateProvider::Observer {
  public:
   MockPolicyProvidedCertsObserver() = default;
 
diff --git a/chrome/browser/policy/networking/policy_cert_service.cc b/chrome/browser/policy/networking/policy_cert_service.cc
index 0b9eac9..0c2fd14 100644
--- a/chrome/browser/policy/networking/policy_cert_service.cc
+++ b/chrome/browser/policy/networking/policy_cert_service.cc
@@ -36,7 +36,7 @@
 
 PolicyCertService::PolicyCertService(
     Profile* profile,
-    chromeos::PolicyCertificateProvider* policy_certificate_provider,
+    ash::PolicyCertificateProvider* policy_certificate_provider,
     bool may_use_profile_wide_trust_anchors)
     : profile_(profile),
       policy_certificate_provider_(policy_certificate_provider),
diff --git a/chrome/browser/policy/networking/policy_cert_service.h b/chrome/browser/policy/networking/policy_cert_service.h
index 6e47482..b3c6039 100644
--- a/chrome/browser/policy/networking/policy_cert_service.h
+++ b/chrome/browser/policy/networking/policy_cert_service.h
@@ -38,17 +38,16 @@
 // This service / its factory keep track of which Profile has used a
 // policy-provided trust anchor.
 class PolicyCertService : public KeyedService,
-                          public chromeos::PolicyCertificateProvider::Observer {
+                          public ash::PolicyCertificateProvider::Observer {
  public:
   // Constructs a PolicyCertService for |profile| using
   // |policy_certificate_provider| as the source of certificates.
   // If |may_use_profile_wide_trust_anchors| is true, certificates from
   // |policy_certificate_provider| that have requested "Web" trust and have
   // profile-wide scope will be used for |profile|.
-  PolicyCertService(
-      Profile* profile,
-      chromeos::PolicyCertificateProvider* policy_certificate_provider,
-      bool may_use_profile_wide_trust_anchors);
+  PolicyCertService(Profile* profile,
+                    ash::PolicyCertificateProvider* policy_certificate_provider,
+                    bool may_use_profile_wide_trust_anchors);
 
   PolicyCertService(const PolicyCertService&) = delete;
   PolicyCertService& operator=(const PolicyCertService&) = delete;
@@ -104,8 +103,7 @@
   const raw_ptr<Profile> profile_;
 
   // The source of certificates for this PolicyCertService.
-  const raw_ptr<chromeos::PolicyCertificateProvider>
-      policy_certificate_provider_;
+  const raw_ptr<ash::PolicyCertificateProvider> policy_certificate_provider_;
 
   // If true, CA certificates |policy_certificate_provider_| that have requested
   // "Web" trust and have profile-wide scope may be used for |profile_|.
diff --git a/chrome/browser/policy/networking/policy_cert_service_factory.cc b/chrome/browser/policy/networking/policy_cert_service_factory.cc
index ae0d371..d6d408a 100644
--- a/chrome/browser/policy/networking/policy_cert_service_factory.cc
+++ b/chrome/browser/policy/networking/policy_cert_service_factory.cc
@@ -33,8 +33,7 @@
 // Returns the PolicyCertificateProvider that should be used for |profile|.
 // May return nullptr, which should be treated as no policy-provided
 // certificates set.
-chromeos::PolicyCertificateProvider* GetPolicyCertificateProvider(
-    Profile* profile) {
+ash::PolicyCertificateProvider* GetPolicyCertificateProvider(Profile* profile) {
   if (ash::ProfileHelper::Get()->IsSigninProfile(profile)) {
     return g_browser_process->platform_part()
         ->browser_policy_connector_ash()
@@ -47,7 +46,7 @@
 KeyedService* BuildServiceInstanceAsh(content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
 
-  chromeos::PolicyCertificateProvider* policy_certificate_provider =
+  ash::PolicyCertificateProvider* policy_certificate_provider =
       GetPolicyCertificateProvider(profile);
   if (!policy_certificate_provider)
     return nullptr;
@@ -87,7 +86,7 @@
 KeyedService* BuildServiceInstanceLacros(content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
 
-  chromeos::PolicyCertificateProvider* policy_certificate_provider =
+  ash::PolicyCertificateProvider* policy_certificate_provider =
       UserNetworkConfigurationUpdaterFactory::GetForBrowserContext(profile);
   if (!policy_certificate_provider)
     return nullptr;
diff --git a/chrome/browser/policy/networking/user_network_configuration_updater_ash.cc b/chrome/browser/policy/networking/user_network_configuration_updater_ash.cc
index 98baf39..116b21e 100644
--- a/chrome/browser/policy/networking/user_network_configuration_updater_ash.cc
+++ b/chrome/browser/policy/networking/user_network_configuration_updater_ash.cc
@@ -49,9 +49,8 @@
 
 UserNetworkConfigurationUpdaterAsh::~UserNetworkConfigurationUpdaterAsh() {
   // NetworkCertLoader may be not initialized in tests.
-  if (chromeos::NetworkCertLoader::IsInitialized()) {
-    chromeos::NetworkCertLoader::Get()->SetUserPolicyCertificateProvider(
-        nullptr);
+  if (ash::NetworkCertLoader::IsInitialized()) {
+    ash::NetworkCertLoader::Get()->SetUserPolicyCertificateProvider(nullptr);
   }
 }
 
@@ -126,8 +125,8 @@
   // primary profile. This assumes that a |UserNetworkConfigurationUpdaterAsh|
   // is only created for the primary profile. NetworkCertLoader may be not
   // initialized in tests.
-  if (chromeos::NetworkCertLoader::IsInitialized())
-    chromeos::NetworkCertLoader::Get()->SetUserPolicyCertificateProvider(this);
+  if (ash::NetworkCertLoader::IsInitialized())
+    ash::NetworkCertLoader::Get()->SetUserPolicyCertificateProvider(this);
 
   // Set profile-wide expansions for policy networks (i.e. those that apply to
   // all networks in this profile). Note that this does currently not apply
diff --git a/chrome/browser/policy/test/policy_certs_browsertest.cc b/chrome/browser/policy/test/policy_certs_browsertest.cc
index d20a368..c3f88f1d 100644
--- a/chrome/browser/policy/test/policy_certs_browsertest.cc
+++ b/chrome/browser/policy/test/policy_certs_browsertest.cc
@@ -79,7 +79,7 @@
 // Allows waiting until the list of policy-pushed web-trusted certificates
 // changes.
 class WebTrustedCertsChangedObserver
-    : public chromeos::PolicyCertificateProvider::Observer {
+    : public ash::PolicyCertificateProvider::Observer {
  public:
   WebTrustedCertsChangedObserver() = default;
 
@@ -88,7 +88,7 @@
   WebTrustedCertsChangedObserver& operator=(
       const WebTrustedCertsChangedObserver&) = delete;
 
-  // chromeos::PolicyCertificateProvider::Observer
+  // ash::PolicyCertificateProvider::Observer
   void OnPolicyProvidedCertsChanged() override { run_loop_.Quit(); }
 
   void Wait() { run_loop_.Run(); }
@@ -98,11 +98,10 @@
 };
 
 // Allows waiting until |NetworkCertLoader| updates its list of certificates.
-class NetworkCertLoaderTestObserver
-    : public chromeos::NetworkCertLoader::Observer {
+class NetworkCertLoaderTestObserver : public ash::NetworkCertLoader::Observer {
  public:
   explicit NetworkCertLoaderTestObserver(
-      chromeos::NetworkCertLoader* network_cert_loader)
+      ash::NetworkCertLoader* network_cert_loader)
       : network_cert_loader_(network_cert_loader) {
     network_cert_loader_->AddObserver(this);
   }
@@ -115,13 +114,13 @@
     network_cert_loader_->RemoveObserver(this);
   }
 
-  // chromeos::NetworkCertLoader::Observer
+  // ash::NetworkCertLoader::Observer
   void OnCertificatesLoaded() override { run_loop_.Quit(); }
 
   void Wait() { run_loop_.Run(); }
 
  private:
-  raw_ptr<chromeos::NetworkCertLoader> network_cert_loader_;
+  raw_ptr<ash::NetworkCertLoader> network_cert_loader_;
   base::RunLoop run_loop_;
 };
 
@@ -540,7 +539,7 @@
 
 bool IsCertInCertificateList(
     const net::X509Certificate* cert,
-    const chromeos::NetworkCertLoader::NetworkCertList& network_cert_list) {
+    const ash::NetworkCertLoader::NetworkCertList& network_cert_list) {
   for (const auto& network_cert : network_cert_list) {
     if (net::x509_util::IsSameCertificate(network_cert.cert(), cert))
       return true;
@@ -554,14 +553,14 @@
   // properly initialized because |UserSessionManager| only sets the primary
   // user's NSS Database in |NetworkCertLoader| if running on ChromeOS according
   // to |base::SysInfo|.
-  ASSERT_TRUE(chromeos::NetworkCertLoader::IsInitialized());
-  chromeos::NetworkCertLoader::Get()->SetUserNSSDB(test_nss_cert_db_.get());
+  ASSERT_TRUE(ash::NetworkCertLoader::IsInitialized());
+  ash::NetworkCertLoader::Get()->SetUserNSSDB(test_nss_cert_db_.get());
 
   EXPECT_FALSE(IsCertInCertificateList(
       user_policy_certs_helper_.root_cert().get(),
-      chromeos::NetworkCertLoader::Get()->authority_certs()));
+      ash::NetworkCertLoader::Get()->authority_certs()));
   NetworkCertLoaderTestObserver network_cert_loader_observer(
-      chromeos::NetworkCertLoader::Get());
+      ash::NetworkCertLoader::Get());
   user_policy_certs_helper_.SetRootCertONCUserPolicy(
       multi_profile_policy_helper_.profile_1(),
       multi_profile_policy_helper_.policy_for_profile_1());
@@ -572,7 +571,7 @@
   // set a policy with a certificate requesting Web Trust here).
   EXPECT_TRUE(IsCertInCertificateList(
       user_policy_certs_helper_.root_cert().get(),
-      chromeos::NetworkCertLoader::Get()->authority_certs()));
+      ash::NetworkCertLoader::Get()->authority_certs()));
 }
 
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index f655316..05e0e136 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -237,6 +237,12 @@
     public static final String DEFAULT_BROWSER_PROMO_PROMOED_BY_SYSTEM_SETTINGS =
             "Chrome.DefaultBrowserPromo.PromoedBySystemSettings";
 
+    /**
+     * Indicates whether the desktop site global setting was enabled by default for a device.
+     */
+    public static final String DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING =
+            "Chrome.RequestDesktopSiteGlobalSetting.DefaultEnabled";
+
     public static final String DOWNLOAD_AUTO_RESUMPTION_ATTEMPT_LEFT = "ResumptionAttemptLeft";
     public static final String DOWNLOAD_FOREGROUND_SERVICE_OBSERVERS = "ForegroundServiceObservers";
     public static final String DOWNLOAD_IS_DOWNLOAD_HOME_ENABLED =
@@ -1012,6 +1018,7 @@
                 DEFAULT_BROWSER_PROMO_PROMOED_BY_SYSTEM_SETTINGS,
                 DEFAULT_BROWSER_PROMO_PROMOED_COUNT,
                 DEFAULT_BROWSER_PROMO_SESSION_COUNT,
+                DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING,
                 DOWNLOAD_INTERSTITIAL_DOWNLOAD_PENDING_REMOVAL,
                 EXPLORE_OFFLINE_CONTENT_AVAILABILITY_STATUS,
                 FEED_ARTICLES_LIST_VISIBLE,
diff --git a/chrome/browser/resources/ntp4/apps_page.js b/chrome/browser/resources/ntp4/apps_page.js
index 8af16a1..cb705f3 100644
--- a/chrome/browser/resources/ntp4/apps_page.js
+++ b/chrome/browser/resources/ntp4/apps_page.js
@@ -333,6 +333,7 @@
     assert(this.appData_.id, 'Got an app without an ID');
     this.id = this.appData_.id;
     this.setAttribute('role', 'menuitem');
+    this.setAttribute('aria-label', this.appData_.full_name);
 
     this.className = 'app focusable';
 
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html
index 3a528e1..95f80e78 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -69,7 +69,7 @@
             section="search">
           <settings-search-page prefs="{{prefs}}"></settings-search-page>
         </settings-section>
-<if expr="not chromeos_ash and not chromeos_lacros">
+<if expr="not is_chromeos">
         <template is="dom-if" if="[[showPage_(pageVisibility.defaultBrowser)]]"
             restamp>
           <settings-section page-title="$i18n{defaultBrowser}"
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.ts b/chrome/browser/resources/settings/basic_page/basic_page.ts
index 309877b..34a89e6 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.ts
+++ b/chrome/browser/resources/settings/basic_page/basic_page.ts
@@ -23,7 +23,7 @@
 import '../settings_page/settings_section.js';
 import '../settings_page_styles.css.js';
 
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 import '../default_browser_page/default_browser_page.js';
 // </if>
 
diff --git a/chrome/browser/resources/settings/chromeos/device_page/audio.html b/chrome/browser/resources/settings/chromeos/device_page/audio.html
index a65bfd5..b259044 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/audio.html
+++ b/chrome/browser/resources/settings/chromeos/device_page/audio.html
@@ -1,4 +1,4 @@
-<style include="settings-shared">
+<style include="settings-shared md-select">
   .audio-mute-button {
     margin-inline-end: var(--settings-control-label-spacing);
   }
@@ -67,10 +67,12 @@
 
 <!-- Output section -->
 <template is="dom-if" if="[[showAudioInfo]]">
+  <!-- TODO(crbug.com/1092970): Output section should be hidden if there are no
+  output devices. -->
   <div id="output">
     <h2 id="audioOutputTitle">$i18n{audioOutputTitle}</h2>
     <div id="audioOutputSubsection" class="subsection">
-      <div class="settings-box">
+      <div id="outputVolumeSubsection" class="settings-box">
         <div class="start settings-box-text" id="audioOutputVolumeLabel">
           $i18n{audioVolumeTitle}
         </div>
@@ -101,6 +103,20 @@
           </div>
         </div>
       </div>
+      <div id="outputDeviceSubsection" class="settings-box">
+        <div class="start settings-box-text" id="audioOutputDeviceLabel">
+          $i18n{audioDeviceTitle}
+        </div>
+        <select id="audioOutputDeviceDropdown" class="md-select"
+            aria-labelledby="audioOutputDeviceLabel">
+          <template is="dom-repeat"
+              items="[[audioSystemProperties_.outputDevices]]">
+            <option value="[[item.id]]" selected="[[item.isActive]]">
+              [[item.displayName]]
+            </option>
+          </template>
+        </select>
+      </div>
     </div>
   </div>
 </template>
diff --git a/chrome/browser/resources/settings/chromeos/device_page/audio.js b/chrome/browser/resources/settings/chromeos/device_page/audio.js
index 457f5fa6..c4a6a62 100644
--- a/chrome/browser/resources/settings/chromeos/device_page/audio.js
+++ b/chrome/browser/resources/settings/chromeos/device_page/audio.js
@@ -107,12 +107,6 @@
             .bindNewPipeAndPassRemote());
   }
 
-  // TODO(crbug.com/1092970): Create onCrSliderChanged_ method for setting
-  // output volume.
-
-  // TODO(crbug.com/1092970): Create onOutputMuteTap_ method for setting output
-  // mute state.
-
   /**
    * @protected
    * @return {boolean}
@@ -122,6 +116,15 @@
         MuteState.kMutedByPolicy;
   }
 
+  // TODO(crbug.com/1092970): Create onCrSliderChanged_ method for setting
+  // output volume.
+
+  // TODO(crbug.com/1092970): Create onOutputMuteTap_ method for setting output
+  // mute state.
+
+  // TODO(crbug.com/1092970): Create onOutputDeviceChanged_ method for setting
+  // active output device.
+
   /**
    * @param {!Route} route
    * @param {!Route=} oldRoute
diff --git a/chrome/browser/resources/settings/lazy_load.ts b/chrome/browser/resources/settings/lazy_load.ts
index dbf95b8..27eec361 100644
--- a/chrome/browser/resources/settings/lazy_load.ts
+++ b/chrome/browser/resources/settings/lazy_load.ts
@@ -38,7 +38,7 @@
 import './site_settings/site_data.js';
 import './site_settings/site_details.js';
 import './site_settings/zoom_levels.js';
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 import './people_page/import_data_dialog.js';
 // </if>
 // <if expr="not chromeos_ash">
@@ -82,7 +82,7 @@
 export {SettingsAddressRemoveConfirmationDialogElement} from './autofill_page/address_remove_confirmation_dialog.js';
 export {AutofillManagerImpl, AutofillManagerProxy, PersonalDataChangedListener} from './autofill_page/autofill_manager_proxy.js';
 export {SettingsAutofillSectionElement} from './autofill_page/autofill_section.js';
-// <if expr="chromeos_ash or chromeos_lacros">
+// <if expr="is_chromeos">
 export {BlockingRequestManager} from './autofill_page/blocking_request_manager.js';
 // </if>
 export {SettingsCreditCardEditDialogElement} from './autofill_page/credit_card_edit_dialog.js';
@@ -140,7 +140,7 @@
 export {SettingsSpellCheckPageElement} from './languages_page/spell_check_page.js';
 export {SettingsTranslatePageElement} from './languages_page/translate_page.js';
 // </if>
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 export {BrowserProfile, ImportDataBrowserProxy, ImportDataBrowserProxyImpl, ImportDataStatus} from './people_page/import_data_browser_proxy.js';
 export {SettingsImportDataDialogElement} from './people_page/import_data_dialog.js';
 // </if>
diff --git a/chrome/browser/resources/settings/page_visibility.ts b/chrome/browser/resources/settings/page_visibility.ts
index 0ae7a0e..62b8eab4 100644
--- a/chrome/browser/resources/settings/page_visibility.ts
+++ b/chrome/browser/resources/settings/page_visibility.ts
@@ -45,7 +45,7 @@
 if (loadTimeData.getBoolean('isGuest')) {
   // "if not chromeos" and "if chromeos" in two completely separate blocks
   // to work around closure compiler.
-  // <if expr="not (chromeos_ash or chromeos_lacros)">
+  // <if expr="not is_chromeos">
   pageVisibility = {
     a11y: false,
     advancedSettings: false,
@@ -63,7 +63,7 @@
     system: false,
   };
   // </if>
-  // <if expr="chromeos_ash or chromeos_lacros">
+  // <if expr="is_chromeos">
   pageVisibility = {
     autofill: false,
     people: false,
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 78504f3..b0f8b13 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -124,7 +124,7 @@
         </template>
 </if>
 
-<if expr="not chromeos_ash and not chromeos_lacros">
+<if expr="not is_chromeos">
         <cr-link-row id="importDataDialogTrigger"
             label="$i18n{importTitle}"
             on-click="onImportDataTap_"></cr-link-row>
diff --git a/chrome/browser/resources/settings/people_page/people_page.ts b/chrome/browser/resources/settings/people_page/people_page.ts
index 83a4294..72a11bb 100644
--- a/chrome/browser/resources/settings/people_page/people_page.ts
+++ b/chrome/browser/resources/settings/people_page/people_page.ts
@@ -367,7 +367,7 @@
     Router.getInstance().navigateTo(routes.SYNC);
   }
 
-  // <if expr="not chromeos_ash and not chromeos_lacros">
+  // <if expr="not is_chromeos">
   private onImportDataTap_() {
     Router.getInstance().navigateTo(routes.IMPORT_DATA);
   }
diff --git a/chrome/browser/resources/settings/people_page/sync_controls.html b/chrome/browser/resources/settings/people_page/sync_controls.html
index 2d07598..6e6ca8e 100644
--- a/chrome/browser/resources/settings/people_page/sync_controls.html
+++ b/chrome/browser/resources/settings/people_page/sync_controls.html
@@ -12,7 +12,7 @@
       }
     </style>
 
-<if expr="chromeos_ash or chromeos_lacros">
+<if expr="is_chromeos">
     <!-- TODO(crbug.com/1231500): Remove this warning after Lacros side-by-side
       rollout stage. -->
     <template is="dom-if" if="[[shouldShowLacrosSideBySideWarning_()]]">
diff --git a/chrome/browser/resources/settings/people_page/sync_controls.ts b/chrome/browser/resources/settings/people_page/sync_controls.ts
index 759b87d..0eba1fc0 100644
--- a/chrome/browser/resources/settings/people_page/sync_controls.ts
+++ b/chrome/browser/resources/settings/people_page/sync_controls.ts
@@ -16,7 +16,7 @@
 import {WebUIListenerMixin} from '//resources/js/web_ui_listener_mixin.js';
 import {PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-// <if expr="chromeos_ash or chromeos_lacros">
+// <if expr="is_chromeos">
 import {loadTimeData} from '../i18n_setup.js';
 // </if>
 
@@ -106,7 +106,7 @@
   }
 
 
-  // <if expr="chromeos_ash or chromeos_lacros">
+  // <if expr="is_chromeos">
   private shouldShowLacrosSideBySideWarning_(): boolean {
     return loadTimeData.getBoolean('shouldShowLacrosSideBySideWarning');
   }
diff --git a/chrome/browser/resources/settings/people_page/sync_page.html b/chrome/browser/resources/settings/people_page/sync_page.html
index 91939a4..3f0c34c3 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.html
+++ b/chrome/browser/resources/settings/people_page/sync_page.html
@@ -83,7 +83,7 @@
       </div>
     </div>
 
-<if expr="chromeos_ash or chromeos_lacros">
+<if expr="is_chromeos">
     <!-- TODO(crbug.com/1231500): Remove this warning after Lacros side-by-side
       rollout stage. -->
     <template is="dom-if" if="[[shouldShowLacrosSideBySideWarning_()]]">
diff --git a/chrome/browser/resources/settings/people_page/sync_page.ts b/chrome/browser/resources/settings/people_page/sync_page.ts
index 8b5bb93..ad7f435 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.ts
+++ b/chrome/browser/resources/settings/people_page/sync_page.ts
@@ -332,7 +332,7 @@
   }
   // </if>
 
-  // <if expr="chromeos_ash or chromeos_lacros">
+  // <if expr="is_chromeos">
   private shouldShowLacrosSideBySideWarning_(): boolean {
     return loadTimeData.getBoolean('shouldShowLacrosSideBySideWarning');
   }
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts
index 82ea4b3..277f1946 100644
--- a/chrome/browser/resources/settings/route.ts
+++ b/chrome/browser/resources/settings/route.ts
@@ -168,7 +168,7 @@
     addPrivacyChildRoutes(r);
   }
 
-  // <if expr="not chromeos_ash and not chromeos_lacros">
+  // <if expr="not is_chromeos">
   if (visibility.defaultBrowser !== false) {
     r.DEFAULT_BROWSER = r.BASIC.createSection(
         '/defaultBrowser', 'defaultBrowser',
diff --git a/chrome/browser/resources/settings/settings.ts b/chrome/browser/resources/settings/settings.ts
index 883910d..0d5c2b0 100644
--- a/chrome/browser/resources/settings/settings.ts
+++ b/chrome/browser/resources/settings/settings.ts
@@ -31,7 +31,7 @@
 export {SettingsDropdownMenuElement} from './controls/settings_dropdown_menu.js';
 export {SettingsIdleLoadElement} from './controls/settings_idle_load.js';
 export {SettingsToggleButtonElement} from './controls/settings_toggle_button.js';
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 export {DefaultBrowserBrowserProxy, DefaultBrowserBrowserProxyImpl, DefaultBrowserInfo} from './default_browser_page/default_browser_browser_proxy.js';
 export {SettingsDefaultBrowserPageElement} from './default_browser_page/default_browser_page.js';
 // </if>
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index 8278812..ee06ca5f 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -91,7 +91,7 @@
             $i18n{searchPageTitle}
             <paper-ripple></paper-ripple>
           </a>
-    <if expr="not chromeos_ash and not chromeos_lacros">
+    <if expr="not is_chromeos">
           <a role="menuitem" id="defaultBrowser" class="cr-nav-menu-item"
             href="/defaultBrowser"
             hidden="[[!pageVisibility.defaultBrowser]]">
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts
index ce9e6fdb..1e64e1e 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -21,22 +21,16 @@
 // check if chrome.readAnything exists prevents runtime errors when the feature
 // is disabled.
 if (chrome.readAnything) {
-  chrome.readAnything.updateFontName = function() {
-    const readAnythingApp = document.querySelector('read-anything-app');
-    assert(readAnythingApp);
-    readAnythingApp.updateFontName();
-  };
-
   chrome.readAnything.updateContent = function() {
     const readAnythingApp = document.querySelector('read-anything-app');
     assert(readAnythingApp);
     readAnythingApp.updateContent();
   };
 
-  chrome.readAnything.updateFontSize = function() {
+  chrome.readAnything.updateTheme = function() {
     const readAnythingApp = document.querySelector('read-anything-app');
     assert(readAnythingApp);
-    readAnythingApp.updateFontSize();
+    readAnythingApp.updateTheme();
   };
 }
 
@@ -174,14 +168,15 @@
     }
   }
 
-  updateFontName() {
+  validatedFontName(): string {
     // Validate that the given font name is a valid choice, or use the default.
     const validFontName = this.validFontNames.find(
         (f: {name: string}) => f.name === chrome.readAnything.fontName);
-    this.fontName_ = validFontName ? validFontName.css : this.defaultFontName;
+    return validFontName ? validFontName.css : this.defaultFontName;
   }
 
-  updateFontSize() {
+  updateTheme() {
+    this.fontName_ = this.validatedFontName();
     this.fontSize_ = chrome.readAnything.fontSize;
   }
 }
diff --git a/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts b/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
index 49a1f7f..6402a07 100644
--- a/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
+++ b/chrome/browser/resources/side_panel/read_anything/read_anything.d.ts
@@ -14,9 +14,8 @@
     // the AXTree distillation process.
     let contentNodeIds: number[];
 
-    // A font name, defined in ReadAnythingFontModel.
+    // Items in the ReadAnythingTheme struct, see read_anything.mojom for info.
     let fontName: string;
-
     let fontSize: number;
 
     // Returns a list of AXNodeIDs corresponding to the unignored children of
@@ -69,8 +68,8 @@
     function setContentForTesting(
         snapshotLite: Object, contentNodeIds: number[]): void;
 
-    // Set the font name. Used by tests only.
-    function setFontNameForTesting(newFontName: string): void;
+    // Set the theme. Used by tests only.
+    function setThemeForTesting(fontName: string, fontSize: number): void;
 
     ////////////////////////////////////////////////////////////////
     // Implemented in read_anything/app.ts and called by native c++.
@@ -80,12 +79,8 @@
     // and is available to consume.
     function updateContent(): void;
 
-    // Ping that the font name has been changed in the ReadAnythingToolbar and
-    // is available to consume.
-    function updateFontName(): void;
-
-    // Ping that the font size has been changed for the distilled contents and
-    // is available to consume.
-    function updateFontSize(): void;
+    // Ping that the theme choices of the user have been changed using the
+    // toolbar and are ready to consume.
+    function updateTheme(): void;
   }
 }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index f3cbdc5..c7d81af 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -5503,6 +5503,8 @@
       "web_applications/web_app_metrics_factory.h",
       "web_applications/web_app_metrics_tab_helper.cc",
       "web_applications/web_app_metrics_tab_helper.h",
+      "web_applications/web_app_tabbed_utils.cc",
+      "web_applications/web_app_tabbed_utils.h",
       "web_applications/web_app_ui_manager_impl.cc",
       "web_applications/web_app_ui_manager_impl.h",
       "web_applications/web_app_ui_utils.cc",
diff --git a/chrome/browser/ui/app_list/search/assistant_text_search_provider.cc b/chrome/browser/ui/app_list/search/assistant_text_search_provider.cc
index d9084828..4a97e38 100644
--- a/chrome/browser/ui/app_list/search/assistant_text_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/assistant_text_search_provider.cc
@@ -55,6 +55,7 @@
     SetResultType(ash::AppListSearchResultType::kAssistantText);
     SetMetricsType(ash::SearchResultType::ASSISTANT_OMNIBOX_RESULT);
     SetTitle(text);
+    SetDetails(l10n_util::GetStringUTF16(IDS_APP_LIST_START_ASSISTANT));
     SetAccessibleName(l10n_util::GetStringFUTF16(
         IDS_ASH_ASSISTANT_QUERY_ACCESSIBILITY_ANNOUNCEMENT, text));
     SetIcon(IconInfo(
diff --git a/chrome/browser/ui/app_list/search/assistant_text_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/assistant_text_search_provider_unittest.cc
index 7a7c063..bf6385d 100644
--- a/chrome/browser/ui/app_list/search/assistant_text_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/assistant_text_search_provider_unittest.cc
@@ -63,6 +63,7 @@
     EXPECT_LT(index, LastResults().size());
     auto* result = LastResults().at(0).get();
     EXPECT_EQ(result->title(), base::UTF8ToUTF16(text));
+    EXPECT_EQ(result->details(), u"Google Assistant");
     EXPECT_EQ(result->id(), "googleassistant_text://" + text);
     EXPECT_EQ(result->accessible_name(),
               base::UTF8ToUTF16(text + ", Google Assistant"));
diff --git a/chrome/browser/ui/app_list/search/files/item_suggest_cache_unittest.cc b/chrome/browser/ui/app_list/search/files/item_suggest_cache_unittest.cc
index e55dead..d46c6d5 100644
--- a/chrome/browser/ui/app_list/search/files/item_suggest_cache_unittest.cc
+++ b/chrome/browser/ui/app_list/search/files/item_suggest_cache_unittest.cc
@@ -66,9 +66,6 @@
 namespace app_list {
 using base::test::ScopedFeatureList;
 
-// TODO(crbug.com/1034842): Add test checking we make no requests when disabled
-// by experiment or policy.
-
 class ItemSuggestCacheTest : public testing::Test {
  protected:
   ItemSuggestCacheTest() = default;
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc
index 049a88b..8e86f98 100644
--- a/chrome/browser/ui/app_list/search/omnibox_result.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -23,6 +23,7 @@
 #include "chromeos/crosapi/mojom/launcher_search.mojom.h"
 #include "components/omnibox/browser/vector_icons.h"
 #include "components/search_engines/util.h"
+#include "components/strings/grit/components_strings.h"
 #include "extensions/common/image_util.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -241,14 +242,11 @@
                                           search_result_->contents_type));
 
     if (IsRichEntity()) {
-      // Only set the details text for rich entities. This prevents default
-      // descriptions such as "Google Search" from being added.
       SetDetails(description_);
       SetDetailsTags(TagsForTextWithMatchTags(
           query_, description_, search_result_->description_type));
-    }
 
-    if (crosapi::OptionalBoolIsTrue(search_result_->is_omnibox_search)) {
+      // Append the search engine to the accessible name only.
       const std::u16string accessible_name =
           details().empty() ? title()
                             : base::StrCat({title(), u", ", details()});
@@ -256,6 +254,13 @@
           IDS_APP_LIST_QUERY_SEARCH_ACCESSIBILITY_NAME, accessible_name,
           GetDefaultSearchEngineName(
               TemplateURLServiceFactory::GetForProfile(profile_))));
+    } else if (crosapi::OptionalBoolIsTrue(search_result_->is_omnibox_search)) {
+      // For non-rich-entity results, put the search engine into the details
+      // field. Tags are not used since this does not change with the query.
+      SetDetails(l10n_util::GetStringFUTF16(
+          IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION,
+          GetDefaultSearchEngineName(
+              TemplateURLServiceFactory::GetForProfile(profile_))));
     }
   } else {
     // For url result with non-empty description, swap title and details. Thus,
diff --git a/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc b/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc
index acc5668..731d6697 100644
--- a/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_result_unittest.cc
@@ -118,6 +118,16 @@
 }
 
 // Returns true if the given text vector has one text entry that equals the
+// given text, and no tags.
+bool IsSingletonTextVectorNoTags(
+    const std::vector<ash::SearchResultTextItem>& v,
+    const std::u16string& text) {
+  return v.size() == 1 &&
+         v[0].GetType() == ash::SearchResultTextItemType::kString &&
+         v[0].GetText() == text && v[0].GetTextTags().empty();
+}
+
+// Returns true if the given text vector has one text entry that equals the
 // given text, and tags that match the given tags.
 //
 // Would use an absl::Span to capture static array lengths, but absl isn't yet
@@ -460,21 +470,24 @@
   EXPECT_NE(std::u16string::npos, result->accessible_name().find(u"contents"));
 }
 
-// Test that there is no description, but an accessible name, for search
-// results.
+// Test that search results put the search engine in the description, and have
+// no accessible name.
 TEST_F(OmniboxResultTest, SearchResultText) {
   // Uses the default example contents and description.
   const auto result = CreateOmniboxResult(
       "https://example.com", AutocompleteMatchType::SEARCH_SUGGEST);
 
-  // Title should be populated, but details shouldn't be.
+  // Title should be populated.
   EXPECT_TRUE(IsSingletonTextVector(result->title_text_vector(),
                                     kExampleContents,
                                     kExpectedExampleContentsTags));
-  EXPECT_TRUE(result->details_text_vector().empty());
+  // Details should contain the search engine. This test relies on the test
+  // environment having Google as the default search engine.
+  EXPECT_TRUE(IsSingletonTextVectorNoTags(result->details_text_vector(),
+                                          u"Google Search"));
 
-  // Accessible name should be set.
-  EXPECT_NE(std::u16string::npos, result->accessible_name().find(u"contents"));
+  // Accessible name should not be set.
+  EXPECT_TRUE(result->accessible_name().empty());
 }
 
 }  // namespace test
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index f6d2f1a..e75184bf 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -141,7 +141,7 @@
   // NetworkConnect handles the network connection state machine for the UI.
   network_connect_delegate_ =
       std::make_unique<NetworkConnectDelegateChromeOS>();
-  chromeos::NetworkConnect::Initialize(network_connect_delegate_.get());
+  ash::NetworkConnect::Initialize(network_connect_delegate_.get());
 
   cast_config_controller_media_router_ =
       std::make_unique<CastConfigControllerMediaRouter>();
@@ -367,8 +367,8 @@
   ambient_client_.reset();
 
   cast_config_controller_media_router_.reset();
-  if (chromeos::NetworkConnect::IsInitialized())
-    chromeos::NetworkConnect::Shutdown();
+  if (ash::NetworkConnect::IsInitialized())
+    ash::NetworkConnect::Shutdown();
   network_connect_delegate_.reset();
   user_profile_loaded_observer_.reset();
 }
diff --git a/chrome/browser/ui/ash/network/mobile_data_notifications_unittest.cc b/chrome/browser/ui/ash/network/mobile_data_notifications_unittest.cc
index 3227f0ce..b4d0dac74 100644
--- a/chrome/browser/ui/ash/network/mobile_data_notifications_unittest.cc
+++ b/chrome/browser/ui/ash/network/mobile_data_notifications_unittest.cc
@@ -41,7 +41,7 @@
 const char kNotificationId[] = "chrome://settings/internet/mobile_data";
 const char kTestUserName[] = "test-user@example.com";
 
-class NetworkConnectTestDelegate : public chromeos::NetworkConnect::Delegate {
+class NetworkConnectTestDelegate : public ash::NetworkConnect::Delegate {
  public:
   NetworkConnectTestDelegate() {}
 
@@ -82,13 +82,13 @@
     SetupNetworkShillState();
     base::RunLoop().RunUntilIdle();
     network_connect_delegate_ = std::make_unique<NetworkConnectTestDelegate>();
-    chromeos::NetworkConnect::Initialize(network_connect_delegate_.get());
+    ash::NetworkConnect::Initialize(network_connect_delegate_.get());
     mobile_data_notifications_ = std::make_unique<MobileDataNotifications>();
   }
 
   void TearDown() override {
     mobile_data_notifications_.reset();
-    chromeos::NetworkConnect::Shutdown();
+    ash::NetworkConnect::Shutdown();
     network_connect_delegate_.reset();
     profile_manager_.reset();
     user_manager_enabler_.reset();
@@ -180,7 +180,7 @@
 TEST_F(MobileDataNotificationsTest, NotificationAlreadyShown) {
   pref_service()->SetBoolean(prefs::kShowMobileDataNotification, false);
 
-  chromeos::NetworkConnect::Get()->ConnectToNetworkId(kCellularGuid);
+  ash::NetworkConnect::Get()->ConnectToNetworkId(kCellularGuid);
   // Wait for async ConnectToNetworkId to take effect.
   base::RunLoop().RunUntilIdle();
 
@@ -191,7 +191,7 @@
 TEST_F(MobileDataNotificationsTest, DisplayNotification) {
   pref_service()->SetBoolean(prefs::kShowMobileDataNotification, true);
 
-  chromeos::NetworkConnect::Get()->ConnectToNetworkId(kCellularGuid);
+  ash::NetworkConnect::Get()->ConnectToNetworkId(kCellularGuid);
   // Wait for async ConnectToNetworkId to take effect.
   base::RunLoop().RunUntilIdle();
 
@@ -202,7 +202,7 @@
 TEST_F(MobileDataNotificationsTest, TogglesPref) {
   pref_service()->SetBoolean(prefs::kShowMobileDataNotification, true);
 
-  chromeos::NetworkConnect::Get()->ConnectToNetworkId(kCellularGuid);
+  ash::NetworkConnect::Get()->ConnectToNetworkId(kCellularGuid);
   // Wait for async ConnectToNetworkId to take effect.
   base::RunLoop().RunUntilIdle();
 
@@ -213,7 +213,7 @@
 // connected.
 TEST_F(MobileDataNotificationsTest, SessionUpdateDisplayNotification) {
   // Set up cellular network, don't trigger notification.
-  chromeos::NetworkConnect::Get()->ConnectToNetworkId(kCellularGuid);
+  ash::NetworkConnect::Get()->ConnectToNetworkId(kCellularGuid);
   pref_service()->SetBoolean(prefs::kShowMobileDataNotification, false);
   // Process network observer update.
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/ui/ash/network/network_connect_delegate_chromeos.h b/chrome/browser/ui/ash/network/network_connect_delegate_chromeos.h
index d1429a0..760580f6 100644
--- a/chrome/browser/ui/ash/network/network_connect_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/network/network_connect_delegate_chromeos.h
@@ -18,8 +18,7 @@
 class NetworkStateNotifier;
 }
 
-class NetworkConnectDelegateChromeOS
-    : public chromeos::NetworkConnect::Delegate {
+class NetworkConnectDelegateChromeOS : public ash::NetworkConnect::Delegate {
  public:
   NetworkConnectDelegateChromeOS();
 
diff --git a/chrome/browser/ui/ash/network/network_state_notifier.cc b/chrome/browser/ui/ash/network/network_state_notifier.cc
index 8a46b47c..262256ba 100644
--- a/chrome/browser/ui/ash/network/network_state_notifier.cc
+++ b/chrome/browser/ui/ash/network/network_state_notifier.cc
@@ -642,7 +642,7 @@
 
 void NetworkStateNotifier::ShowCarrierAccountDetail(
     const std::string& network_id) {
-  NetworkConnect::Get()->ShowCarrierAccountDetail(network_id);
+  ash::NetworkConnect::Get()->ShowCarrierAccountDetail(network_id);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/ui/ash/network/tether_notification_presenter.cc b/chrome/browser/ui/ash/network/tether_notification_presenter.cc
index 625f8b7..29aa0dc 100644
--- a/chrome/browser/ui/ash/network/tether_notification_presenter.cc
+++ b/chrome/browser/ui/ash/network/tether_notification_presenter.cc
@@ -120,7 +120,7 @@
 
 TetherNotificationPresenter::TetherNotificationPresenter(
     Profile* profile,
-    NetworkConnect* network_connect)
+    ash::NetworkConnect* network_connect)
     : profile_(profile),
       network_connect_(network_connect),
       settings_ui_delegate_(base::WrapUnique(new SettingsUiDelegateImpl())) {}
diff --git a/chrome/browser/ui/ash/network/tether_notification_presenter.h b/chrome/browser/ui/ash/network/tether_notification_presenter.h
index 2223693..2eeec48b 100644
--- a/chrome/browser/ui/ash/network/tether_notification_presenter.h
+++ b/chrome/browser/ui/ash/network/tether_notification_presenter.h
@@ -18,15 +18,15 @@
 
 class Profile;
 
+namespace ash {
+class NetworkConnect;
+}
+
 namespace message_center {
 class Notification;
 }  // namespace message_center
 
-namespace chromeos {
-
-class NetworkConnect;
-
-namespace tether {
+namespace chromeos::tether {
 
 // Produces notifications associated with CrOS tether network events and alerts
 // observers about interactions with those notifications.
@@ -35,7 +35,7 @@
   // Caller must ensure that |profile| and |network_connect| outlive this
   // instance.
   TetherNotificationPresenter(Profile* profile,
-                              NetworkConnect* network_connect);
+                              ash::NetworkConnect* network_connect);
 
   TetherNotificationPresenter(const TetherNotificationPresenter&) = delete;
   TetherNotificationPresenter& operator=(const TetherNotificationPresenter&) =
@@ -111,7 +111,7 @@
   void RemoveNotificationIfVisible(const std::string& notification_id);
 
   Profile* profile_;
-  NetworkConnect* network_connect_;
+  ash::NetworkConnect* network_connect_;
 
   // The ID of the currently showing notification.
   std::string showing_notification_id_;
@@ -125,8 +125,6 @@
   base::WeakPtrFactory<TetherNotificationPresenter> weak_ptr_factory_{this};
 };
 
-}  // namespace tether
-
-}  // namespace chromeos
+}  // namespace chromeos::tether
 
 #endif  // CHROME_BROWSER_UI_ASH_NETWORK_TETHER_NOTIFICATION_PRESENTER_H_
diff --git a/chrome/browser/ui/ash/projector/screencast_manager.cc b/chrome/browser/ui/ash/projector/screencast_manager.cc
index 369dbc4..f5926da3 100644
--- a/chrome/browser/ui/ash/projector/screencast_manager.cc
+++ b/chrome/browser/ui/ash/projector/screencast_manager.cc
@@ -5,11 +5,58 @@
 #include "chrome/browser/ui/ash/projector/screencast_manager.h"
 
 #include <memory>
+#include <vector>
 
+#include "ash/components/drivefs/mojom/drivefs.mojom.h"
 #include "ash/webui/projector_app/projector_screencast.h"
+#include "ash/webui/projector_app/public/cpp/projector_app_constants.h"
+#include "base/files/file_path.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/ash/drive/drive_integration_service.h"
+#include "chrome/browser/ui/ash/projector/projector_drivefs_provider.h"
 
 namespace ash {
 
+namespace {
+
+void OnVideoFilePathLocated(
+    std::unique_ptr<ProjectorScreencastVideo> video,
+    ProjectorAppClient::OnGetVideoCallback callback,
+    absl::optional<std::vector<drivefs::mojom::FilePathOrErrorPtr>> paths) {
+  const std::string& video_id = video->file_id;
+  if (!paths || paths.value().size() != 1u) {
+    std::move(callback).Run(
+        /*video=*/nullptr,
+        base::StringPrintf("Failed to find DriveFS path with video file id=%s",
+                           video_id.c_str()));
+    return;
+  }
+
+  const auto& path_or_error = paths.value()[0];
+  if (path_or_error->is_error() || !path_or_error->is_path()) {
+    std::move(callback).Run(
+        /*video=*/nullptr,
+        base::StringPrintf("Failed to fetch DriveFS file with video file id=%s "
+                           "and error code=%d",
+                           video_id.c_str(), path_or_error->get_error()));
+    return;
+  }
+
+  const base::FilePath& relative_drivefs_path = path_or_error->get_path();
+  if (!relative_drivefs_path.MatchesExtension(kProjectorMediaFileExtension)) {
+    std::move(callback).Run(
+        /*video=*/nullptr,
+        base::StringPrintf("Failed to fetch video file with video file id=%s",
+                           video_id.c_str()));
+    return;
+  }
+
+  // TODO(b/237089852): Launch the file.
+  std::move(callback).Run(std::move(video), /*error_message=*/std::string());
+}
+
+}  // namespace
+
 ScreencastManager::ScreencastManager() = default;
 ScreencastManager::~ScreencastManager() = default;
 
@@ -20,10 +67,15 @@
   auto video = std::make_unique<ProjectorScreencastVideo>();
   video->file_id = video_file_id;
   // TODO(b/237089852):
-  // 1. Find the video file by id.
-  // 2. Find the video duration.
-  // 3. Launch the app with the video file.
-  std::move(callback).Run(std::move(video), /*error_message=*/std::string());
+  // 1. Find the video duration.
+  // 2. Launch the app with the video file.
+  // 3. Handle the resource key once LocateFilesByItemIds() supports it.
+
+  drive::DriveIntegrationService* integration_service =
+      ProjectorDriveFsProvider::GetActiveDriveIntegrationService();
+  integration_service->LocateFilesByItemIds(
+      {video_file_id}, base::BindOnce(&OnVideoFilePathLocated, std::move(video),
+                                      std::move(callback)));
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ui/ash/projector/screencast_manager_browsertest.cc b/chrome/browser/ui/ash/projector/screencast_manager_browsertest.cc
index 47330c6..34d09bd 100644
--- a/chrome/browser/ui/ash/projector/screencast_manager_browsertest.cc
+++ b/chrome/browser/ui/ash/projector/screencast_manager_browsertest.cc
@@ -6,10 +6,19 @@
 
 #include <memory>
 
+#include "ash/components/drivefs/fake_drivefs.h"
 #include "ash/webui/projector_app/projector_screencast.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "base/threading/thread_restrictions.h"
+#include "chrome/browser/ash/drive/drive_integration_service.h"
+#include "chrome/browser/ash/drive/drivefs_test_support.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "components/drive/file_errors.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -17,8 +26,10 @@
 
 namespace {
 
+constexpr char kVideoFileName[] = "MyTestScreencast.webm";
 constexpr char kVideoFileId[] = "videoFileId";
 constexpr char kResourceKey[] = "resourceKey";
+constexpr char kTestFileContents[] = "This is some test content.";
 
 }  // namespace
 
@@ -30,7 +41,142 @@
   ScreencastManager screencast_manager_;
 };
 
-IN_PROC_BROWSER_TEST_F(ScreencastManagerTest, GetVideoSuccess) {
+class ScreencastManagerTestWithDriveFs : public ScreencastManagerTest {
+ public:
+  // ScreencastManagerTest:
+  void SetUpInProcessBrowserTestFixture() override {
+    ScreencastManagerTest::SetUpInProcessBrowserTestFixture();
+    create_drive_integration_service_ = base::BindRepeating(
+        &ScreencastManagerTestWithDriveFs::CreateDriveIntegrationService,
+        base::Unretained(this));
+    service_factory_for_test_ = std::make_unique<
+        drive::DriveIntegrationServiceFactory::ScopedFactoryForTest>(
+        &create_drive_integration_service_);
+  }
+
+  // Gets the file path for a named file in the test folder. If `relative`
+  // is true, then returns the file path relative to the DriveFS mount point.
+  // Otherwise, returns the absolute file path.
+  base::FilePath GetTestFile(const std::string& title, bool relative) {
+    auto* drive_service = drive::DriveIntegrationServiceFactory::FindForProfile(
+        browser()->profile());
+    base::FilePath mount_path = drive_service->GetMountPointPath();
+    base::FilePath file_path = mount_path.Append(title);
+    if (!relative) {
+      return file_path;
+    }
+    base::FilePath relative_path("/");
+    EXPECT_TRUE(mount_path.AppendRelativePath(file_path, &relative_path));
+    return relative_path;
+  }
+
+  void AddFileToDefaultFolder(const std::string& file_id,
+                              const std::string& content_type,
+                              const std::string& title,
+                              bool shared_with_me) {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    drivefs::FakeDriveFs* fake = GetFakeDriveFsForProfile(browser()->profile());
+
+    const base::FilePath& absolute_path =
+        GetTestFile(title, /*relative=*/false);
+    EXPECT_TRUE(base::WriteFile(absolute_path, kTestFileContents));
+
+    const base::FilePath& relative_path = GetTestFile(title, /*relative=*/true);
+    fake->SetMetadata(relative_path, content_type, title, false, shared_with_me,
+                      {}, {}, file_id, "");
+  }
+
+ protected:
+  drivefs::FakeDriveFs* GetFakeDriveFsForProfile(Profile* profile) {
+    return &fake_drivefs_helpers_[profile]->fake_drivefs();
+  }
+
+  drive::DriveIntegrationService* CreateDriveIntegrationService(
+      Profile* profile) {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    base::FilePath mount_path = profile->GetPath().Append("drivefs");
+    fake_drivefs_helpers_[profile] =
+        std::make_unique<drive::FakeDriveFsHelper>(profile, mount_path);
+    auto* integration_service = new drive::DriveIntegrationService(
+        profile, std::string(), mount_path,
+        fake_drivefs_helpers_[profile]->CreateFakeDriveFsListenerFactory());
+    return integration_service;
+  }
+
+ private:
+  drive::DriveIntegrationServiceFactory::FactoryCallback
+      create_drive_integration_service_;
+  std::unique_ptr<drive::DriveIntegrationServiceFactory::ScopedFactoryForTest>
+      service_factory_for_test_;
+  std::map<Profile*, std::unique_ptr<drive::FakeDriveFsHelper>>
+      fake_drivefs_helpers_;
+};
+
+// Tests that GetDriveFsFile() fails with an appropriate error message when
+// there's no DriveFS mount point available.
+IN_PROC_BROWSER_TEST_F(ScreencastManagerTest, NoDriveFsMountPoint) {
+  base::RunLoop run_loop;
+  screencast_manager().GetVideo(
+      kVideoFileId, /*resource_key=*/"",
+      base::BindLambdaForTesting(
+          [&run_loop](std::unique_ptr<ProjectorScreencastVideo> video,
+                      const std::string& error_message) {
+            EXPECT_EQ(error_message,
+                      base::StringPrintf(
+                          "Failed to find DriveFS path with video file id=%s",
+                          kVideoFileId));
+            // Quits the run loop.
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+}
+
+// Tests that GetDriveFsFile() fails with an appropriate error message when the
+// files don't exist in DriveFS. This scenario can happen right after the user
+// logs in on a new device, before the files have fully synced.
+IN_PROC_BROWSER_TEST_F(ScreencastManagerTestWithDriveFs, FileNotFound) {
+  base::RunLoop run_loop;
+  screencast_manager().GetVideo(
+      kVideoFileId, kResourceKey,
+      base::BindLambdaForTesting(
+          [&run_loop](std::unique_ptr<ProjectorScreencastVideo> video,
+                      const std::string& error_message) {
+            EXPECT_EQ(
+                error_message,
+                base::StringPrintf("Failed to fetch DriveFS file with video "
+                                   "file id=%s and error code=%d",
+                                   kVideoFileId, drive::FILE_ERROR_NOT_FOUND));
+            // Quits the run loop.
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+}
+
+// Tests that the ScreencastManager rejects files that don't look like a video.
+IN_PROC_BROWSER_TEST_F(ScreencastManagerTestWithDriveFs, NotAVideo) {
+  AddFileToDefaultFolder(kVideoFileId, "video/webm", "MyTestScreencast.exe",
+                         /*shared_with_me=*/true);
+
+  base::RunLoop run_loop;
+  screencast_manager().GetVideo(
+      kVideoFileId, /*resource_key=*/"",
+      base::BindLambdaForTesting(
+          [&run_loop](std::unique_ptr<ProjectorScreencastVideo> video,
+                      const std::string& error_message) {
+            EXPECT_EQ(error_message,
+                      base::StringPrintf(
+                          "Failed to fetch video file with video file id=%s",
+                          kVideoFileId));
+            // Quits the run loop.
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(ScreencastManagerTestWithDriveFs, GetVideoSuccess) {
+  AddFileToDefaultFolder(kVideoFileId, "video/webm", kVideoFileName,
+                         /*shared_with_me=*/false);
+
   base::RunLoop run_loop;
   screencast_manager().GetVideo(
       kVideoFileId, kResourceKey,
diff --git a/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc b/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc
index 31a53118..b5760b05 100644
--- a/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_context_menu_controller.cc
@@ -70,7 +70,7 @@
     BookmarkLaunchLocation location,
     WindowOpenDisposition disposition) {
   switch (location) {
-    case BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR:
+    case BookmarkLaunchLocation::kAttachedBar:
       switch (disposition) {
         case WindowOpenDisposition::NEW_BACKGROUND_TAB:
           return &kBookmarkBarNewBackgroundTab;
@@ -81,7 +81,7 @@
         default:
           return nullptr;
       }
-    case BOOKMARK_LAUNCH_LOCATION_APP_MENU:
+    case BookmarkLaunchLocation::kAppMenu:
       switch (disposition) {
         case WindowOpenDisposition::NEW_BACKGROUND_TAB:
           return &kAppMenuBookmarksNewBackgroundTab;
@@ -92,7 +92,7 @@
         default:
           return nullptr;
       }
-    case BOOKMARK_LAUNCH_LOCATION_SIDE_PANEL_CONTEXT_MENU:
+    case BookmarkLaunchLocation::kSidePanelContextMenu:
       switch (disposition) {
         case WindowOpenDisposition::NEW_BACKGROUND_TAB:
           return &kSidePanelBookmarksNewBackgroundTab;
diff --git a/chrome/browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc b/chrome/browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc
index 66b03acb..f138d663 100644
--- a/chrome/browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc
@@ -99,7 +99,7 @@
       model_->bookmark_bar_node()->children().front().get(),
   };
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes);
   GURL url = model_->bookmark_bar_node()->children().front()->url();
   ASSERT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
@@ -123,7 +123,7 @@
 // Tests the enabled state of the menus when supplied an empty vector.
 TEST_F(BookmarkContextMenuControllerTest, EmptyNodes) {
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       model_->other_node(), std::vector<const BookmarkNode*>());
   EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_FALSE(
@@ -144,7 +144,7 @@
       model_->bookmark_bar_node()->children().front().get(),
   };
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes);
   EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_TRUE(
@@ -166,7 +166,7 @@
       model_->bookmark_bar_node()->children()[1]->children()[0].get(),
   };
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes);
   EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_TRUE(
@@ -187,7 +187,7 @@
       model_->bookmark_bar_node()->children()[2].get(),
   };
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes);
   EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_FALSE(
@@ -209,7 +209,7 @@
       model_->bookmark_bar_node()->children()[3].get(),
   };
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes);
   EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_FALSE(
@@ -231,7 +231,7 @@
       model_->bookmark_bar_node()->children()[4].get(),
   };
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes);
   EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_TRUE(
@@ -260,7 +260,7 @@
       model_->bookmark_bar_node()->children().front().get(),
   };
   BookmarkContextMenuController controller(nullptr, nullptr, nullptr, incognito,
-                                           BOOKMARK_LAUNCH_LOCATION_NONE,
+                                           BookmarkLaunchLocation::kNone,
                                            nodes[0]->parent(), nodes);
   EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_INCOGNITO));
   EXPECT_FALSE(
@@ -272,7 +272,7 @@
   std::vector<const BookmarkNode*> nodes;
   nodes.push_back(model_->other_node());
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0], nodes);
   EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_EDIT));
   EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_REMOVE));
@@ -282,7 +282,7 @@
 // parent.
 TEST_F(BookmarkContextMenuControllerTest, EmptyNodesNullParent) {
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nullptr, std::vector<const BookmarkNode*>());
   EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_FALSE(
@@ -302,7 +302,7 @@
   std::vector<const BookmarkNode*> nodes;
   nodes.push_back(model_->bookmark_bar_node());
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes);
   EXPECT_TRUE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_TRUE(
@@ -324,7 +324,7 @@
   std::unique_ptr<BookmarkContextMenuController> controller(
       new BookmarkContextMenuController(
           nullptr, nullptr, nullptr, profile_.get(),
-          BOOKMARK_LAUNCH_LOCATION_NONE, nodes[0]->parent(), nodes));
+          BookmarkLaunchLocation::kNone, nodes[0]->parent(), nodes));
   EXPECT_TRUE(controller->IsCommandIdEnabled(IDC_COPY));
   EXPECT_TRUE(controller->IsCommandIdEnabled(IDC_CUT));
 
@@ -332,7 +332,7 @@
   controller->ExecuteCommand(IDC_COPY, 0);
 
   controller = base::WrapUnique(new BookmarkContextMenuController(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes));
   size_t old_count = bb_node->children().size();
   controller->ExecuteCommand(IDC_PASTE, 0);
@@ -342,7 +342,7 @@
   ASSERT_EQ(bb_node->children()[0]->url(), bb_node->children()[1]->url());
 
   controller = base::WrapUnique(new BookmarkContextMenuController(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes));
   // Cut the URL.
   controller->ExecuteCommand(IDC_CUT, 0);
@@ -354,7 +354,7 @@
 TEST_F(BookmarkContextMenuControllerTest,
        ManagedShowAppsShortcutInBookmarksBar) {
   BookmarkContextMenuController controller(
-      nullptr, nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       model_->bookmark_bar_node(), std::vector<const BookmarkNode*>());
 
   // By default, the pref is not managed and the command is enabled.
diff --git a/chrome/browser/ui/bookmarks/bookmark_stats.cc b/chrome/browser/ui/bookmarks/bookmark_stats.cc
index 3bc84fe..1f92808 100644
--- a/chrome/browser/ui/bookmarks/bookmark_stats.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_stats.cc
@@ -15,8 +15,8 @@
 namespace {
 
 bool IsBookmarkBarLocation(BookmarkLaunchLocation location) {
-  return location == BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR ||
-         location == BOOKMARK_LAUNCH_LOCATION_BAR_SUBFOLDER;
+  return location == BookmarkLaunchLocation::kAttachedBar ||
+         location == BookmarkLaunchLocation::kSubfolder;
 }
 
 auto GetMetricProfile(const Profile* profile) {
@@ -33,15 +33,14 @@
                           profile_metrics::BrowserProfileType profile_type) {
   if (IsBookmarkBarLocation(location)) {
     base::RecordAction(base::UserMetricsAction("ClickedBookmarkBarURLButton"));
-  } else if (location == BOOKMARK_LAUNCH_LOCATION_APP_MENU) {
+  } else if (location == BookmarkLaunchLocation::kAppMenu) {
     base::RecordAction(
         base::UserMetricsAction("WrenchMenu_Bookmarks_LaunchURL"));
-  } else if (location == BOOKMARK_LAUNCH_LOCATION_TOP_MENU) {
+  } else if (location == BookmarkLaunchLocation::kTopMenu) {
     base::RecordAction(base::UserMetricsAction("TopMenu_Bookmarks_LaunchURL"));
   }
 
-  UMA_HISTOGRAM_ENUMERATION("Bookmarks.LaunchLocation", location,
-                            BOOKMARK_LAUNCH_LOCATION_LIMIT);
+  UMA_HISTOGRAM_ENUMERATION("Bookmarks.LaunchLocation", location);
 
   UMA_HISTOGRAM_ENUMERATION("Bookmarks.UsageCountPerProfileType", profile_type);
 }
@@ -66,13 +65,11 @@
 }
 
 void RecordBookmarkEdited(BookmarkLaunchLocation location) {
-  UMA_HISTOGRAM_ENUMERATION("Bookmarks.EditLocation", location,
-                            BOOKMARK_LAUNCH_LOCATION_LIMIT);
+  UMA_HISTOGRAM_ENUMERATION("Bookmarks.EditLocation", location);
 }
 
 void RecordBookmarkRemoved(BookmarkLaunchLocation location) {
-  UMA_HISTOGRAM_ENUMERATION("Bookmarks.RemovedLocation", location,
-                            BOOKMARK_LAUNCH_LOCATION_LIMIT);
+  UMA_HISTOGRAM_ENUMERATION("Bookmarks.RemovedLocation", location);
 }
 
 void RecordBookmarksAdded(const Profile* profile) {
diff --git a/chrome/browser/ui/bookmarks/bookmark_stats.h b/chrome/browser/ui/bookmarks/bookmark_stats.h
index 84debd7..2df2773 100644
--- a/chrome/browser/ui/bookmarks/bookmark_stats.h
+++ b/chrome/browser/ui/bookmarks/bookmark_stats.h
@@ -17,51 +17,51 @@
 // This enum is used for the Bookmarks.EntryPoint histogram.
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
-enum BookmarkEntryPoint {
-  BOOKMARK_ENTRY_POINT_ACCELERATOR,
-  BOOKMARK_ENTRY_POINT_STAR_GESTURE,
-  BOOKMARK_ENTRY_POINT_STAR_KEY,
-  BOOKMARK_ENTRY_POINT_STAR_MOUSE,
+enum class BookmarkEntryPoint {
+  kAccelerator = 0,
+  kStarGesture = 1,
+  kStarKey = 2,
+  kStarMouse = 3,
 
-  BOOKMARK_ENTRY_POINT_LIMIT  // Keep this last.
+  kMaxValue = kStarMouse
 };
 
 // This enum is used for the Bookmarks.LaunchLocation histogram.
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
-enum BookmarkLaunchLocation {
-  BOOKMARK_LAUNCH_LOCATION_NONE,
-  BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR = 0,
-  // BOOKMARK_LAUNCH_LOCATION_DETACHED_BAR = 1, (deprecated)
+enum class BookmarkLaunchLocation {
+  kNone,
+  kAttachedBar = 0,
+  // kDetachedBar = 1, (deprecated)
   // These two are kind of sub-categories of the bookmark bar. Generally
   // a launch from a context menu or subfolder could be classified in one of
   // the other two bar buckets, but doing so is difficult because the menus
   // don't know of their greater place in Chrome.
-  BOOKMARK_LAUNCH_LOCATION_BAR_SUBFOLDER = 2,
-  BOOKMARK_LAUNCH_LOCATION_CONTEXT_MENU = 3,
+  kSubfolder = 2,
+  kContextMenu = 3,
 
   // Bookmarks menu within app menu.
-  BOOKMARK_LAUNCH_LOCATION_APP_MENU = 4,
+  kAppMenu = 4,
   // Bookmark manager.
-  BOOKMARK_LAUNCH_LOCATION_MANAGER = 5,
+  kManager = 5,
   // Autocomplete suggestion.
-  BOOKMARK_LAUNCH_LOCATION_OMNIBOX = 6,
+  kOmnibox = 6,
   // System application menu (e.g. on Mac).
-  BOOKMARK_LAUNCH_LOCATION_TOP_MENU = 7,
+  kTopMenu = 7,
 
   // Bookmarks top level folder (i.e. bookmarks bar, other bookmarks) within the
   // side panel.
-  BOOKMARK_LAUNCH_LOCATION_SIDE_PANEL_FOLDER = 8,
+  kSidePanelFolder = 8,
   // Bookmarks subfolder within the side panel.
-  BOOKMARK_LAUNCH_LOCATION_SIDE_PANEL_SUBFOLDER = 9,
+  kSidePanelSubfolder = 9,
   // Reading list tab within the side panel.
-  BOOKMARK_LAUNCH_LOCATION_SIDE_PANEL_READING_LIST = 10,
+  kSidePanelPendingList = 10,
   // Reading list bubble in the bookmarks bar.
-  BOOKMARK_LAUNCH_LOCATION_READING_LIST_DIALOG = 11,
+  kReadingListDialog = 11,
   // Context menu for a bookmark node in the side panel.
-  BOOKMARK_LAUNCH_LOCATION_SIDE_PANEL_CONTEXT_MENU = 12,
+  kSidePanelContextMenu = 12,
 
-  BOOKMARK_LAUNCH_LOCATION_LIMIT  // Keep this last.
+  kMaxValue = kSidePanelContextMenu
 };
 
 // Records the launch of a bookmark for UMA purposes.
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
index 3aa71c0..6299d11 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
@@ -108,7 +108,7 @@
       ui::PAGE_TRANSITION_AUTO_BOOKMARK, false);
   browser->OpenURL(params);
   RecordBookmarkLaunch(
-      BOOKMARK_LAUNCH_LOCATION_TOP_MENU,
+      BookmarkLaunchLocation::kTopMenu,
       profile_metrics::GetBrowserProfileType(_bridge->GetProfile()));
 }
 
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
index 243d049..91dbdc7 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -394,7 +394,7 @@
 }
 
 void ChromeOmniboxClient::OnBookmarkLaunched() {
-  RecordBookmarkLaunch(BOOKMARK_LAUNCH_LOCATION_OMNIBOX,
+  RecordBookmarkLaunch(BookmarkLaunchLocation::kOmnibox,
                        profile_metrics::GetBrowserProfileType(profile_));
 }
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index 12a2ac1..5262af23 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -1334,7 +1334,7 @@
                                 ui::DispositionFromEventFlags(event.flags()),
                                 ui::PAGE_TRANSITION_AUTO_BOOKMARK, false);
   page_navigator_->OpenURL(params);
-  RecordBookmarkAppsPageOpen(BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR);
+  RecordBookmarkAppsPageOpen(BookmarkLaunchLocation::kAttachedBar);
 }
 
 void BookmarkBarView::OnButtonPressed(const bookmarks::BookmarkNode* node,
@@ -1346,7 +1346,7 @@
   chrome::OpenAllIfAllowed(browser_, {node},
                            ui::DispositionFromEventFlags(event.flags()), false);
   RecordBookmarkLaunch(
-      BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR,
+      BookmarkLaunchLocation::kAttachedBar,
       profile_metrics::GetBrowserProfileType(browser_->profile()));
 }
 
@@ -1356,11 +1356,11 @@
   // opens all bookmarks in the folder in new tabs.
   if ((event.flags() & ui::EF_MIDDLE_MOUSE_BUTTON) ||
       (event.flags() & ui::EF_PLATFORM_ACCELERATOR)) {
-    RecordBookmarkFolderLaunch(BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR);
+    RecordBookmarkFolderLaunch(BookmarkLaunchLocation::kAttachedBar);
     chrome::OpenAllIfAllowed(
         browser_, {node}, ui::DispositionFromEventFlags(event.flags()), false);
   } else {
-    RecordBookmarkFolderOpen(BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR);
+    RecordBookmarkFolderOpen(BookmarkLaunchLocation::kAttachedBar);
     const size_t start_index = (node == bookmark_model_->bookmark_bar_node())
                                    ? GetFirstHiddenNodeIndex()
                                    : 0;
@@ -1412,7 +1412,7 @@
 
   context_menu_ = std::make_unique<BookmarkContextMenu>(
       GetWidget(), browser_, browser_->profile(),
-      BOOKMARK_LAUNCH_LOCATION_ATTACHED_BAR, parent, nodes, close_on_remove);
+      BookmarkLaunchLocation::kAttachedBar, parent, nodes, close_on_remove);
   context_menu_->RunMenuAt(point, source_type);
 }
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_context_menu_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_context_menu_unittest.cc
index ae74cb3..28d3f23 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_context_menu_unittest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_context_menu_unittest.cc
@@ -120,7 +120,7 @@
       model_->bookmark_bar_node()->children().front().get(),
   };
   BookmarkContextMenu controller(nullptr, nullptr, profile_.get(),
-                                 BOOKMARK_LAUNCH_LOCATION_NONE,
+                                 BookmarkLaunchLocation::kNone,
                                  nodes[0]->parent(), nodes, false);
   GURL url = model_->bookmark_bar_node()->children().front()->url();
   ASSERT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
@@ -173,7 +173,7 @@
 // Tests the enabled state of the menus when supplied an empty vector.
 TEST_F(BookmarkContextMenuTest, EmptyNodes) {
   BookmarkContextMenu controller(
-      nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       model_->other_node(), std::vector<const BookmarkNode*>(), false);
   EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_FALSE(
@@ -194,7 +194,7 @@
       model_->bookmark_bar_node()->children().front().get(),
   };
   BookmarkContextMenu controller(nullptr, nullptr, profile_.get(),
-                                 BOOKMARK_LAUNCH_LOCATION_NONE,
+                                 BookmarkLaunchLocation::kNone,
                                  nodes[0]->parent(), nodes, false);
   EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_TRUE(
@@ -215,7 +215,7 @@
       model_->bookmark_bar_node()->children()[1]->children()[0].get(),
   };
   BookmarkContextMenu controller(nullptr, nullptr, profile_.get(),
-                                 BOOKMARK_LAUNCH_LOCATION_NONE,
+                                 BookmarkLaunchLocation::kNone,
                                  nodes[0]->parent(), nodes, false);
   EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_TRUE(
@@ -235,7 +235,7 @@
       model_->bookmark_bar_node()->children()[2].get(),
   };
   BookmarkContextMenu controller(nullptr, nullptr, profile_.get(),
-                                 BOOKMARK_LAUNCH_LOCATION_NONE,
+                                 BookmarkLaunchLocation::kNone,
                                  nodes[0]->parent(), nodes, false);
   EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_FALSE(
@@ -257,7 +257,7 @@
       model_->bookmark_bar_node()->children()[3].get(),
   };
   BookmarkContextMenu controller(nullptr, nullptr, profile_.get(),
-                                 BOOKMARK_LAUNCH_LOCATION_NONE,
+                                 BookmarkLaunchLocation::kNone,
                                  nodes[0]->parent(), nodes, false);
   EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_FALSE(
@@ -279,7 +279,7 @@
       model_->bookmark_bar_node()->children()[4].get(),
   };
   BookmarkContextMenu controller(nullptr, nullptr, profile_.get(),
-                                 BOOKMARK_LAUNCH_LOCATION_NONE,
+                                 BookmarkLaunchLocation::kNone,
                                  nodes[0]->parent(), nodes, false);
   EXPECT_TRUE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_TRUE(
@@ -300,7 +300,7 @@
   Profile* incognito =
       profile_->GetPrimaryOTRProfile(/*create_if_needed=*/true);
   BookmarkContextMenu controller(nullptr, nullptr, incognito,
-                                 BOOKMARK_LAUNCH_LOCATION_NONE,
+                                 BookmarkLaunchLocation::kNone,
                                  nodes[0]->parent(), nodes, false);
   EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_INCOGNITO));
   EXPECT_FALSE(
@@ -311,7 +311,7 @@
 TEST_F(BookmarkContextMenuTest, DisabledItemsWithOtherNode) {
   std::vector<const BookmarkNode*> nodes = {model_->other_node()};
   BookmarkContextMenu controller(nullptr, nullptr, profile_.get(),
-                                 BOOKMARK_LAUNCH_LOCATION_NONE, nodes[0], nodes,
+                                 BookmarkLaunchLocation::kNone, nodes[0], nodes,
                                  false);
   EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_EDIT));
   EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_REMOVE));
@@ -321,8 +321,7 @@
 // parent.
 TEST_F(BookmarkContextMenuTest, EmptyNodesNullParent) {
   BookmarkContextMenu controller(nullptr, nullptr, profile_.get(),
-
-                                 BOOKMARK_LAUNCH_LOCATION_NONE, nullptr,
+                                 BookmarkLaunchLocation::kNone, nullptr,
                                  std::vector<const BookmarkNode*>(), false);
   EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL));
   EXPECT_FALSE(
@@ -340,7 +339,7 @@
   const BookmarkNode* bb_node = model_->bookmark_bar_node();
   std::vector<const BookmarkNode*> nodes = {bb_node->children()[0].get()};
   std::unique_ptr<BookmarkContextMenu> controller(new BookmarkContextMenu(
-      nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes, false));
   EXPECT_TRUE(controller->IsCommandEnabled(IDC_COPY));
   EXPECT_TRUE(controller->IsCommandEnabled(IDC_CUT));
@@ -349,7 +348,7 @@
   controller->ExecuteCommand(IDC_COPY, 0);
 
   controller = std::make_unique<BookmarkContextMenu>(
-      nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes, false);
   size_t old_count = bb_node->children().size();
   controller->ExecuteCommand(IDC_PASTE, 0);
@@ -359,7 +358,7 @@
   ASSERT_EQ(bb_node->children()[0]->url(), bb_node->children()[1]->url());
 
   controller = std::make_unique<BookmarkContextMenu>(
-      nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes, false);
   // Cut the URL.
   controller->ExecuteCommand(IDC_CUT, 0);
@@ -377,7 +376,7 @@
       bb_node->children().front().get(),
   };
   std::unique_ptr<BookmarkContextMenu> controller(new BookmarkContextMenu(
-      nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes, false));
 
   // Verify that there are no managed nodes yet.
@@ -409,7 +408,7 @@
 
   // New context menus now show the "Show managed bookmarks" option.
   controller = std::make_unique<BookmarkContextMenu>(
-      nullptr, nullptr, profile_.get(), BOOKMARK_LAUNCH_LOCATION_NONE,
+      nullptr, nullptr, profile_.get(), BookmarkLaunchLocation::kNone,
       nodes[0]->parent(), nodes, false);
   EXPECT_TRUE(controller->IsCommandVisible(IDC_BOOKMARK_BAR_NEW_FOLDER));
   EXPECT_TRUE(
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc
index 974f188..44c62d5 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc
@@ -36,7 +36,7 @@
       bookmark_bar_(nullptr) {
   menu_delegate_->Init(this, nullptr, node, start_child_index,
                        BookmarkMenuDelegate::HIDE_PERMANENT_FOLDERS,
-                       BOOKMARK_LAUNCH_LOCATION_BAR_SUBFOLDER);
+                       BookmarkLaunchLocation::kSubfolder);
   int run_type = 0;
   if (for_drop)
     run_type |= views::MenuRunner::FOR_DROP;
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
index 338b9cd..546bda3 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
@@ -127,7 +127,7 @@
       next_menu_id_(IDC_FIRST_UNBOUNDED_MENU),
       real_delegate_(nullptr),
       is_mutating_model_(false),
-      location_(BOOKMARK_LAUNCH_LOCATION_NONE) {}
+      location_(BookmarkLaunchLocation::kNone) {}
 
 BookmarkMenuDelegate::~BookmarkMenuDelegate() {
   GetBookmarkModel()->RemoveObserver(this);
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate_unittest.cc
index 9b87ecd..5d744c0 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate_unittest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate_unittest.cc
@@ -89,7 +89,7 @@
     NewDelegate();
     bookmark_menu_delegate_->Init(&test_delegate_, nullptr, node, 0,
                                   BookmarkMenuDelegate::SHOW_PERMANENT_FOLDERS,
-                                  BOOKMARK_LAUNCH_LOCATION_NONE);
+                                  BookmarkLaunchLocation::kNone);
   }
 
   const BookmarkNode* GetNodeForMenuItem(views::MenuItemView* menu) {
@@ -204,7 +204,7 @@
   NewDelegate();
   bookmark_menu_delegate_->Init(&test_delegate, nullptr, node, 0,
                                 BookmarkMenuDelegate::HIDE_PERMANENT_FOLDERS,
-                                BOOKMARK_LAUNCH_LOCATION_NONE);
+                                BookmarkLaunchLocation::kNone);
   LoadAllMenus();
   std::vector<const BookmarkNode*> nodes_to_remove = {
       node->children()[1].get(),
@@ -222,7 +222,7 @@
   NewDelegate();
   bookmark_menu_delegate_->Init(&test_delegate, nullptr, node, 0,
                                 BookmarkMenuDelegate::HIDE_PERMANENT_FOLDERS,
-                                BOOKMARK_LAUNCH_LOCATION_NONE);
+                                BookmarkLaunchLocation::kNone);
   // Any nodes on the bookmark bar should close on remove.
   EXPECT_TRUE(
       ShouldCloseOnRemove(model_->bookmark_bar_node()->children()[2].get()));
@@ -243,7 +243,7 @@
   NewDelegate();
   bookmark_menu_delegate_->Init(&test_delegate, nullptr, node, 0,
                                 BookmarkMenuDelegate::HIDE_PERMANENT_FOLDERS,
-                                BOOKMARK_LAUNCH_LOCATION_NONE);
+                                BookmarkLaunchLocation::kNone);
   // Any nodes on the bookmark bar should close on remove.
   EXPECT_TRUE(ShouldCloseOnRemove(model_->other_node()->children()[0].get()));
 }
@@ -254,7 +254,7 @@
   NewDelegate();
   bookmark_menu_delegate_->Init(&test_delegate, nullptr, node, 0,
                                 BookmarkMenuDelegate::HIDE_PERMANENT_FOLDERS,
-                                BOOKMARK_LAUNCH_LOCATION_NONE);
+                                BookmarkLaunchLocation::kNone);
   LoadAllMenus();
 
   views::MenuItemView* root_item = bookmark_menu_delegate_->menu();
@@ -284,7 +284,7 @@
   NewDelegate();
   bookmark_menu_delegate_->Init(&test_delegate, nullptr, node, 0,
                                 BookmarkMenuDelegate::HIDE_PERMANENT_FOLDERS,
-                                BOOKMARK_LAUNCH_LOCATION_NONE);
+                                BookmarkLaunchLocation::kNone);
   LoadAllMenus();
 
   views::MenuItemView* root_item = bookmark_menu_delegate_->menu();
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 5482f26..4f1cee2 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -4325,8 +4325,7 @@
 
   if (command_id == IDC_BOOKMARK_THIS_TAB) {
     UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint",
-                              BOOKMARK_ENTRY_POINT_ACCELERATOR,
-                              BOOKMARK_ENTRY_POINT_LIMIT);
+                              BookmarkEntryPoint::kAccelerator);
   }
   if (command_id == IDC_NEW_TAB &&
       browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP)) {
diff --git a/chrome/browser/ui/views/location_bar/star_view.cc b/chrome/browser/ui/views/location_bar/star_view.cc
index e01e712..96addc63 100644
--- a/chrome/browser/ui/views/location_bar/star_view.cc
+++ b/chrome/browser/ui/views/location_bar/star_view.cc
@@ -84,20 +84,19 @@
 }
 
 void StarView::OnExecuting(PageActionIconView::ExecuteSource execute_source) {
-  BookmarkEntryPoint entry_point = BOOKMARK_ENTRY_POINT_STAR_MOUSE;
+  BookmarkEntryPoint entry_point = BookmarkEntryPoint::kStarMouse;
   switch (execute_source) {
     case EXECUTE_SOURCE_MOUSE:
-      entry_point = BOOKMARK_ENTRY_POINT_STAR_MOUSE;
+      entry_point = BookmarkEntryPoint::kStarMouse;
       break;
     case EXECUTE_SOURCE_KEYBOARD:
-      entry_point = BOOKMARK_ENTRY_POINT_STAR_KEY;
+      entry_point = BookmarkEntryPoint::kStarKey;
       break;
     case EXECUTE_SOURCE_GESTURE:
-      entry_point = BOOKMARK_ENTRY_POINT_STAR_GESTURE;
+      entry_point = BookmarkEntryPoint::kStarGesture;
       break;
   }
-  UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint", entry_point,
-                            BOOKMARK_ENTRY_POINT_LIMIT);
+  UMA_HISTOGRAM_ENUMERATION("Bookmarks.EntryPoint", entry_point);
 }
 
 void StarView::ExecuteCommand(ExecuteSource source) {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 41210e7..defd75f 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/omnibox/browser/actions/omnibox_pedal.h"
+#include "components/omnibox/browser/autocomplete_match_type.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_popup_selection.h"
 #include "components/omnibox/browser/vector_icons.h"
@@ -283,7 +284,7 @@
   SetBackground(GetPopupCellBackground(this, state));
 
   // Reapply the dim color to account for the highlight state.
-  const bool selected = state == OmniboxPartState::SELECTED;
+  const bool selected = (state == OmniboxPartState::SELECTED);
   const ui::ColorId dimmed_id = selected
                                     ? kColorOmniboxResultsTextDimmedSelected
                                     : kColorOmniboxResultsTextDimmed;
@@ -384,6 +385,12 @@
 }
 
 OmniboxPartState OmniboxResultView::GetThemeState() const {
+  // NULL_RESULT_MESSAGE matches are no-op suggestions that only deliver a
+  // message. The selected and hovered states imply an action can be taken from
+  // that suggestion, so do not allow those states for this result.
+  if (match_.type == AutocompleteMatchType::NULL_RESULT_MESSAGE)
+    return OmniboxPartState::NORMAL;
+
   if (GetMatchSelected())
     return OmniboxPartState::SELECTED;
 
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc
index 569dd8b..f0d6533 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.cc
@@ -13,6 +13,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_constants.h"
 
+using read_anything::mojom::ReadAnythingTheme;
+
 ReadAnythingModel::ReadAnythingModel()
     : font_name_(kReadAnythingDefaultFontName),
       font_scale_(kReadAnythingDefaultFontScale),
@@ -33,9 +35,8 @@
 
 void ReadAnythingModel::AddObserver(Observer* obs) {
   observers_.AddObserver(obs);
-  NotifyFontNameUpdated();
   NotifyAXTreeDistilled();
-  NotifyFontSizeChanged();
+  NotifyThemeChanged();
 }
 
 void ReadAnythingModel::RemoveObserver(Observer* obs) {
@@ -48,7 +49,7 @@
 
   // Update state and notify listeners
   font_name_ = font_model_->GetFontNameAt(new_index);
-  NotifyFontNameUpdated();
+  NotifyThemeChanged();
 }
 
 void ReadAnythingModel::SetDistilledAXTree(
@@ -66,7 +67,7 @@
   if (font_scale_ < kReadAnythingMinimumFontScale)
     font_scale_ = kReadAnythingMinimumFontScale;
 
-  NotifyFontSizeChanged();
+  NotifyThemeChanged();
 }
 
 void ReadAnythingModel::IncreaseTextSize() {
@@ -74,13 +75,7 @@
   if (font_scale_ > kReadAnythingMaximumFontScale)
     font_scale_ = kReadAnythingMaximumFontScale;
 
-  NotifyFontSizeChanged();
-}
-
-void ReadAnythingModel::NotifyFontNameUpdated() {
-  for (Observer& obs : observers_) {
-    obs.OnFontNameUpdated(font_name_);
-  }
+  NotifyThemeChanged();
 }
 
 void ReadAnythingModel::NotifyAXTreeDistilled() {
@@ -89,9 +84,10 @@
   }
 }
 
-void ReadAnythingModel::NotifyFontSizeChanged() {
+void ReadAnythingModel::NotifyThemeChanged() {
   for (Observer& obs : observers_) {
-    obs.OnFontSizeChanged(kReadAnythingDefaultFontSize * font_scale_);
+    obs.OnThemeChanged(ReadAnythingTheme::New(
+        font_name_, kReadAnythingDefaultFontSize * font_scale_));
   }
 }
 
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h
index e006890..add6e27 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model.h
@@ -62,11 +62,11 @@
  public:
   class Observer : public base::CheckedObserver {
    public:
-    virtual void OnFontNameUpdated(const std::string& new_font_name) = 0;
     virtual void OnAXTreeDistilled(
         const ui::AXTreeUpdate& snapshot,
         const std::vector<ui::AXNodeID>& content_node_ids) = 0;
-    virtual void OnFontSizeChanged(const float new_font_size) = 0;
+    virtual void OnThemeChanged(
+        read_anything::mojom::ReadAnythingThemePtr new_theme) = 0;
   };
 
   ReadAnythingModel();
@@ -91,15 +91,15 @@
 
  private:
   void NotifyAXTreeDistilled();
-  void NotifyFontNameUpdated();
-  void NotifyFontSizeChanged();
+  void NotifyThemeChanged();
 
   // State:
+
+  // Members of read_anything::mojom::ReadAnythingTheme:
   std::string font_name_;
 
-  // Font scale, a double to multiply the default font size by to get the user
-  // preferred font size. This number is opaque to the user.
-  double font_scale_;
+  // A scale multiplier for font size (internal use only, not shown to user).
+  float font_scale_;
 
   // TODO(crbug.com/1266555): Use |snapshot_| and |content_node_ids_| to keep
   // scrolls in sync.
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc
index 1a32434..d3de682 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_model_unittest.cc
@@ -14,21 +14,21 @@
 
 #include "ui/accessibility/accessibility_features.h"
 
+using read_anything::mojom::ReadAnythingThemePtr;
 using testing::_;
 using testing::FloatNear;
 
 class MockReadAnythingModelObserver : public ReadAnythingModel::Observer {
  public:
   MOCK_METHOD(void,
-              OnFontNameUpdated,
-              (const std::string& new_font_name),
-              (override));
-  MOCK_METHOD(void,
               OnAXTreeDistilled,
               (const ui::AXTreeUpdate& snapshot,
                const std::vector<ui::AXNodeID>& content_node_ids),
               (override));
-  MOCK_METHOD(void, OnFontSizeChanged, (const float new_font_size), (override));
+  MOCK_METHOD(void,
+              OnThemeChanged,
+              (ReadAnythingThemePtr new_theme),
+              (override));
 };
 
 class ReadAnythingModelTest : public TestWithBrowserView {
@@ -62,13 +62,11 @@
 TEST_F(ReadAnythingModelTest, AddingModelObserverNotifiesAllObservers) {
   model_->AddObserver(&model_observer_1_);
 
-  EXPECT_CALL(model_observer_1_, OnFontNameUpdated(_)).Times(1);
   EXPECT_CALL(model_observer_1_, OnAXTreeDistilled(_, _)).Times(1);
-  EXPECT_CALL(model_observer_1_, OnFontSizeChanged(_)).Times(1);
+  EXPECT_CALL(model_observer_1_, OnThemeChanged(_)).Times(1);
 
-  EXPECT_CALL(model_observer_2_, OnFontNameUpdated(_)).Times(1);
   EXPECT_CALL(model_observer_2_, OnAXTreeDistilled(_, _)).Times(1);
-  EXPECT_CALL(model_observer_2_, OnFontSizeChanged(_)).Times(1);
+  EXPECT_CALL(model_observer_2_, OnThemeChanged(_)).Times(1);
 
   model_->AddObserver(&model_observer_2_);
 }
@@ -77,17 +75,14 @@
   model_->AddObserver(&model_observer_1_);
   model_->AddObserver(&model_observer_2_);
 
-  EXPECT_CALL(model_observer_1_, OnFontNameUpdated(_)).Times(1);
   EXPECT_CALL(model_observer_1_, OnAXTreeDistilled(_, _)).Times(1);
-  EXPECT_CALL(model_observer_1_, OnFontSizeChanged(_)).Times(1);
+  EXPECT_CALL(model_observer_1_, OnThemeChanged(_)).Times(1);
 
-  EXPECT_CALL(model_observer_2_, OnFontNameUpdated(_)).Times(0);
   EXPECT_CALL(model_observer_2_, OnAXTreeDistilled(_, _)).Times(0);
-  EXPECT_CALL(model_observer_2_, OnFontSizeChanged(_)).Times(0);
+  EXPECT_CALL(model_observer_2_, OnThemeChanged(_)).Times(0);
 
-  EXPECT_CALL(model_observer_3_, OnFontNameUpdated(_)).Times(1);
   EXPECT_CALL(model_observer_3_, OnAXTreeDistilled(_, _)).Times(1);
-  EXPECT_CALL(model_observer_3_, OnFontSizeChanged(_)).Times(1);
+  EXPECT_CALL(model_observer_3_, OnThemeChanged(_)).Times(1);
 
   model_->RemoveObserver(&model_observer_2_);
   model_->AddObserver(&model_observer_3_);
@@ -96,7 +91,7 @@
 TEST_F(ReadAnythingModelTest, NotificationsOnSetSelectedFontIndex) {
   model_->AddObserver(&model_observer_1_);
 
-  EXPECT_CALL(model_observer_1_, OnFontNameUpdated("Serif")).Times(1);
+  EXPECT_CALL(model_observer_1_, OnThemeChanged(_)).Times(1);
 
   model_->SetSelectedFontByIndex(2);
 }
@@ -114,8 +109,7 @@
 TEST_F(ReadAnythingModelTest, NotificationsOnDecreasedFontSize) {
   model_->AddObserver(&model_observer_1_);
 
-  EXPECT_CALL(model_observer_1_, OnFontSizeChanged(FloatNear(14.4, 0.01)))
-      .Times(1);
+  EXPECT_CALL(model_observer_1_, OnThemeChanged(_)).Times(1);
 
   model_->DecreaseTextSize();
 
@@ -125,8 +119,7 @@
 TEST_F(ReadAnythingModelTest, NotificationsOnIncreasedFontSize) {
   model_->AddObserver(&model_observer_1_);
 
-  EXPECT_CALL(model_observer_1_, OnFontSizeChanged(FloatNear(21.6, 0.01)))
-      .Times(1);
+  EXPECT_CALL(model_observer_1_, OnThemeChanged(_)).Times(1);
 
   model_->IncreaseTextSize();
 
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index 04e0b97..e28666e 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -1249,7 +1249,7 @@
   bookmark_menu_delegate_->Init(this, bookmark_menu_,
                                 model->bookmark_bar_node(), 0,
                                 BookmarkMenuDelegate::SHOW_PERMANENT_FOLDERS,
-                                BOOKMARK_LAUNCH_LOCATION_APP_MENU);
+                                BookmarkLaunchLocation::kAppMenu);
 }
 
 size_t AppMenu::ModelIndexFromCommandId(int command_id) const {
diff --git a/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc
index f2cc84b..4a7d305 100644
--- a/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
@@ -18,6 +19,7 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/web_applications/commands/fetch_manifest_and_install_command.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/user_display_mode.h"
@@ -30,6 +32,7 @@
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "components/webapps/browser/install_result_code.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
@@ -257,10 +260,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppTabStripBrowserTest, NewTabUrl) {
-  GURL start_url = embedded_test_server()->GetURL(
-      "/banners/"
-      "manifest_test_page.html?manifest=manifest_tab_strip_customizations."
-      "json");
+  GURL start_url =
+      embedded_test_server()->GetURL("/web_apps/tab_strip_customizations.html");
   AppId app_id = InstallWebAppFromPage(browser(), start_url);
   Browser* app_browser = LaunchWebAppBrowser(browser()->profile(), app_id);
 
@@ -269,7 +270,120 @@
   chrome::NewTab(app_browser);
   EXPECT_EQ(
       app_browser->tab_strip_model()->GetActiveWebContents()->GetVisibleURL(),
-      embedded_test_server()->GetURL("/banners/theme-color.html"));
+      embedded_test_server()->GetURL("/web_apps/favicon_only.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppTabStripBrowserTest, InstallingPinsHomeTab) {
+  GURL start_url = embedded_test_server()->GetURL(
+      "/web_apps/tab_strip_customizations.html?some_query#blah");
+  AppId app_id = InstallWebAppFromPage(browser(), start_url);
+  Browser* app_browser = FindWebAppBrowser(browser()->profile(), app_id);
+  TabStripModel* tab_strip = app_browser->tab_strip_model();
+
+  EXPECT_TRUE(registrar().IsTabbedWindowModeEnabled(app_id));
+
+  EXPECT_EQ(tab_strip->count(), 1);
+  EXPECT_TRUE(tab_strip->IsTabPinned(0));
+  // The URL of the pinned home tab should include the query params.
+  EXPECT_EQ(tab_strip->GetWebContentsAt(0)->GetVisibleURL(), start_url);
+  EXPECT_EQ(tab_strip->active_index(), 0);
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppTabStripBrowserTest, InstallFromNonHomeTabUrl) {
+  GURL start_url = embedded_test_server()->GetURL(
+      "/web_apps/get_manifest.html?tab_strip_customizations.json");
+  AppId app_id = InstallWebAppFromPage(browser(), start_url);
+  Browser* app_browser = FindWebAppBrowser(browser()->profile(), app_id);
+  TabStripModel* tab_strip = app_browser->tab_strip_model();
+
+  EXPECT_TRUE(registrar().IsTabbedWindowModeEnabled(app_id));
+
+  // Expect the home tab was opened in addition to the launch URL.
+  EXPECT_EQ(tab_strip->count(), 2);
+  EXPECT_TRUE(tab_strip->IsTabPinned(0));
+  EXPECT_EQ(tab_strip->GetWebContentsAt(0)->GetVisibleURL(),
+            registrar().GetAppStartUrl(app_id));
+  EXPECT_EQ(tab_strip->active_index(), 1);
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppTabStripBrowserTest, OpeningPinsHomeTab) {
+  GURL start_url =
+      embedded_test_server()->GetURL("/web_apps/tab_strip_customizations.html");
+  // Install and close app.
+  AppId app_id = InstallWebAppFromPage(browser(), start_url);
+  Browser* app_browser = FindWebAppBrowser(browser()->profile(), app_id);
+  CloseAndWait(app_browser);
+
+  // Launch the app to a non home tab URL.
+  app_browser = LaunchWebAppToURL(
+      browser()->profile(), app_id,
+      embedded_test_server()->GetURL("/web_apps/favicon_only.html"));
+  TabStripModel* tab_strip = app_browser->tab_strip_model();
+
+  EXPECT_TRUE(registrar().IsTabbedWindowModeEnabled(app_id));
+
+  // Expect the home tab was opened in addition to the launch URL.
+  EXPECT_EQ(tab_strip->count(), 2);
+  EXPECT_TRUE(tab_strip->IsTabPinned(0));
+  EXPECT_EQ(tab_strip->GetWebContentsAt(0)->GetVisibleURL(),
+            registrar().GetAppStartUrl(app_id));
+  EXPECT_EQ(tab_strip->active_index(), 1);
+
+  // Open app at home tab URL.
+  EXPECT_EQ(app_browser,
+            LaunchWebAppToURL(browser()->profile(), app_id, start_url));
+
+  // Expect the home tab to be focused.
+  EXPECT_EQ(tab_strip->count(), 2);
+  EXPECT_TRUE(tab_strip->IsTabPinned(0));
+  EXPECT_EQ(tab_strip->GetWebContentsAt(0)->GetVisibleURL(), start_url);
+  EXPECT_EQ(tab_strip->active_index(), 0);
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppTabStripBrowserTest, ReparentingPinsHomeTab) {
+  GURL start_url =
+      embedded_test_server()->GetURL("/web_apps/tab_strip_customizations.html");
+  // Install and close app.
+  AppId app_id = InstallWebAppFromPage(browser(), start_url);
+  Browser* app_browser = FindWebAppBrowser(browser()->profile(), app_id);
+  CloseAndWait(app_browser);
+
+  // Navigate to the app URL in the browser.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL("/web_apps/favicon_only.html")));
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Reparent web contents into app browser.
+  app_browser =
+      web_app::ReparentWebContentsIntoAppBrowser(web_contents, app_id);
+  TabStripModel* tab_strip = app_browser->tab_strip_model();
+
+  // Expect the pinned home tab to also be opened.
+  EXPECT_EQ(tab_strip->count(), 2);
+  EXPECT_TRUE(tab_strip->IsTabPinned(0));
+  EXPECT_EQ(tab_strip->GetWebContentsAt(0)->GetVisibleURL(),
+            registrar().GetAppStartUrl(app_id));
+  EXPECT_EQ(tab_strip->active_index(), 1);
+
+  // Navigate to home tab URL in the browser.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL(
+                     "/web_apps/tab_strip_customizations.html")));
+  web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Reparent web contents into app browser.
+  EXPECT_EQ(app_browser,
+            web_app::ReparentWebContentsIntoAppBrowser(web_contents, app_id));
+  tab_strip = app_browser->tab_strip_model();
+
+  // Expect home tab to be focused.
+  EXPECT_EQ(tab_strip->count(), 2);
+  EXPECT_TRUE(tab_strip->IsTabPinned(0));
+  EXPECT_EQ(tab_strip->GetWebContentsAt(0)->GetVisibleURL(),
+            registrar().GetAppStartUrl(app_id));
+  EXPECT_EQ(tab_strip->active_index(), 0);
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/ui/web_applications/app_browser_controller.cc b/chrome/browser/ui/web_applications/app_browser_controller.cc
index 1420b335..38ef15d3 100644
--- a/chrome/browser/ui/web_applications/app_browser_controller.cc
+++ b/chrome/browser/ui/web_applications/app_browser_controller.cc
@@ -403,10 +403,11 @@
   if (selection.active_tab_changed()) {
     content::WebContentsObserver::Observe(selection.new_contents);
     // Update themes when we switch tabs, or create the first tab, but not
-    // when we create 2nd or subsequent tabs. They should keep current theme
-    // until page loads. See |DOMContentLoaded|.
+    // when we create 2nd or subsequent tabs. Don't update the theme if the
+    // tab has not finished loading to avoid using uninitialized colors,
+    // wait for |DOMContentLoaded| before updating.
     if (change.type() != TabStripModelChange::kInserted ||
-        tab_strip_model->count() == 1) {
+        tab_strip_model->count() == 1 || !selection.new_contents->IsLoading()) {
       UpdateThemePack();
     }
   }
diff --git a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
index fcb23cba..fc3fde2a 100644
--- a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
+++ b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
@@ -236,6 +236,24 @@
   return browser;
 }
 
+Browser* LaunchWebAppToURL(Profile* profile,
+                           const AppId& app_id,
+                           const GURL& url) {
+  apps::AppLaunchParams params(
+      app_id, apps::LaunchContainer::kLaunchContainerWindow,
+      WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromCommandLine);
+  params.override_url = url;
+  content::WebContents* const web_contents =
+      apps::AppServiceProxyFactory::GetForProfile(profile)
+          ->BrowserAppLauncher()
+          ->LaunchAppWithParamsForTesting(std::move(params));
+  EXPECT_TRUE(web_contents);
+
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+  EXPECT_TRUE(AppBrowserController::IsForWebApp(browser, app_id));
+  return browser;
+}
+
 ExternalInstallOptions CreateInstallOptions(
     const GURL& url,
     const ExternalInstallSource& source) {
diff --git a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h
index 4068aef..9af11db8 100644
--- a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h
+++ b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.h
@@ -65,6 +65,11 @@
 // Launches a new tab for |app| in |profile|.
 Browser* LaunchBrowserForWebAppInTab(Profile*, const AppId&);
 
+// Launches the web app to the given URL.
+Browser* LaunchWebAppToURL(Profile* profile,
+                           const AppId& app_id,
+                           const GURL& url);
+
 // Return |ExternalInstallOptions| with OS shortcut creation disabled.
 ExternalInstallOptions CreateInstallOptions(
     const GURL& url,
diff --git a/chrome/browser/ui/web_applications/web_app_launch_process.cc b/chrome/browser/ui/web_applications/web_app_launch_process.cc
index abf11e6a..56d49f4 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_process.cc
+++ b/chrome/browser/ui/web_applications/web_app_launch_process.cc
@@ -184,6 +184,10 @@
 
 WindowOpenDisposition WebAppLaunchProcess::GetNavigationDisposition(
     bool is_new_browser) const {
+  if (provider_.registrar().IsTabbedWindowModeEnabled(params_.app_id)) {
+    return WindowOpenDisposition::NEW_FOREGROUND_TAB;
+  }
+
   if (is_new_browser) {
     // By opening a new window we've already performed part of a "disposition",
     // the only remaining thing for Navigate() to do is navigate the new window.
diff --git a/chrome/browser/ui/web_applications/web_app_launch_utils.cc b/chrome/browser/ui/web_applications/web_app_launch_utils.cc
index 1e11dfd..0823d1d 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_utils.cc
+++ b/chrome/browser/ui/web_applications/web_app_launch_utils.cc
@@ -30,10 +30,12 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/ui/web_applications/web_app_browser_controller.h"
+#include "chrome/browser/ui/web_applications/web_app_tabbed_utils.h"
 #include "chrome/browser/web_applications/web_app_constants.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_install_utils.h"
@@ -81,7 +83,9 @@
 }
 
 Browser* ReparentWebContentsIntoAppBrowser(content::WebContents* contents,
-                                           Browser* target_browser) {
+                                           Browser* target_browser,
+                                           const AppId& app_id,
+                                           bool as_pinned_home_tab) {
   DCHECK(target_browser->is_type_app());
   Browser* source_browser = chrome::FindBrowserWithWebContents(contents);
 
@@ -92,14 +96,39 @@
   service->TabClosing(contents);
 
   TabStripModel* source_tabstrip = source_browser->tab_strip_model();
+  TabStripModel* target_tabstrip = target_browser->tab_strip_model();
+
   // Avoid causing the existing browser window to close if this is the last tab
   // remaining.
   if (source_tabstrip->count() == 1)
     chrome::NewTab(source_browser);
-  target_browser->tab_strip_model()->AppendWebContents(
-      source_tabstrip->DetachWebContentsAtForInsertion(
-          source_tabstrip->GetIndexOfWebContents(contents)),
-      true);
+
+  if (as_pinned_home_tab) {
+    if (HasPinnedHomeTab(target_tabstrip)) {
+      // Insert the web contents into the pinned home tab and delete the
+      // existing home tab.
+      target_tabstrip->InsertWebContentsAt(
+          /*index=*/0,
+          source_tabstrip->DetachWebContentsAtForInsertion(
+              source_tabstrip->GetIndexOfWebContents(contents)),
+          (TabStripModel::ADD_INHERIT_OPENER | TabStripModel::ADD_ACTIVE |
+           TabStripModel::ADD_PINNED));
+      target_tabstrip->DetachAndDeleteWebContentsAt(1);
+    } else {
+      target_tabstrip->InsertWebContentsAt(
+          /*index=*/0,
+          source_tabstrip->DetachWebContentsAtForInsertion(
+              source_tabstrip->GetIndexOfWebContents(contents)),
+          (TabStripModel::ADD_INHERIT_OPENER | TabStripModel::ADD_ACTIVE |
+           TabStripModel::ADD_PINNED));
+    }
+  } else {
+    MaybeAddPinnedHomeTab(target_browser, app_id);
+    target_tabstrip->AppendWebContents(
+        source_tabstrip->DetachWebContentsAtForInsertion(
+            source_tabstrip->GetIndexOfWebContents(contents)),
+        true);
+  }
   target_browser->window()->Show();
 
   // The app window will be registered correctly, however the tab will not
@@ -182,10 +211,13 @@
                 extensions::AppLaunchSource::kSourceReparenting, launch_url,
                 contents);
 
+  bool as_pinned_home_tab = IsPinnedHomeTabUrl(registrar, app_id, launch_url);
+
   if (registrar.IsTabbedWindowModeEnabled(app_id)) {
     for (Browser* browser : *BrowserList::GetInstance()) {
       if (AppBrowserController::IsForWebApp(browser, app_id))
-        return ReparentWebContentsIntoAppBrowser(contents, browser);
+        return ReparentWebContentsIntoAppBrowser(contents, browser, app_id,
+                                                 as_pinned_home_tab);
     }
   }
 
@@ -193,7 +225,8 @@
       contents,
       Browser::Create(Browser::CreateParams::CreateForApp(
           GenerateApplicationNameFromAppId(app_id), true /* trusted_source */,
-          gfx::Rect(), profile, true /* user_gesture */)));
+          gfx::Rect(), profile, true /* user_gesture */)),
+      app_id, as_pinned_home_tab);
 }
 
 void SetWebContentsActingAsApp(content::WebContents* contents,
@@ -264,6 +297,23 @@
   return controller;
 }
 
+void MaybeAddPinnedHomeTab(Browser* browser, const std::string& app_id) {
+  WebAppRegistrar& registrar =
+      WebAppProvider::GetForLocalAppsUnchecked(browser->profile())->registrar();
+  absl::optional<GURL> pinned_home_tab_url =
+      registrar.GetAppPinnedHomeTabUrl(app_id);
+
+  if (registrar.IsTabbedWindowModeEnabled(app_id) &&
+      !HasPinnedHomeTab(browser->tab_strip_model()) &&
+      pinned_home_tab_url.has_value()) {
+    NavigateParams home_tab_nav_params(browser, pinned_home_tab_url.value(),
+                                       ui::PAGE_TRANSITION_AUTO_BOOKMARK);
+    home_tab_nav_params.disposition = WindowOpenDisposition::NEW_BACKGROUND_TAB;
+    home_tab_nav_params.tabstrip_add_types |= TabStripModel::ADD_PINNED;
+    Navigate(&home_tab_nav_params);
+  }
+}
+
 Browser* CreateWebApplicationWindow(Profile* profile,
                                     const std::string& app_id,
                                     WindowOpenDisposition disposition,
@@ -289,7 +339,9 @@
   browser_params.can_resize = can_resize;
   browser_params.can_maximize = can_maximize;
   browser_params.are_tab_groups_enabled = false;
-  return Browser::Create(browser_params);
+  Browser* browser = Browser::Create(browser_params);
+  MaybeAddPinnedHomeTab(browser, app_id);
+  return browser;
 }
 
 content::WebContents* NavigateWebApplicationWindow(
@@ -304,6 +356,17 @@
 
 content::WebContents* NavigateWebAppUsingParams(const std::string& app_id,
                                                 NavigateParams& nav_params) {
+  WebAppRegistrar& registrar =
+      WebAppProvider::GetForLocalAppsUnchecked(nav_params.browser->profile())
+          ->registrar();
+
+  if (IsPinnedHomeTabUrl(registrar, app_id, nav_params.url)) {
+    // Navigations to the home tab URL in tabbed apps should happen in the home
+    // tab.
+    nav_params.browser->tab_strip_model()->ActivateTabAt(0);
+    nav_params.disposition = WindowOpenDisposition::CURRENT_TAB;
+  }
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   Browser* browser = nav_params.browser;
   const absl::optional<ash::SystemWebAppType> capturing_system_app_type =
diff --git a/chrome/browser/ui/web_applications/web_app_launch_utils.h b/chrome/browser/ui/web_applications/web_app_launch_utils.h
index 27a5e713..af58069 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_utils.h
+++ b/chrome/browser/ui/web_applications/web_app_launch_utils.h
@@ -60,6 +60,8 @@
 std::unique_ptr<AppBrowserController> MaybeCreateAppBrowserController(
     Browser* browser);
 
+void MaybeAddPinnedHomeTab(Browser* browser, const std::string& app_id);
+
 Browser* CreateWebApplicationWindow(Profile* profile,
                                     const std::string& app_id,
                                     WindowOpenDisposition disposition,
diff --git a/chrome/browser/ui/web_applications/web_app_tabbed_utils.cc b/chrome/browser/ui/web_applications/web_app_tabbed_utils.cc
new file mode 100644
index 0000000..62b084e
--- /dev/null
+++ b/chrome/browser/ui/web_applications/web_app_tabbed_utils.cc
@@ -0,0 +1,36 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/web_applications/web_app_tabbed_utils.h"
+
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace web_app {
+
+bool HasPinnedHomeTab(TabStripModel* tab_strip_model) {
+  if (!tab_strip_model->ContainsIndex(0))
+    return false;
+  return tab_strip_model->IsTabPinned(0);
+}
+
+bool IsPinnedHomeTabUrl(const WebAppRegistrar& registrar,
+                        const AppId& app_id,
+                        GURL launch_url) {
+  if (!registrar.IsTabbedWindowModeEnabled(app_id))
+    return false;
+
+  absl::optional<GURL> pinned_home_url =
+      registrar.GetAppPinnedHomeTabUrl(app_id);
+  if (!pinned_home_url)
+    return false;
+
+  // A launch URL which is the home tab URL with query params and
+  // hash ref should be opened as the home tab.
+  GURL::Replacements replacements;
+  replacements.ClearQuery();
+  replacements.ClearRef();
+  return launch_url.ReplaceComponents(replacements) == pinned_home_url.value();
+}
+
+}  // namespace web_app
diff --git a/chrome/browser/ui/web_applications/web_app_tabbed_utils.h b/chrome/browser/ui/web_applications/web_app_tabbed_utils.h
new file mode 100644
index 0000000..6a36d173
--- /dev/null
+++ b/chrome/browser/ui/web_applications/web_app_tabbed_utils.h
@@ -0,0 +1,25 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_TABBED_UTILS_H_
+#define CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_TABBED_UTILS_H_
+
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/web_applications/web_app_id.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
+#include "url/gurl.h"
+
+namespace web_app {
+
+// Returns whether the web apps tab strip contains a pinned home tab.
+bool HasPinnedHomeTab(TabStripModel* tab_strip_model);
+
+// Returns whether the given launch_url should be treated as the home tab URL.
+bool IsPinnedHomeTabUrl(const WebAppRegistrar& registrar,
+                        const AppId& app_id,
+                        GURL launch_url);
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_UI_WEB_APPLICATIONS_WEB_APP_TABBED_UTILS_H_
diff --git a/chrome/browser/ui/webui/realbox/realbox_handler.cc b/chrome/browser/ui/webui/realbox/realbox_handler.cc
index 0768a30..afdebc6 100644
--- a/chrome/browser/ui/webui/realbox/realbox_handler.cc
+++ b/chrome/browser/ui/webui/realbox/realbox_handler.cc
@@ -605,7 +605,7 @@
 
   auto* bookmark_model = BookmarkModelFactory::GetForBrowserContext(profile_);
   if (bookmark_model->IsBookmarked(match.destination_url)) {
-    RecordBookmarkLaunch(BOOKMARK_LAUNCH_LOCATION_OMNIBOX,
+    RecordBookmarkLaunch(BookmarkLaunchLocation::kOmnibox,
                          profile_metrics::GetBrowserProfileType(profile_));
   }
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_section.cc b/chrome/browser/ui/webui/settings/chromeos/device_section.cc
index 30f8e2591..9cc12f7 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_section.cc
@@ -760,6 +760,7 @@
       {"audioTitle", IDS_SETTINGS_AUDIO_TITLE},
       {"audioOutputTitle", IDS_SETTINGS_AUDIO_OUTPUT_TITLE},
       {"audioVolumeTitle", IDS_SETTINGS_AUDIO_VOLUME_TITLE},
+      {"audioDeviceTitle", IDS_SETTINGS_AUDIO_DEVICE_TITLE},
   };
 
   html_source->AddLocalizedStrings(kAudioStrings);
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 5c39581..f566fcf 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -875,280 +875,276 @@
                         Profile* profile,
                         content::WebContents* web_contents) {
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
-      {"autofillPageTitle", IDS_SETTINGS_AUTOFILL},
-      {"passwordsDescription", IDS_SETTINGS_PASSWORD_MANAGER_DESCRIPTION},
-      {"passwordsDevice", IDS_SETTINGS_DEVICE_PASSWORDS},
-      {"checkPasswords", IDS_SETTINGS_CHECK_PASSWORDS},
-      {"checkPasswordsCanceled", IDS_SETTINGS_CHECK_PASSWORDS_CANCELED},
-      {"checkedPasswords", IDS_SETTINGS_CHECKED_PASSWORDS},
-      {"checkPasswordsDescription", IDS_SETTINGS_CHECK_PASSWORDS_DESCRIPTION},
-      {"checkPasswordsErrorOffline",
-       IDS_SETTINGS_CHECK_PASSWORDS_ERROR_OFFLINE},
-      {"checkPasswordsErrorSignedOut",
-       IDS_SETTINGS_CHECK_PASSWORDS_ERROR_SIGNED_OUT},
-      {"checkPasswordsErrorNoPasswords",
-       IDS_SETTINGS_CHECK_PASSWORDS_ERROR_NO_PASSWORDS},
-      {"checkPasswordsErrorQuota",
-       IDS_SETTINGS_CHECK_PASSWORDS_ERROR_QUOTA_LIMIT},
-      {"checkPasswordsErrorGeneric",
-       IDS_SETTINGS_CHECK_PASSWORDS_ERROR_GENERIC},
-      {"noCompromisedCredentials",
-       IDS_SETTINGS_NO_COMPROMISED_CREDENTIALS_LABEL},
-      {"checkPasswordsAgain", IDS_SETTINGS_CHECK_PASSWORDS_AGAIN},
-      {"checkPasswordsAgainAfterError",
-       IDS_SETTINGS_CHECK_PASSWORDS_AGAIN_AFTER_ERROR},
-      {"checkPasswordsProgress", IDS_SETTINGS_CHECK_PASSWORDS_PROGRESS},
-      {"checkPasswordsStop", IDS_SETTINGS_CHECK_PASSWORDS_STOP},
-      {"compromisedPasswords", IDS_SETTINGS_COMPROMISED_PASSWORDS},
-      {"compromisedPasswordsDescription",
-       IDS_SETTINGS_COMPROMISED_PASSWORDS_ADVICE},
-      {"mutedPasswords", IDS_SETTINGS_MUTED_PASSWORDS},
-      {"weakPasswords", IDS_SETTINGS_WEAK_PASSWORDS},
-      {"changePasswordButton", IDS_SETTINGS_CHANGE_PASSWORD_BUTTON},
-      {"changePasswordInApp", IDS_SETTINGS_CHANGE_PASSWORD_IN_APP_LABEL},
-      {"leakedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_REASON_LEAKED},
-      {"phishedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_REASON_PHISHED},
-      {"phishedAndLeakedPassword",
-       IDS_SETTINGS_COMPROMISED_PASSWORD_REASON_PHISHED_AND_LEAKED},
-      {"showCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_SHOW},
-      {"hideCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_HIDE},
-      {"removeCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_REMOVE},
-      {"muteCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_MUTE},
-      {"unmuteMutedCompromisedPassword",
-       IDS_SETTINGS_COMPROMISED_PASSWORD_UNMUTE},
-      {"removeCompromisedPasswordConfirmationTitle",
-       IDS_SETTINGS_REMOVE_COMPROMISED_PASSWORD_CONFIRMATION_TITLE},
-      {"removeCompromisedPasswordConfirmationDescription",
-       IDS_SETTINGS_REMOVE_COMPROMISED_PASSWORD_CONFIRMATION_DESCRIPTION},
-      {"alreadyChangedPasswordLink",
-       IDS_SETTINGS_COMPROMISED_ALREADY_CHANGED_PASSWORD},
-      {"editDisclaimerTitle", IDS_SETTINGS_COMPROMISED_EDIT_DISCLAIMER_TITLE},
-      {"editDisclaimerDescription",
-       IDS_SETTINGS_COMPROMISED_EDIT_DISCLAIMER_DESCRIPTION},
-      {"genericCreditCard", IDS_AUTOFILL_CC_GENERIC},
-      {"creditCards", IDS_AUTOFILL_PAYMENT_METHODS},
-      {"noPaymentMethodsFound", IDS_SETTINGS_PAYMENT_METHODS_NONE},
-      {"googlePayments", IDS_SETTINGS_GOOGLE_PAYMENTS},
-      {"googlePaymentsCached", IDS_SETTINGS_GOOGLE_PAYMENTS_CACHED},
-      {"enableProfilesLabel", IDS_AUTOFILL_ENABLE_PROFILES_TOGGLE_LABEL},
-      {"enableProfilesSublabel", IDS_AUTOFILL_ENABLE_PROFILES_TOGGLE_SUBLABEL},
-      {"enableCreditCardsLabel", IDS_AUTOFILL_ENABLE_CREDIT_CARDS_TOGGLE_LABEL},
-      {"enableCreditCardsSublabel",
-       IDS_AUTOFILL_ENABLE_CREDIT_CARDS_TOGGLE_SUBLABEL},
-      {"enableCreditCardFIDOAuthLabel", IDS_ENABLE_CREDIT_CARD_FIDO_AUTH_LABEL},
-      {"enableCreditCardFIDOAuthSublabel",
-       IDS_ENABLE_CREDIT_CARD_FIDO_AUTH_SUBLABEL},
-      {"addresses", IDS_AUTOFILL_ADDRESSES},
-      {"addressesTitle", IDS_AUTOFILL_ADDRESSES_SETTINGS_TITLE},
-      {"addAddressTitle", IDS_SETTINGS_AUTOFILL_ADDRESSES_ADD_TITLE},
-      {"editAddressTitle", IDS_SETTINGS_AUTOFILL_ADDRESSES_EDIT_TITLE},
-      {"addressCountry", IDS_SETTINGS_AUTOFILL_ADDRESSES_COUNTRY},
-      {"addressPhone", IDS_SETTINGS_AUTOFILL_ADDRESSES_PHONE},
-      {"addressEmail", IDS_SETTINGS_AUTOFILL_ADDRESSES_EMAIL},
-      {"honorificLabel", IDS_SETTINGS_AUTOFILL_ADDRESS_HONORIFIC_LABEL},
-      {"moreActionsForAddress", IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_ADDRESS},
-      {"moreActionsForCreditCard",
-       IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_CREDIT_CARD},
-      {"moreActionsCreditCardDescription",
-       IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_CARD_DESCRIPTION},
-      {"removeAddress", IDS_SETTINGS_ADDRESS_REMOVE},
-      {"removeAddressConfirmationTitle",
-       IDS_SETTINGS_ADDRESS_REMOVE_CONFIRMATION_TITLE},
-      {"removeAddressConfirmationDescription",
-       IDS_SETTINGS_ADDRESS_REMOVE_CONFIRMATION_DESCRIPTION},
-      {"removeCreditCard", IDS_SETTINGS_CREDIT_CARD_REMOVE},
-      {"clearCreditCard", IDS_SETTINGS_CREDIT_CARD_CLEAR},
-      {"creditCardType", IDS_SETTINGS_AUTOFILL_CREDIT_CARD_TYPE_COLUMN_LABEL},
-      {"creditCardExpiration", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_DATE},
-      {"creditCardName", IDS_SETTINGS_NAME_ON_CREDIT_CARD},
-      {"creditCardNickname", IDS_SETTINGS_CREDIT_CARD_NICKNAME},
-      {"creditCardNicknameInvalid", IDS_SETTINGS_CREDIT_CARD_NICKNAME_INVALID},
-      {"creditCardNumber", IDS_SETTINGS_CREDIT_CARD_NUMBER},
-      {"creditCardExpirationMonth", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_MONTH},
-      {"creditCardExpirationYear", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_YEAR},
-      {"creditCardExpired", IDS_SETTINGS_CREDIT_CARD_EXPIRED},
-      {"editCreditCardTitle", IDS_SETTINGS_EDIT_CREDIT_CARD_TITLE},
-      {"addCreditCardTitle", IDS_SETTINGS_ADD_CREDIT_CARD_TITLE},
-      {"migrateCreditCardsLabel", IDS_SETTINGS_MIGRATABLE_CARDS_LABEL},
-      {"migratableCardsInfoSingle", IDS_SETTINGS_SINGLE_MIGRATABLE_CARD_INFO},
-      {"migratableCardsInfoMultiple",
-       IDS_SETTINGS_MULTIPLE_MIGRATABLE_CARDS_INFO},
-      {"remoteCreditCardLinkLabel", IDS_SETTINGS_REMOTE_CREDIT_CARD_LINK_LABEL},
-      {"upiIdLabel", IDS_SETTINGS_UPI_ID_LABEL},
-      {"upiIdExpirationNever", IDS_SETTINGS_UPI_ID_EXPIRATION_NEVER},
-      {"canMakePaymentToggleLabel", IDS_SETTINGS_CAN_MAKE_PAYMENT_TOGGLE_LABEL},
-      {"autofillDetail", IDS_SETTINGS_AUTOFILL_DETAIL},
-      {"passwordsSavePasswordsLabel",
-       IDS_SETTINGS_PASSWORDS_SAVE_PASSWORDS_TOGGLE_LABEL},
-      {"passwordsAutosigninLabel",
-       IDS_SETTINGS_PASSWORDS_AUTOSIGNIN_CHECKBOX_LABEL},
-      {"passwordsAutosigninDescription",
-       IDS_SETTINGS_PASSWORDS_AUTOSIGNIN_CHECKBOX_DESC},
-      {"passwordsLeakDetectionLabel",
-       IDS_SETTINGS_PASSWORDS_LEAK_DETECTION_LABEL},
-      {"passwordsLeakDetectionGeneralDescription",
-       IDS_PASSWORD_MANAGER_LEAK_HELP_MESSAGE},
-      {"passwordsLeakDetectionSignedOutEnabledDescription",
-       IDS_SETTINGS_PASSWORDS_LEAK_DETECTION_SIGNED_OUT_ENABLED_DESC},
-      {"savedPasswordsHeading", IDS_SETTINGS_PASSWORDS_SAVED_HEADING},
-      {"passwordExceptionsHeading", IDS_SETTINGS_PASSWORDS_EXCEPTIONS_HEADING},
-      {"deviceOnlyPasswordsHeading",
-       IDS_SETTINGS_DEVICE_PASSWORDS_ON_DEVICE_ONLY_HEADING},
-      {"deviceAndAccountPasswordsHeading",
-       IDS_SETTINGS_DEVICE_PASSWORDS_ON_DEVICE_AND_ACCOUNT_HEADING},
-      {"deletePasswordException", IDS_SETTINGS_PASSWORDS_DELETE_EXCEPTION},
-      {"removePassword", IDS_SETTINGS_PASSWORD_REMOVE},
-      {"searchPasswords", IDS_SETTINGS_PASSWORD_SEARCH},
-      {"showPassword", IDS_SETTINGS_PASSWORD_SHOW},
-      {"hidePassword", IDS_SETTINGS_PASSWORD_HIDE},
-      {"passwordDetailsTitle", IDS_SETTINGS_PASSWORDS_VIEW_DETAILS_TITLE},
-      {"passwordViewDetails", IDS_SETTINGS_PASSWORD_DETAILS},
-      {"editPasswordTitle", IDS_SETTINGS_PASSWORD_EDIT_TITLE},
-      {"editPassword", IDS_SETTINGS_PASSWORD_EDIT},
-      {"editPasswordFootnote", IDS_SETTINGS_PASSWORD_EDIT_FOOTNOTE},
-      {"addPasswordTitle", IDS_SETTINGS_PASSWORD_ADD_TITLE},
-      {"addPasswordFootnote", IDS_SETTINGS_PASSWORD_ADD_FOOTNOTE},
-      {"addPasswordStoreOptionAccount",
-       IDS_SETTINGS_PASSWORD_ADD_STORE_OPTION_ACCOUNT},
-      {"addPasswordStoreOptionDevice",
-       IDS_PASSWORD_MANAGER_DESTINATION_DROPDOWN_SAVE_TO_DEVICE},
-      {"addPasswordStorePickerA11yDescription",
-       IDS_PASSWORD_MANAGER_DESTINATION_DROPDOWN_ACCESSIBLE_NAME},
-      {"usernameAlreadyUsed", IDS_SETTINGS_PASSWORD_USERNAME_ALREADY_USED},
-      {"missingTLD", IDS_SETTINGS_PASSWORD_MISSING_TLD},
-      {"viewExistingPassword", IDS_SETTINGS_PASSWORD_VIEW_EXISTING_PASSWORD},
-      {"viewExistingPasswordAriaDescription",
-       IDS_SETTINGS_PASSWORD_VIEW_EXISTING_PASSWORD_ARIA_DESCRIPTION},
-      {"copyPassword", IDS_SETTINGS_PASSWORD_COPY},
-      {"sendPassword", IDS_SETTINGS_PASSWORD_SEND},
-      {"copyUsername", IDS_SETTINGS_USERNAME_COPY},
-      {"passwordStoredOnDevice", IDS_SETTINGS_PASSWORD_STORED_ON_DEVICE},
-      {"passwordStoredInAccount", IDS_SETTINGS_PASSWORD_STORED_IN_ACCOUNT},
-      {"passwordStoredInAccountAndOnDevice",
-       IDS_SETTINGS_PASSWORD_STORED_IN_ACCOUNT_AND_ON_DEVICE},
-      {"editPasswordWebsiteLabel", IDS_SETTINGS_PASSWORDS_WEBSITE},
-      {"editPasswordAppLabel", IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_APP},
-      {"editPasswordUsernameLabel", IDS_SETTINGS_PASSWORDS_USERNAME},
-      {"editPasswordPasswordLabel", IDS_SETTINGS_PASSWORDS_PASSWORD},
-      {"passwordNoteLabel", IDS_SETTINGS_PASSWORDS_NOTE},
-      {"passwordNoNoteAdded", IDS_SETTINGS_PASSWORDS_NO_NOTE_ADDED},
-      {"passwordNoteCharacterCount",
-       IDS_SETTINGS_PASSWORDS_NOTE_CHARACTER_COUNT},
-      {"passwordNoteCharacterCountWarning",
-       IDS_SETTINGS_PASSWORDS_NOTE_CHARACTER_COUNT_WARNING},
-      {"noAddressesFound", IDS_SETTINGS_ADDRESS_NONE},
-      {"noPasswordsFound", IDS_SETTINGS_PASSWORDS_NONE},
-      {"noExceptionsFound", IDS_SETTINGS_PASSWORDS_EXCEPTIONS_NONE},
-      {"optInAccountStorageLabel",
-       IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_LABEL},
-      {"optOutAccountStorageLabel",
-       IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_LABEL},
-      {"undoRemovePassword", IDS_SETTINGS_PASSWORD_UNDO},
-      {"movePasswordToAccount", IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT},
-      {"passwordDeleted", IDS_SETTINGS_PASSWORD_DELETED_PASSWORD},
-      {"passwordDeletedFromDevice",
-       IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_DEVICE},
-      {"passwordDeletedFromAccount",
-       IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_ACCOUNT},
-      {"passwordDeletedFromAccountAndDevice",
-       IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_ACCOUNT_AND_DEVICE},
-      {"passwordCopiedToClipboard", IDS_SETTINGS_PASSWORD_COPIED_TO_CLIPBOARD},
-      {"passwordUsernameCopiedToClipboard",
-       IDS_SETTINGS_PASSWORD_USERNAME_COPIED_TO_CLIPBOARD},
-      {"passwordMovePasswordsToAccount",
-       IDS_SETTINGS_PASSWORD_MOVE_PASSWORDS_TO_ACCOUNT},
-      {"passwordMovePasswordsToAccountDialogBodyText",
-       IDS_SETTINGS_PASSWORD_MOVE_PASSWORDS_TO_ACCOUNT_DIALOG_BODY_TEXT},
-      {"passwordMovePasswordsToAccountDialogTitle",
-       IDS_SETTINGS_PASSWORD_MOVE_PASSWORDS_TO_ACCOUNT_DIALOG_TITLE},
-      {"passwordMoveToAccountDialogTitle",
-       IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_TITLE},
-      {"passwordMoveToAccountDialogBody",
-       IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_BODY},
-      {"passwordMoveMultiplePasswordsToAccountDialogMoveButtonText",
-       IDS_SETTINGS_PASSWORD_MOVE_MULTIPLE_PASSWORDS_TO_ACCOUNT_DIALOG_MOVE_BUTTON_TEXT},
-      {"passwordMoveMultiplePasswordsToAccountDialogCancelButtonText",
-       IDS_SETTINGS_PASSWORD_MOVE_MULTIPLE_PASSWORDS_TO_ACCOUNT_DIALOG_CANCEL_BUTTON_TEXT},
-      {"passwordMoveToAccountDialogMoveButtonText",
-       IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_MOVE_BUTTON_TEXT},
-      {"passwordMoveToAccountDialogCancelButtonText",
-       IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_CANCEL_BUTTON_TEXT},
-      {"passwordOpenMoveMultiplePasswordsToAccountDialogButtonText",
-       IDS_SETTINGS_PASSWORD_OPEN_MOVE_MULTIPLE_PASSWORDS_TO_ACCOUNT_DIALOG_BUTTON_TEXT},
-      {"passwordRemoveDialogTitle", IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_TITLE},
-      {"passwordRemoveDialogBody", IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_BODY},
-      {"passwordRemoveDialogRemoveButtonText",
-       IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_REMOVE_BUTTON_TEXT},
-      {"passwordRemoveDialogCancelButtonText",
-       IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_CANCEL_BUTTON_TEXT},
-      {"passwordRemoveDialogFromAccountCheckboxLabel",
-       IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_FROM_ACCOUNT_CHECKBOX_LABEL},
-      {"passwordRemoveDialogFromDeviceCheckboxLabel",
-       IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_FROM_DEVICE_CHECKBOX_LABEL},
-      {"devicePasswordsLinkLabel", IDS_SETTINGS_DEVICE_PASSWORDS_LINK_LABEL},
-      {"devicePasswordsMoved",
-       IDS_SETTINGS_PASSWORD_MOVE_PASSWORDS_TO_ACCOUNT_SNACKBAR},
-      {"passwordRowMoreActionsButton", IDS_SETTINGS_PASSWORD_ROW_MORE_ACTIONS},
-      {"passwordRowFederatedMoreActionsButton",
-       IDS_SETTINGS_PASSWORD_ROW_FEDERATED_MORE_ACTIONS},
-      {"passwordRowPasswordDetailPageButton",
-       IDS_SETTINGS_PASSWORD_ROW_PASSWORD_DETAIL_PAGE},
-      {"importMenuItem", IDS_SETTINGS_PASSWORDS_IMPORT_MENU_ITEM},
-      {"importPasswordsTitle", IDS_SETTINGS_PASSWORDS_IMPORT_TITLE},
-      {"importPasswordsChooseFile", IDS_SETTINGS_PASSWORDS_IMPORT_CHOOSE_FILE},
-      {"importPasswordsSuccessTip", IDS_SETTINGS_PASSWORDS_IMPORT_SUCCESS_TIP},
-      {"importPasswordsUnknownError",
-       IDS_SETTINGS_PASSWORDS_IMPORT_ERROR_UNKNOWN},
-      {"importPasswordsBadFormatError",
-       IDS_SETTINGS_PASSWORDS_IMPORT_ERROR_BAD_FORMAT},
-      {"importPasswordsGenericDescription",
-       IDS_SETTINGS_PASSWORDS_IMPORT_DESCRIPTION_GENERIC},
-      {"exportMenuItem", IDS_SETTINGS_PASSWORDS_EXPORT_MENU_ITEM},
-      {"exportPasswordsTitle", IDS_SETTINGS_PASSWORDS_EXPORT_TITLE},
-      {"exportPasswordsDescription", IDS_SETTINGS_PASSWORDS_EXPORT_DESCRIPTION},
-      {"exportPasswords", IDS_SETTINGS_PASSWORDS_EXPORT},
-      {"exportingPasswordsTitle", IDS_SETTINGS_PASSWORDS_EXPORTING_TITLE},
-      {"exportPasswordsTryAgain", IDS_SETTINGS_PASSWORDS_EXPORT_TRY_AGAIN},
-      {"exportPasswordsFailTitle",
-       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TITLE},
-      {"exportPasswordsFailTips",
-       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIPS},
-      {"exportPasswordsFailTipsEnoughSpace",
-       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIP_ENOUGH_SPACE},
-      {"exportPasswordsFailTipsAnotherFolder",
-       IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIP_ANOTHER_FOLDER},
-      {"managePasswordsPlaintext",
-       IDS_SETTINGS_PASSWORDS_MANAGE_PASSWORDS_PLAINTEXT},
-      {"savedToThisDeviceOnly",
-       IDS_SETTINGS_PAYMENTS_SAVED_TO_THIS_DEVICE_ONLY},
-      {"trustedVaultBannerLabel", IDS_SETTINGS_TRUSTED_VAULT_BANNER_LABEL},
-      {"trustedVaultBannerSubLabelOfferOptIn",
-       IDS_SETTINGS_TRUSTED_VAULT_BANNER_SUB_LABEL_OFFER_OPT_IN},
-      {"trustedVaultBannerSubLabelOptedIn",
-       IDS_SETTINGS_TRUSTED_VAULT_BANNER_SUB_LABEL_OPTED_IN},
-      {"noSearchResults", IDS_SEARCH_NO_RESULTS},
-      {"searchResultsPlural", IDS_SEARCH_RESULTS_PLURAL},
-      {"searchResultsSingular", IDS_SEARCH_RESULTS_SINGULAR},
-      {"showPasswordLabel", IDS_SETTINGS_PASSWORD_SHOW_PASSWORD_A11Y},
-      {"hidePasswordLabel", IDS_SETTINGS_PASSWORD_HIDE_PASSWORD_A11Y},
-      {"addVirtualCard", IDS_AUTOFILL_ADD_VIRTUAL_CARD},
-      {"removeVirtualCard", IDS_AUTOFILL_REMOVE_VIRTUAL_CARD},
-      {"editServerCard", IDS_AUTOFILL_EDIT_SERVER_CREDIT_CARD},
-      {"virtualCardEnabled", IDS_AUTOFILL_VIRTUAL_CARD_ENABLED_LABEL},
-      {"unenrollVirtualCardDialogTitle",
-       IDS_AUTOFILL_VIRTUAL_CARD_UNENROLL_DIALOG_TITLE},
-      {"unenrollVirtualCardDialogConfirm",
-       IDS_AUTOFILL_VIRTUAL_CARD_UNENROLL_DIALOG_CONFIRM_BUTTON_LABEL},
+    {"autofillPageTitle", IDS_SETTINGS_AUTOFILL},
+    {"passwordsDescription", IDS_SETTINGS_PASSWORD_MANAGER_DESCRIPTION},
+    {"passwordsDevice", IDS_SETTINGS_DEVICE_PASSWORDS},
+    {"checkPasswords", IDS_SETTINGS_CHECK_PASSWORDS},
+    {"checkPasswordsCanceled", IDS_SETTINGS_CHECK_PASSWORDS_CANCELED},
+    {"checkedPasswords", IDS_SETTINGS_CHECKED_PASSWORDS},
+    {"checkPasswordsDescription", IDS_SETTINGS_CHECK_PASSWORDS_DESCRIPTION},
+    {"checkPasswordsErrorOffline", IDS_SETTINGS_CHECK_PASSWORDS_ERROR_OFFLINE},
+    {"checkPasswordsErrorSignedOut",
+     IDS_SETTINGS_CHECK_PASSWORDS_ERROR_SIGNED_OUT},
+    {"checkPasswordsErrorNoPasswords",
+     IDS_SETTINGS_CHECK_PASSWORDS_ERROR_NO_PASSWORDS},
+    {"checkPasswordsErrorQuota",
+     IDS_SETTINGS_CHECK_PASSWORDS_ERROR_QUOTA_LIMIT},
+    {"checkPasswordsErrorGeneric", IDS_SETTINGS_CHECK_PASSWORDS_ERROR_GENERIC},
+    {"noCompromisedCredentials", IDS_SETTINGS_NO_COMPROMISED_CREDENTIALS_LABEL},
+    {"checkPasswordsAgain", IDS_SETTINGS_CHECK_PASSWORDS_AGAIN},
+    {"checkPasswordsAgainAfterError",
+     IDS_SETTINGS_CHECK_PASSWORDS_AGAIN_AFTER_ERROR},
+    {"checkPasswordsProgress", IDS_SETTINGS_CHECK_PASSWORDS_PROGRESS},
+    {"checkPasswordsStop", IDS_SETTINGS_CHECK_PASSWORDS_STOP},
+    {"compromisedPasswords", IDS_SETTINGS_COMPROMISED_PASSWORDS},
+    {"compromisedPasswordsDescription",
+     IDS_SETTINGS_COMPROMISED_PASSWORDS_ADVICE},
+    {"mutedPasswords", IDS_SETTINGS_MUTED_PASSWORDS},
+    {"weakPasswords", IDS_SETTINGS_WEAK_PASSWORDS},
+    {"changePasswordButton", IDS_SETTINGS_CHANGE_PASSWORD_BUTTON},
+    {"changePasswordInApp", IDS_SETTINGS_CHANGE_PASSWORD_IN_APP_LABEL},
+    {"leakedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_REASON_LEAKED},
+    {"phishedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_REASON_PHISHED},
+    {"phishedAndLeakedPassword",
+     IDS_SETTINGS_COMPROMISED_PASSWORD_REASON_PHISHED_AND_LEAKED},
+    {"showCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_SHOW},
+    {"hideCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_HIDE},
+    {"removeCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_REMOVE},
+    {"muteCompromisedPassword", IDS_SETTINGS_COMPROMISED_PASSWORD_MUTE},
+    {"unmuteMutedCompromisedPassword",
+     IDS_SETTINGS_COMPROMISED_PASSWORD_UNMUTE},
+    {"removeCompromisedPasswordConfirmationTitle",
+     IDS_SETTINGS_REMOVE_COMPROMISED_PASSWORD_CONFIRMATION_TITLE},
+    {"removeCompromisedPasswordConfirmationDescription",
+     IDS_SETTINGS_REMOVE_COMPROMISED_PASSWORD_CONFIRMATION_DESCRIPTION},
+    {"alreadyChangedPasswordLink",
+     IDS_SETTINGS_COMPROMISED_ALREADY_CHANGED_PASSWORD},
+    {"editDisclaimerTitle", IDS_SETTINGS_COMPROMISED_EDIT_DISCLAIMER_TITLE},
+    {"editDisclaimerDescription",
+     IDS_SETTINGS_COMPROMISED_EDIT_DISCLAIMER_DESCRIPTION},
+    {"genericCreditCard", IDS_AUTOFILL_CC_GENERIC},
+    {"creditCards", IDS_AUTOFILL_PAYMENT_METHODS},
+    {"noPaymentMethodsFound", IDS_SETTINGS_PAYMENT_METHODS_NONE},
+    {"googlePayments", IDS_SETTINGS_GOOGLE_PAYMENTS},
+    {"googlePaymentsCached", IDS_SETTINGS_GOOGLE_PAYMENTS_CACHED},
+    {"enableProfilesLabel", IDS_AUTOFILL_ENABLE_PROFILES_TOGGLE_LABEL},
+    {"enableProfilesSublabel", IDS_AUTOFILL_ENABLE_PROFILES_TOGGLE_SUBLABEL},
+    {"enableCreditCardsLabel", IDS_AUTOFILL_ENABLE_CREDIT_CARDS_TOGGLE_LABEL},
+    {"enableCreditCardsSublabel",
+     IDS_AUTOFILL_ENABLE_CREDIT_CARDS_TOGGLE_SUBLABEL},
+    {"enableCreditCardFIDOAuthLabel", IDS_ENABLE_CREDIT_CARD_FIDO_AUTH_LABEL},
+    {"enableCreditCardFIDOAuthSublabel",
+     IDS_ENABLE_CREDIT_CARD_FIDO_AUTH_SUBLABEL},
+    {"addresses", IDS_AUTOFILL_ADDRESSES},
+    {"addressesTitle", IDS_AUTOFILL_ADDRESSES_SETTINGS_TITLE},
+    {"addAddressTitle", IDS_SETTINGS_AUTOFILL_ADDRESSES_ADD_TITLE},
+    {"editAddressTitle", IDS_SETTINGS_AUTOFILL_ADDRESSES_EDIT_TITLE},
+    {"addressCountry", IDS_SETTINGS_AUTOFILL_ADDRESSES_COUNTRY},
+    {"addressPhone", IDS_SETTINGS_AUTOFILL_ADDRESSES_PHONE},
+    {"addressEmail", IDS_SETTINGS_AUTOFILL_ADDRESSES_EMAIL},
+    {"honorificLabel", IDS_SETTINGS_AUTOFILL_ADDRESS_HONORIFIC_LABEL},
+    {"moreActionsForAddress", IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_ADDRESS},
+    {"moreActionsForCreditCard",
+     IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_FOR_CREDIT_CARD},
+    {"moreActionsCreditCardDescription",
+     IDS_SETTINGS_AUTOFILL_MORE_ACTIONS_CARD_DESCRIPTION},
+    {"removeAddress", IDS_SETTINGS_ADDRESS_REMOVE},
+    {"removeAddressConfirmationTitle",
+     IDS_SETTINGS_ADDRESS_REMOVE_CONFIRMATION_TITLE},
+    {"removeAddressConfirmationDescription",
+     IDS_SETTINGS_ADDRESS_REMOVE_CONFIRMATION_DESCRIPTION},
+    {"removeCreditCard", IDS_SETTINGS_CREDIT_CARD_REMOVE},
+    {"clearCreditCard", IDS_SETTINGS_CREDIT_CARD_CLEAR},
+    {"creditCardType", IDS_SETTINGS_AUTOFILL_CREDIT_CARD_TYPE_COLUMN_LABEL},
+    {"creditCardExpiration", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_DATE},
+    {"creditCardName", IDS_SETTINGS_NAME_ON_CREDIT_CARD},
+    {"creditCardNickname", IDS_SETTINGS_CREDIT_CARD_NICKNAME},
+    {"creditCardNicknameInvalid", IDS_SETTINGS_CREDIT_CARD_NICKNAME_INVALID},
+    {"creditCardNumber", IDS_SETTINGS_CREDIT_CARD_NUMBER},
+    {"creditCardExpirationMonth", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_MONTH},
+    {"creditCardExpirationYear", IDS_SETTINGS_CREDIT_CARD_EXPIRATION_YEAR},
+    {"creditCardExpired", IDS_SETTINGS_CREDIT_CARD_EXPIRED},
+    {"editCreditCardTitle", IDS_SETTINGS_EDIT_CREDIT_CARD_TITLE},
+    {"addCreditCardTitle", IDS_SETTINGS_ADD_CREDIT_CARD_TITLE},
+    {"migrateCreditCardsLabel", IDS_SETTINGS_MIGRATABLE_CARDS_LABEL},
+    {"migratableCardsInfoSingle", IDS_SETTINGS_SINGLE_MIGRATABLE_CARD_INFO},
+    {"migratableCardsInfoMultiple",
+     IDS_SETTINGS_MULTIPLE_MIGRATABLE_CARDS_INFO},
+    {"remoteCreditCardLinkLabel", IDS_SETTINGS_REMOTE_CREDIT_CARD_LINK_LABEL},
+    {"upiIdLabel", IDS_SETTINGS_UPI_ID_LABEL},
+    {"upiIdExpirationNever", IDS_SETTINGS_UPI_ID_EXPIRATION_NEVER},
+    {"canMakePaymentToggleLabel", IDS_SETTINGS_CAN_MAKE_PAYMENT_TOGGLE_LABEL},
+    {"autofillDetail", IDS_SETTINGS_AUTOFILL_DETAIL},
+    {"passwordsSavePasswordsLabel",
+     IDS_SETTINGS_PASSWORDS_SAVE_PASSWORDS_TOGGLE_LABEL},
+    {"passwordsAutosigninLabel",
+     IDS_SETTINGS_PASSWORDS_AUTOSIGNIN_CHECKBOX_LABEL},
+    {"passwordsAutosigninDescription",
+     IDS_SETTINGS_PASSWORDS_AUTOSIGNIN_CHECKBOX_DESC},
+    {"passwordsLeakDetectionLabel",
+     IDS_SETTINGS_PASSWORDS_LEAK_DETECTION_LABEL},
+    {"passwordsLeakDetectionGeneralDescription",
+     IDS_PASSWORD_MANAGER_LEAK_HELP_MESSAGE},
+    {"passwordsLeakDetectionSignedOutEnabledDescription",
+     IDS_SETTINGS_PASSWORDS_LEAK_DETECTION_SIGNED_OUT_ENABLED_DESC},
+    {"savedPasswordsHeading", IDS_SETTINGS_PASSWORDS_SAVED_HEADING},
+    {"passwordExceptionsHeading", IDS_SETTINGS_PASSWORDS_EXCEPTIONS_HEADING},
+    {"deviceOnlyPasswordsHeading",
+     IDS_SETTINGS_DEVICE_PASSWORDS_ON_DEVICE_ONLY_HEADING},
+    {"deviceAndAccountPasswordsHeading",
+     IDS_SETTINGS_DEVICE_PASSWORDS_ON_DEVICE_AND_ACCOUNT_HEADING},
+    {"deletePasswordException", IDS_SETTINGS_PASSWORDS_DELETE_EXCEPTION},
+    {"removePassword", IDS_SETTINGS_PASSWORD_REMOVE},
+    {"searchPasswords", IDS_SETTINGS_PASSWORD_SEARCH},
+    {"showPassword", IDS_SETTINGS_PASSWORD_SHOW},
+    {"hidePassword", IDS_SETTINGS_PASSWORD_HIDE},
+    {"passwordDetailsTitle", IDS_SETTINGS_PASSWORDS_VIEW_DETAILS_TITLE},
+    {"passwordViewDetails", IDS_SETTINGS_PASSWORD_DETAILS},
+    {"editPasswordTitle", IDS_SETTINGS_PASSWORD_EDIT_TITLE},
+    {"editPassword", IDS_SETTINGS_PASSWORD_EDIT},
+    {"editPasswordFootnote", IDS_SETTINGS_PASSWORD_EDIT_FOOTNOTE},
+    {"addPasswordTitle", IDS_SETTINGS_PASSWORD_ADD_TITLE},
+    {"addPasswordFootnote", IDS_SETTINGS_PASSWORD_ADD_FOOTNOTE},
+    {"addPasswordStoreOptionAccount",
+     IDS_SETTINGS_PASSWORD_ADD_STORE_OPTION_ACCOUNT},
+    {"addPasswordStoreOptionDevice",
+     IDS_PASSWORD_MANAGER_DESTINATION_DROPDOWN_SAVE_TO_DEVICE},
+    {"addPasswordStorePickerA11yDescription",
+     IDS_PASSWORD_MANAGER_DESTINATION_DROPDOWN_ACCESSIBLE_NAME},
+    {"usernameAlreadyUsed", IDS_SETTINGS_PASSWORD_USERNAME_ALREADY_USED},
+    {"missingTLD", IDS_SETTINGS_PASSWORD_MISSING_TLD},
+    {"viewExistingPassword", IDS_SETTINGS_PASSWORD_VIEW_EXISTING_PASSWORD},
+    {"viewExistingPasswordAriaDescription",
+     IDS_SETTINGS_PASSWORD_VIEW_EXISTING_PASSWORD_ARIA_DESCRIPTION},
+    {"copyPassword", IDS_SETTINGS_PASSWORD_COPY},
+    {"sendPassword", IDS_SETTINGS_PASSWORD_SEND},
+    {"copyUsername", IDS_SETTINGS_USERNAME_COPY},
+    {"passwordStoredOnDevice", IDS_SETTINGS_PASSWORD_STORED_ON_DEVICE},
+    {"passwordStoredInAccount", IDS_SETTINGS_PASSWORD_STORED_IN_ACCOUNT},
+    {"passwordStoredInAccountAndOnDevice",
+     IDS_SETTINGS_PASSWORD_STORED_IN_ACCOUNT_AND_ON_DEVICE},
+    {"editPasswordWebsiteLabel", IDS_SETTINGS_PASSWORDS_WEBSITE},
+    {"editPasswordAppLabel", IDS_SETTINGS_COMPROMISED_EDIT_PASSWORD_APP},
+    {"editPasswordUsernameLabel", IDS_SETTINGS_PASSWORDS_USERNAME},
+    {"editPasswordPasswordLabel", IDS_SETTINGS_PASSWORDS_PASSWORD},
+    {"passwordNoteLabel", IDS_SETTINGS_PASSWORDS_NOTE},
+    {"passwordNoNoteAdded", IDS_SETTINGS_PASSWORDS_NO_NOTE_ADDED},
+    {"passwordNoteCharacterCount", IDS_SETTINGS_PASSWORDS_NOTE_CHARACTER_COUNT},
+    {"passwordNoteCharacterCountWarning",
+     IDS_SETTINGS_PASSWORDS_NOTE_CHARACTER_COUNT_WARNING},
+    {"noAddressesFound", IDS_SETTINGS_ADDRESS_NONE},
+    {"noPasswordsFound", IDS_SETTINGS_PASSWORDS_NONE},
+    {"noExceptionsFound", IDS_SETTINGS_PASSWORDS_EXCEPTIONS_NONE},
+    {"optInAccountStorageLabel",
+     IDS_SETTINGS_PASSWORDS_OPT_IN_ACCOUNT_STORAGE_LABEL},
+    {"optOutAccountStorageLabel",
+     IDS_SETTINGS_PASSWORDS_OPT_OUT_ACCOUNT_STORAGE_LABEL},
+    {"undoRemovePassword", IDS_SETTINGS_PASSWORD_UNDO},
+    {"movePasswordToAccount", IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT},
+    {"passwordDeleted", IDS_SETTINGS_PASSWORD_DELETED_PASSWORD},
+    {"passwordDeletedFromDevice",
+     IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_DEVICE},
+    {"passwordDeletedFromAccount",
+     IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_ACCOUNT},
+    {"passwordDeletedFromAccountAndDevice",
+     IDS_SETTINGS_PASSWORD_DELETED_PASSWORD_FROM_ACCOUNT_AND_DEVICE},
+    {"passwordCopiedToClipboard", IDS_SETTINGS_PASSWORD_COPIED_TO_CLIPBOARD},
+    {"passwordUsernameCopiedToClipboard",
+     IDS_SETTINGS_PASSWORD_USERNAME_COPIED_TO_CLIPBOARD},
+    {"passwordMovePasswordsToAccount",
+     IDS_SETTINGS_PASSWORD_MOVE_PASSWORDS_TO_ACCOUNT},
+    {"passwordMovePasswordsToAccountDialogBodyText",
+     IDS_SETTINGS_PASSWORD_MOVE_PASSWORDS_TO_ACCOUNT_DIALOG_BODY_TEXT},
+    {"passwordMovePasswordsToAccountDialogTitle",
+     IDS_SETTINGS_PASSWORD_MOVE_PASSWORDS_TO_ACCOUNT_DIALOG_TITLE},
+    {"passwordMoveToAccountDialogTitle",
+     IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_TITLE},
+    {"passwordMoveToAccountDialogBody",
+     IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_BODY},
+    {"passwordMoveMultiplePasswordsToAccountDialogMoveButtonText",
+     IDS_SETTINGS_PASSWORD_MOVE_MULTIPLE_PASSWORDS_TO_ACCOUNT_DIALOG_MOVE_BUTTON_TEXT},
+    {"passwordMoveMultiplePasswordsToAccountDialogCancelButtonText",
+     IDS_SETTINGS_PASSWORD_MOVE_MULTIPLE_PASSWORDS_TO_ACCOUNT_DIALOG_CANCEL_BUTTON_TEXT},
+    {"passwordMoveToAccountDialogMoveButtonText",
+     IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_MOVE_BUTTON_TEXT},
+    {"passwordMoveToAccountDialogCancelButtonText",
+     IDS_SETTINGS_PASSWORD_MOVE_TO_ACCOUNT_DIALOG_CANCEL_BUTTON_TEXT},
+    {"passwordOpenMoveMultiplePasswordsToAccountDialogButtonText",
+     IDS_SETTINGS_PASSWORD_OPEN_MOVE_MULTIPLE_PASSWORDS_TO_ACCOUNT_DIALOG_BUTTON_TEXT},
+    {"passwordRemoveDialogTitle", IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_TITLE},
+    {"passwordRemoveDialogBody", IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_BODY},
+    {"passwordRemoveDialogRemoveButtonText",
+     IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_REMOVE_BUTTON_TEXT},
+    {"passwordRemoveDialogCancelButtonText",
+     IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_CANCEL_BUTTON_TEXT},
+    {"passwordRemoveDialogFromAccountCheckboxLabel",
+     IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_FROM_ACCOUNT_CHECKBOX_LABEL},
+    {"passwordRemoveDialogFromDeviceCheckboxLabel",
+     IDS_SETTINGS_PASSWORD_REMOVE_DIALOG_FROM_DEVICE_CHECKBOX_LABEL},
+    {"devicePasswordsLinkLabel", IDS_SETTINGS_DEVICE_PASSWORDS_LINK_LABEL},
+    {"devicePasswordsMoved",
+     IDS_SETTINGS_PASSWORD_MOVE_PASSWORDS_TO_ACCOUNT_SNACKBAR},
+    {"passwordRowMoreActionsButton", IDS_SETTINGS_PASSWORD_ROW_MORE_ACTIONS},
+    {"passwordRowFederatedMoreActionsButton",
+     IDS_SETTINGS_PASSWORD_ROW_FEDERATED_MORE_ACTIONS},
+    {"passwordRowPasswordDetailPageButton",
+     IDS_SETTINGS_PASSWORD_ROW_PASSWORD_DETAIL_PAGE},
+    {"importMenuItem", IDS_SETTINGS_PASSWORDS_IMPORT_MENU_ITEM},
+    {"importPasswordsTitle", IDS_SETTINGS_PASSWORDS_IMPORT_TITLE},
+    {"importPasswordsChooseFile", IDS_SETTINGS_PASSWORDS_IMPORT_CHOOSE_FILE},
+    {"importPasswordsSuccessTip", IDS_SETTINGS_PASSWORDS_IMPORT_SUCCESS_TIP},
+    {"importPasswordsUnknownError",
+     IDS_SETTINGS_PASSWORDS_IMPORT_ERROR_UNKNOWN},
+    {"importPasswordsBadFormatError",
+     IDS_SETTINGS_PASSWORDS_IMPORT_ERROR_BAD_FORMAT},
+    {"importPasswordsGenericDescription",
+     IDS_SETTINGS_PASSWORDS_IMPORT_DESCRIPTION_GENERIC},
+    {"exportMenuItem", IDS_SETTINGS_PASSWORDS_EXPORT_MENU_ITEM},
+    {"exportPasswordsTitle", IDS_SETTINGS_PASSWORDS_EXPORT_TITLE},
+    {"exportPasswordsDescription", IDS_SETTINGS_PASSWORDS_EXPORT_DESCRIPTION},
+    {"exportPasswords", IDS_SETTINGS_PASSWORDS_EXPORT},
+    {"exportingPasswordsTitle", IDS_SETTINGS_PASSWORDS_EXPORTING_TITLE},
+    {"exportPasswordsTryAgain", IDS_SETTINGS_PASSWORDS_EXPORT_TRY_AGAIN},
+    {"exportPasswordsFailTitle",
+     IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TITLE},
+    {"exportPasswordsFailTips", IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIPS},
+    {"exportPasswordsFailTipsEnoughSpace",
+     IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIP_ENOUGH_SPACE},
+    {"exportPasswordsFailTipsAnotherFolder",
+     IDS_SETTINGS_PASSWORDS_EXPORTING_FAILURE_TIP_ANOTHER_FOLDER},
+    {"managePasswordsPlaintext",
+     IDS_SETTINGS_PASSWORDS_MANAGE_PASSWORDS_PLAINTEXT},
+    {"savedToThisDeviceOnly", IDS_SETTINGS_PAYMENTS_SAVED_TO_THIS_DEVICE_ONLY},
+    {"trustedVaultBannerLabel", IDS_SETTINGS_TRUSTED_VAULT_BANNER_LABEL},
+    {"trustedVaultBannerSubLabelOfferOptIn",
+     IDS_SETTINGS_TRUSTED_VAULT_BANNER_SUB_LABEL_OFFER_OPT_IN},
+    {"trustedVaultBannerSubLabelOptedIn",
+     IDS_SETTINGS_TRUSTED_VAULT_BANNER_SUB_LABEL_OPTED_IN},
+    {"noSearchResults", IDS_SEARCH_NO_RESULTS},
+    {"searchResultsPlural", IDS_SEARCH_RESULTS_PLURAL},
+    {"searchResultsSingular", IDS_SEARCH_RESULTS_SINGULAR},
+    {"showPasswordLabel", IDS_SETTINGS_PASSWORD_SHOW_PASSWORD_A11Y},
+    {"hidePasswordLabel", IDS_SETTINGS_PASSWORD_HIDE_PASSWORD_A11Y},
+    {"addVirtualCard", IDS_AUTOFILL_ADD_VIRTUAL_CARD},
+    {"removeVirtualCard", IDS_AUTOFILL_REMOVE_VIRTUAL_CARD},
+    {"editServerCard", IDS_AUTOFILL_EDIT_SERVER_CREDIT_CARD},
+    {"virtualCardAvailable", IDS_AUTOFILL_VIRTUAL_CARD_AVAILABLE_LABEL},
+    {"virtualCardEnabled", IDS_AUTOFILL_VIRTUAL_CARD_ENABLED_LABEL},
+    {"virtualCardTurnedOn", IDS_AUTOFILL_VIRTUAL_CARD_TURNED_ON_LABEL},
+    {"unenrollVirtualCardDialogTitle",
+     IDS_AUTOFILL_VIRTUAL_CARD_UNENROLL_DIALOG_TITLE},
+    {"unenrollVirtualCardDialogConfirm",
+     IDS_AUTOFILL_VIRTUAL_CARD_UNENROLL_DIALOG_CONFIRM_BUTTON_LABEL},
 #if BUILDFLAG(IS_WIN)
-      {"managePasskeysLabel", IDS_AUTOFILL_MANAGE_PASSKEYS_LABEL},
-      {"managePasskeysTitle", IDS_AUTOFILL_MANAGE_PASSKEYS_TITLE},
-      {"managePasskeysSubTitle", IDS_AUTOFILL_MANAGE_PASSKEYS_SUB_TITLE},
-      {"managePasskeysSearch", IDS_AUTOFILL_MANAGE_PASSKEYS_SEARCH},
-      {"managePasskeysNoSupport", IDS_AUTOFILL_MANAGE_PASSKEYS_NO_SUPPORT},
-      {"managePasskeysCannotDeleteTitle",
-       IDS_AUTOFILL_MANAGE_PASSKEYS_CANNOT_DELETE_TITLE},
-      {"managePasskeysCannotDeleteBody",
-       IDS_AUTOFILL_MANAGE_PASSKEYS_CANNOT_DELETE_BODY},
+    {"managePasskeysLabel", IDS_AUTOFILL_MANAGE_PASSKEYS_LABEL},
+    {"managePasskeysTitle", IDS_AUTOFILL_MANAGE_PASSKEYS_TITLE},
+    {"managePasskeysSubTitle", IDS_AUTOFILL_MANAGE_PASSKEYS_SUB_TITLE},
+    {"managePasskeysSearch", IDS_AUTOFILL_MANAGE_PASSKEYS_SEARCH},
+    {"managePasskeysNoSupport", IDS_AUTOFILL_MANAGE_PASSKEYS_NO_SUPPORT},
+    {"managePasskeysCannotDeleteTitle",
+     IDS_AUTOFILL_MANAGE_PASSKEYS_CANNOT_DELETE_TITLE},
+    {"managePasskeysCannotDeleteBody",
+     IDS_AUTOFILL_MANAGE_PASSKEYS_CANNOT_DELETE_BODY},
 #endif
   };
 
diff --git a/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_page_handler.cc b/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_page_handler.cc
index 4bb1886..938b65d 100644
--- a/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_page_handler.cc
+++ b/chrome/browser/ui/webui/side_panel/bookmarks/bookmarks_page_handler.cc
@@ -51,7 +51,7 @@
             this,
             browser,
             browser->profile(),
-            BOOKMARK_LAUNCH_LOCATION_SIDE_PANEL_CONTEXT_MENU,
+            BookmarkLaunchLocation::kSidePanelContextMenu,
             bookmark->parent(),
             {bookmark}))) {
     AddItem(IDC_BOOKMARK_BAR_OPEN_ALL);
@@ -142,8 +142,8 @@
   chrome::OpenAllIfAllowed(browser, {bookmark_node}, open_location, false);
   base::RecordAction(base::UserMetricsAction("SidePanel.Bookmarks.Navigation"));
   RecordBookmarkLaunch(
-      parent_folder_depth > 0 ? BOOKMARK_LAUNCH_LOCATION_SIDE_PANEL_SUBFOLDER
-                              : BOOKMARK_LAUNCH_LOCATION_SIDE_PANEL_FOLDER,
+      parent_folder_depth > 0 ? BookmarkLaunchLocation::kSidePanelSubfolder
+                              : BookmarkLaunchLocation::kSidePanelFolder,
       profile_metrics::GetBrowserProfileType(browser->profile()));
 }
 
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.cc b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.cc
index b0df7d3..072ea2278 100644
--- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.cc
+++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.cc
@@ -13,6 +13,10 @@
 #include "chrome/browser/ui/views/side_panel/read_anything/read_anything_controller.h"
 #include "ui/accessibility/ax_tree_update.h"
 
+using read_anything::mojom::Page;
+using read_anything::mojom::PageHandler;
+using read_anything::mojom::ReadAnythingThemePtr;
+
 ReadAnythingPageHandler::ReadAnythingPageHandler(
     mojo::PendingRemote<Page> page,
     mojo::PendingReceiver<PageHandler> receiver)
@@ -64,11 +68,7 @@
   page_->OnAXTreeDistilled(snapshot, content_node_ids);
 }
 
-void ReadAnythingPageHandler::OnFontNameUpdated(
-    const std::string& new_font_name) {
-  page_->OnFontNameChange(std::move(new_font_name));
-}
-
-void ReadAnythingPageHandler::OnFontSizeChanged(const float new_font_size) {
-  page_->OnFontSizeChanged(new_font_size);
+void ReadAnythingPageHandler::OnThemeChanged(
+    ReadAnythingThemePtr new_theme_ptr) {
+  page_->OnThemeChanged(std::move(new_theme_ptr));
 }
diff --git a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.h b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.h
index 0cad6d3c..8888458 100644
--- a/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.h
+++ b/chrome/browser/ui/webui/side_panel/read_anything/read_anything_page_handler.h
@@ -21,9 +21,6 @@
 #include "ui/accessibility/ax_node_id_forward.h"
 #include "ui/accessibility/ax_tree_update_forward.h"
 
-using read_anything::mojom::Page;
-using read_anything::mojom::PageHandler;
-
 ///////////////////////////////////////////////////////////////////////////////
 // ReadAnythingPageHandler
 //
@@ -32,7 +29,7 @@
 //  This class is created and owned by ReadAnythingUI and has the same lifetime
 //  as the Side Panel view.
 //
-class ReadAnythingPageHandler : public PageHandler,
+class ReadAnythingPageHandler : public read_anything::mojom::PageHandler,
                                 public ReadAnythingModel::Observer,
                                 public ReadAnythingCoordinator::Observer {
  public:
@@ -42,18 +39,19 @@
     virtual void OnUIDestroyed() = 0;
   };
 
-  ReadAnythingPageHandler(mojo::PendingRemote<Page> page,
-                          mojo::PendingReceiver<PageHandler> receiver);
+  ReadAnythingPageHandler(
+      mojo::PendingRemote<read_anything::mojom::Page> page,
+      mojo::PendingReceiver<read_anything::mojom::PageHandler> receiver);
   ReadAnythingPageHandler(const ReadAnythingPageHandler&) = delete;
   ReadAnythingPageHandler& operator=(const ReadAnythingPageHandler&) = delete;
   ~ReadAnythingPageHandler() override;
 
   // ReadAnythingModel::Observer:
-  void OnFontNameUpdated(const std::string& new_font_name) override;
   void OnAXTreeDistilled(
       const ui::AXTreeUpdate& snapshot,
       const std::vector<ui::AXNodeID>& content_node_ids) override;
-  void OnFontSizeChanged(const float new_font_size) override;
+  void OnThemeChanged(
+      read_anything::mojom::ReadAnythingThemePtr new_theme) override;
 
   // ReadAnythingCoordinator::Observer:
   void OnCoordinatorDestroyed() override;
@@ -65,8 +63,8 @@
 
   raw_ptr<Browser> browser_;
 
-  mojo::Receiver<PageHandler> receiver_;
-  mojo::Remote<Page> page_;
+  mojo::Receiver<read_anything::mojom::PageHandler> receiver_;
+  mojo::Remote<read_anything::mojom::Page> page_;
   base::WeakPtrFactory<ReadAnythingPageHandler> weak_pointer_factory_{this};
 };
 
diff --git a/chrome/browser/ui/webui/side_panel/reading_list/reading_list_page_handler.cc b/chrome/browser/ui/webui/side_panel/reading_list/reading_list_page_handler.cc
index 528bd03e..d143e28 100644
--- a/chrome/browser/ui/webui/side_panel/reading_list/reading_list_page_handler.cc
+++ b/chrome/browser/ui/webui/side_panel/reading_list/reading_list_page_handler.cc
@@ -191,7 +191,7 @@
   base::RecordAction(
       base::UserMetricsAction("SidePanel.ReadingList.Navigation"));
   RecordBookmarkLaunch(
-      BOOKMARK_LAUNCH_LOCATION_SIDE_PANEL_READING_LIST,
+      BookmarkLaunchLocation::kSidePanelPendingList,
       profile_metrics::GetBrowserProfileType(Profile::FromWebUI(web_ui_)));
 }
 
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
index 6b75bc9..e6f22b25 100644
--- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
+++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.cc
@@ -72,8 +72,10 @@
 #include "components/services/app_service/public/cpp/app_types.h"
 #include "components/services/app_service/public/cpp/file_handler.h"
 #include "components/services/app_service/public/cpp/intent_filter.h"
+#include "components/services/app_service/public/cpp/intent_filter_util.h"
 #include "components/services/app_service/public/cpp/intent_util.h"
 #include "components/services/app_service/public/cpp/run_on_os_login_types.h"
+#include "components/services/app_service/public/cpp/share_target.h"
 #include "components/services/app_service/public/cpp/shortcut.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "content/public/browser/clear_site_data_utils.h"
@@ -102,6 +104,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/constants/ash_features.h"
+#include "ash/webui/projector_app/public/cpp/projector_app_constants.h"  // nogncheck
 #include "chrome/browser/ash/file_manager/app_id.h"
 #include "chrome/browser/ash/guest_os/guest_os_terminal.h"
 #include "chrome/browser/ash/login/demo_mode/demo_session.h"
@@ -139,6 +142,9 @@
     ContentSettingsType::NOTIFICATIONS,
 };
 
+// Mime Type for plain text.
+const char kTextPlain[] = "text/plain";
+
 bool GetContentSettingsType(apps::PermissionType permission_type,
                             ContentSettingsType& content_setting_type) {
   switch (permission_type) {
@@ -255,6 +261,86 @@
   return web_app.lock_screen_start_url().is_valid();
 }
 
+apps::mojom::IntentFilterPtr CreateMimeTypeShareFilter(
+    const std::vector<std::string>& mime_types) {
+  DCHECK(!mime_types.empty());
+  auto intent_filter = apps::mojom::IntentFilter::New();
+
+  std::vector<apps::mojom::ConditionValuePtr> action_condition_values;
+  action_condition_values.push_back(apps_util::MakeConditionValue(
+      apps_util::kIntentActionSend, apps::mojom::PatternMatchType::kLiteral));
+  auto action_condition = apps_util::MakeCondition(
+      apps::mojom::ConditionType::kAction, std::move(action_condition_values));
+  intent_filter->conditions.push_back(std::move(action_condition));
+
+  std::vector<apps::mojom::ConditionValuePtr> condition_values;
+  for (auto& mime_type : mime_types) {
+    condition_values.push_back(apps_util::MakeConditionValue(
+        mime_type, apps::mojom::PatternMatchType::kMimeType));
+  }
+  auto mime_condition = apps_util::MakeCondition(
+      apps::mojom::ConditionType::kMimeType, std::move(condition_values));
+  intent_filter->conditions.push_back(std::move(mime_condition));
+
+  return intent_filter;
+}
+
+apps::IntentFilters CreateShareIntentFiltersFromShareTarget(
+    const apps::ShareTarget& share_target) {
+  apps::IntentFilters filters;
+
+  if (!share_target.params.text.empty()) {
+    // The share target accepts navigator.share() calls with text.
+    filters.push_back(apps::ConvertMojomIntentFilterToIntentFilter(
+        CreateMimeTypeShareFilter({kTextPlain})));
+  }
+
+  std::vector<std::string> content_types;
+  for (const auto& files_entry : share_target.params.files) {
+    for (const auto& file_type : files_entry.accept) {
+      // Skip any file_type that is not a MIME type.
+      if (file_type.empty() || file_type[0] == '.' ||
+          std::count(file_type.begin(), file_type.end(), '/') != 1) {
+        continue;
+      }
+
+      content_types.push_back(file_type);
+    }
+  }
+
+  if (!content_types.empty()) {
+    const std::vector<std::string> intent_actions(
+        {apps_util::kIntentActionSend, apps_util::kIntentActionSendMultiple});
+    filters.push_back(
+        apps_util::CreateFileFilter(intent_actions, content_types, {}));
+  }
+
+  return filters;
+}
+
+apps::IntentFilters CreateIntentFiltersFromFileHandlers(
+    const apps::FileHandlers& file_handlers) {
+  apps::IntentFilters filters;
+  for (const apps::FileHandler& handler : file_handlers) {
+    std::vector<std::string> mime_types;
+    std::vector<std::string> file_extensions;
+    std::string action_url = handler.action.spec();
+    // TODO(petermarshall): Use GetFileExtensionsFromFileHandlers /
+    // GetMimeTypesFromFileHandlers?
+    for (const apps::FileHandler::AcceptEntry& accept_entry : handler.accept) {
+      mime_types.push_back(accept_entry.mime_type);
+      for (const std::string& extension : accept_entry.file_extensions) {
+        file_extensions.push_back(extension);
+      }
+    }
+    filters.push_back(
+        apps_util::CreateFileFilter({apps_util::kIntentActionView}, mime_types,
+                                    file_extensions, action_url));
+  }
+
+  return filters;
+}
+
 }  // namespace
 
 void UninstallImpl(WebAppProvider* provider,
@@ -523,6 +609,41 @@
   return permissions;
 }
 
+// static
+apps::IntentFilters WebAppPublisherHelper::CreateIntentFiltersForWebApp(
+    const web_app::AppId& app_id,
+    const GURL& app_scope,
+    const apps::ShareTarget* app_share_target,
+    const apps::FileHandlers* enabled_file_handlers) {
+  apps::IntentFilters filters;
+
+  if (!app_scope.is_empty()) {
+    filters.push_back(apps::ConvertMojomIntentFilterToIntentFilter(
+        apps_util::CreateIntentFilterForUrlScope(app_scope)));
+  }
+
+  if (app_share_target) {
+    base::Extend(filters,
+                 CreateShareIntentFiltersFromShareTarget(*app_share_target));
+  }
+
+  if (enabled_file_handlers) {
+    base::Extend(filters,
+                 CreateIntentFiltersFromFileHandlers(*enabled_file_handlers));
+  }
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  if (ash::features::IsProjectorEnabled() &&
+      app_id == ash::kChromeUITrustedProjectorSwaAppId) {
+    filters.push_back(apps::ConvertMojomIntentFilterToIntentFilter(
+        apps_util::CreateIntentFilterForUrlScope(
+            GURL(ash::kChromeUIUntrustedProjectorPwaUrl))));
+  }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+  return filters;
+}
+
 apps::AppPtr WebAppPublisherHelper::CreateWebApp(const WebApp* web_app) {
   DCHECK(!IsShuttingDown());
 
@@ -586,7 +707,7 @@
   // Add the intent filters for PWAs.
   base::Extend(
       app->intent_filters,
-      apps_util::CreateIntentFiltersForWebApp(
+      CreateIntentFiltersForWebApp(
           web_app->app_id(), registrar().GetAppScope(web_app->app_id()),
           registrar().GetAppShareTarget(web_app->app_id()),
           provider_->os_integration_manager().GetEnabledFileHandlers(
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper.h b/chrome/browser/web_applications/app_service/web_app_publisher_helper.h
index 61164a5..0f9308b 100644
--- a/chrome/browser/web_applications/app_service/web_app_publisher_helper.h
+++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper.h
@@ -290,6 +290,15 @@
 
   bool IsShuttingDown() const;
 
+  // Create intent filters for `app_id`. The `app_scope` is needed because
+  // currently the correct app scope is not provided through WebApp API for
+  // shortcuts.
+  static apps::IntentFilters CreateIntentFiltersForWebApp(
+      const web_app::AppId& app_id,
+      const GURL& app_scope,
+      const apps::ShareTarget* app_share_target,
+      const apps::FileHandlers* enabled_file_handlers);
+
  private:
 #if BUILDFLAG(IS_CHROMEOS)
   class BadgeManagerDelegate : public badging::BadgeManagerDelegate {
diff --git a/chrome/browser/apps/app_service/intent_util_browsertest.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper_browsertest.cc
similarity index 75%
rename from chrome/browser/apps/app_service/intent_util_browsertest.cc
rename to chrome/browser/web_applications/app_service/web_app_publisher_helper_browsertest.cc
index a683e4b..fac08d28 100644
--- a/chrome/browser/apps/app_service/intent_util_browsertest.cc
+++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper_browsertest.cc
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/apps/app_service/intent_util.h"
+#include "chrome/browser/web_applications/app_service/web_app_publisher_helper.h"
 
+#include <memory>
 #include <string>
 
 #include "chrome/browser/ui/browser.h"
@@ -18,12 +19,12 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "url/gurl.h"
 
-using apps::mojom::Condition;
-using apps::mojom::ConditionType;
-using apps::mojom::IntentFilterPtr;
-using apps::mojom::PatternMatchType;
+using apps::Condition;
+using apps::ConditionType;
+using apps::IntentFilterPtr;
+using apps::PatternMatchType;
 
-namespace apps_util {
+namespace web_app {
 
 namespace {
 
@@ -51,14 +52,13 @@
             PatternMatchType::kMimeType);
   EXPECT_EQ(condition.condition_values[0]->value, "text/plain");
 
-  EXPECT_TRUE(apps_util::IntentMatchesFilter(
-      apps_util::CreateShareIntentFromText("text", "title"), intent_filter));
+  EXPECT_TRUE(
+      apps_util::MakeShareIntent("text", "title")->MatchFilter(intent_filter));
 
   std::vector<GURL> filesystem_urls(1U);
   std::vector<std::string> mime_types(1U, "audio/mp3");
-  EXPECT_FALSE(apps_util::IntentMatchesFilter(
-      apps_util::CreateShareIntentFromFiles(filesystem_urls, mime_types),
-      intent_filter));
+  EXPECT_FALSE(apps_util::MakeShareIntent(filesystem_urls, mime_types)
+                   ->MatchFilter(intent_filter));
 }
 
 void CheckShareFileFilter(const IntentFilterPtr& intent_filter,
@@ -100,44 +100,41 @@
     {
       std::vector<GURL> filesystem_urls(1U);
       std::vector<std::string> mime_types(1U, accepted_type);
-      EXPECT_TRUE(apps_util::IntentMatchesFilter(
-          apps_util::CreateShareIntentFromFiles(filesystem_urls, mime_types),
-          intent_filter));
+      EXPECT_TRUE(apps_util::MakeShareIntent(filesystem_urls, mime_types)
+                      ->MatchFilter(intent_filter));
     }
 
     {
       std::vector<GURL> filesystem_urls(3U);
       std::vector<std::string> mime_types(3U, accepted_type);
-      EXPECT_TRUE(apps_util::IntentMatchesFilter(
-          apps_util::CreateShareIntentFromFiles(filesystem_urls, mime_types),
-          intent_filter));
+      EXPECT_TRUE(apps_util::MakeShareIntent(filesystem_urls, mime_types)
+                      ->MatchFilter(intent_filter));
     }
   }
 
   for (const std::string& rejected_type : rejected_types) {
     std::vector<GURL> filesystem_urls(1U);
     std::vector<std::string> mime_types(1U, rejected_type);
-    EXPECT_FALSE(apps_util::IntentMatchesFilter(
-        apps_util::CreateShareIntentFromFiles(filesystem_urls, mime_types),
-        intent_filter));
+    EXPECT_FALSE(apps_util::MakeShareIntent(filesystem_urls, mime_types)
+                     ->MatchFilter(intent_filter));
   }
 }
 
 }  // namespace
 
-using WebAppsUtilsBrowserTest = InProcessBrowserTest;
+using WebAppPublisherHelperBrowserTest = InProcessBrowserTest;
 
-IN_PROC_BROWSER_TEST_F(WebAppsUtilsBrowserTest, CreateIntentFilters) {
+IN_PROC_BROWSER_TEST_F(WebAppPublisherHelperBrowserTest, CreateIntentFilters) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL app_url(
       embedded_test_server()->GetURL("/web_share_target/charts.html"));
 
-  std::vector<IntentFilterPtr> filters;
+  apps::IntentFilters filters;
   {
     auto& provider = *web_app::WebAppProvider::GetForTest(browser()->profile());
     const web_app::AppId app_id =
         web_app::InstallWebAppFromManifest(browser(), app_url);
-    filters = CreateWebAppIntentFilters(
+    filters = WebAppPublisherHelper::CreateIntentFiltersForWebApp(
         app_id, provider.registrar().GetAppScope(app_id),
         provider.registrar().GetAppShareTarget(app_id),
         provider.os_integration_manager().GetEnabledFileHandlers(app_id));
@@ -145,9 +142,9 @@
 
   ASSERT_EQ(filters.size(), 3U);
 
-  EXPECT_TRUE(apps_util::IntentMatchesFilter(
-      apps_util::CreateIntentFromUrl(app_url.GetWithoutFilename()),
-      filters[0]));
+  EXPECT_TRUE(std::make_unique<apps::Intent>(apps_util::kIntentActionView,
+                                             app_url.GetWithoutFilename())
+                  ->MatchFilter(filters[0]));
 
   CheckShareTextFilter(filters[1]);
 
@@ -160,17 +157,17 @@
                        rejected_types);
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppsUtilsBrowserTest, PartialWild) {
+IN_PROC_BROWSER_TEST_F(WebAppPublisherHelperBrowserTest, PartialWild) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL app_url(
       embedded_test_server()->GetURL("/web_share_target/partial-wild.html"));
 
-  std::vector<IntentFilterPtr> filters;
+  apps::IntentFilters filters;
   {
     auto& provider = *web_app::WebAppProvider::GetForTest(browser()->profile());
     const web_app::AppId app_id =
         web_app::InstallWebAppFromManifest(browser(), app_url);
-    filters = CreateWebAppIntentFilters(
+    filters = WebAppPublisherHelper::CreateIntentFiltersForWebApp(
         app_id, provider.registrar().GetAppScope(app_id),
         provider.registrar().GetAppShareTarget(app_id),
         provider.os_integration_manager().GetEnabledFileHandlers(app_id));
@@ -178,9 +175,9 @@
 
   ASSERT_EQ(filters.size(), 2U);
 
-  EXPECT_TRUE(apps_util::IntentMatchesFilter(
-      apps_util::CreateIntentFromUrl(app_url.GetWithoutFilename()),
-      filters[0]));
+  EXPECT_TRUE(std::make_unique<apps::Intent>(apps_util::kIntentActionView,
+                                             app_url.GetWithoutFilename())
+                  ->MatchFilter(filters[0]));
 
   const std::vector<std::string> filter_types({"image/*"});
   const std::vector<std::string> accepted_types({"image/png", "image/svg+xml"});
@@ -190,17 +187,18 @@
                        rejected_types);
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppsUtilsBrowserTest, ShareTargetWithoutFiles) {
+IN_PROC_BROWSER_TEST_F(WebAppPublisherHelperBrowserTest,
+                       ShareTargetWithoutFiles) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL app_url(
       embedded_test_server()->GetURL("/web_share_target/poster.html"));
 
-  std::vector<IntentFilterPtr> filters;
+  apps::IntentFilters filters;
   {
     auto& provider = *web_app::WebAppProvider::GetForTest(browser()->profile());
     const web_app::AppId app_id =
         web_app::InstallWebAppFromManifest(browser(), app_url);
-    filters = CreateWebAppIntentFilters(
+    filters = WebAppPublisherHelper::CreateIntentFiltersForWebApp(
         app_id, provider.registrar().GetAppScope(app_id),
         provider.registrar().GetAppShareTarget(app_id),
         provider.os_integration_manager().GetEnabledFileHandlers(app_id));
@@ -208,11 +206,11 @@
 
   ASSERT_EQ(filters.size(), 2U);
 
-  EXPECT_TRUE(apps_util::IntentMatchesFilter(
-      apps_util::CreateIntentFromUrl(app_url.GetWithoutFilename()),
-      filters[0]));
+  EXPECT_TRUE(std::make_unique<apps::Intent>(apps_util::kIntentActionView,
+                                             app_url.GetWithoutFilename())
+                  ->MatchFilter(filters[0]));
 
   CheckShareTextFilter(filters[1]);
 }
 
-}  // namespace apps_util
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/app_service/web_app_publisher_helper_unittest.cc b/chrome/browser/web_applications/app_service/web_app_publisher_helper_unittest.cc
index 4ac3519..00ec3d7 100644
--- a/chrome/browser/web_applications/app_service/web_app_publisher_helper_unittest.cc
+++ b/chrome/browser/web_applications/app_service/web_app_publisher_helper_unittest.cc
@@ -213,6 +213,106 @@
   EXPECT_EQ(ToString(app), ToString(apps::ConvertMojomAppToApp(mojom_app)));
 }
 
+TEST_F(WebAppPublisherHelperTest,
+       CreateIntentFiltersForWebApp_WebApp_HasUrlFilter) {
+  auto web_app = web_app::test::CreateWebApp();
+  DCHECK(web_app->start_url().is_valid());
+  GURL scope = web_app->start_url().GetWithoutFilename();
+  web_app->SetScope(scope);
+
+  apps::IntentFilters filters =
+      WebAppPublisherHelper::CreateIntentFiltersForWebApp(
+          web_app->app_id(), scope,
+          /*app_share_target*/ nullptr, /*enabled_file_handlers*/ nullptr);
+
+  ASSERT_EQ(filters.size(), 1u);
+  apps::IntentFilterPtr& filter = filters[0];
+  EXPECT_FALSE(filter->activity_name.has_value());
+  EXPECT_FALSE(filter->activity_label.has_value());
+  ASSERT_EQ(filter->conditions.size(), 4U);
+
+  {
+    const apps::Condition& condition = *filter->conditions[0];
+    EXPECT_EQ(condition.condition_type, apps::ConditionType::kAction);
+    ASSERT_EQ(condition.condition_values.size(), 1U);
+    EXPECT_EQ(condition.condition_values[0]->match_type,
+              apps::PatternMatchType::kLiteral);
+    EXPECT_EQ(condition.condition_values[0]->value,
+              apps_util::kIntentActionView);
+  }
+
+  {
+    const apps::Condition& condition = *filter->conditions[1];
+    EXPECT_EQ(condition.condition_type, apps::ConditionType::kScheme);
+    ASSERT_EQ(condition.condition_values.size(), 1U);
+    EXPECT_EQ(condition.condition_values[0]->match_type,
+              apps::PatternMatchType::kLiteral);
+    EXPECT_EQ(condition.condition_values[0]->value, scope.scheme());
+  }
+
+  {
+    const apps::Condition& condition = *filter->conditions[2];
+    EXPECT_EQ(condition.condition_type, apps::ConditionType::kHost);
+    ASSERT_EQ(condition.condition_values.size(), 1U);
+    EXPECT_EQ(condition.condition_values[0]->match_type,
+              apps::PatternMatchType::kLiteral);
+    EXPECT_EQ(condition.condition_values[0]->value, scope.host());
+  }
+
+  {
+    const apps::Condition& condition = *filter->conditions[3];
+    EXPECT_EQ(condition.condition_type, apps::ConditionType::kPath);
+    ASSERT_EQ(condition.condition_values.size(), 1U);
+    EXPECT_EQ(condition.condition_values[0]->match_type,
+              apps::PatternMatchType::kPrefix);
+    EXPECT_EQ(condition.condition_values[0]->value, scope.path());
+  }
+}
+
+TEST_F(WebAppPublisherHelperTest, CreateIntentFiltersForWebApp_FileHandlers) {
+  auto web_app = web_app::test::CreateWebApp();
+  DCHECK(web_app->start_url().is_valid());
+  GURL scope = web_app->start_url().GetWithoutFilename();
+  web_app->SetScope(scope);
+
+  apps::FileHandler::AcceptEntry accept_entry;
+  accept_entry.mime_type = "text/plain";
+  accept_entry.file_extensions.insert(".txt");
+  apps::FileHandler file_handler;
+  file_handler.action = GURL("https://example.com/path/handler.html");
+  file_handler.accept.push_back(std::move(accept_entry));
+  apps::FileHandlers file_handlers;
+  file_handlers.push_back(std::move(file_handler));
+  web_app->SetFileHandlers(file_handlers);
+
+  apps::IntentFilters filters =
+      WebAppPublisherHelper::CreateIntentFiltersForWebApp(
+          web_app->app_id(), scope,
+          /*app_share_target*/ nullptr, &file_handlers);
+
+  ASSERT_EQ(filters.size(), 2u);
+  // 1st filter is URL filter.
+
+  // File filter - View action
+  const apps::IntentFilterPtr& file_filter = filters[1];
+  ASSERT_EQ(file_filter->conditions.size(), 2u);
+  const apps::Condition& view_cond = *file_filter->conditions[0];
+  EXPECT_EQ(view_cond.condition_type, apps::ConditionType::kAction);
+  ASSERT_EQ(view_cond.condition_values.size(), 1u);
+  EXPECT_EQ(view_cond.condition_values[0]->value, apps_util::kIntentActionView);
+
+  // File filter - mime & file extension match
+  const apps::Condition& file_cond = *file_filter->conditions[1];
+  EXPECT_EQ(file_cond.condition_type, apps::ConditionType::kFile);
+  ASSERT_EQ(file_cond.condition_values.size(), 2u);
+  EXPECT_EQ(file_cond.condition_values[0]->match_type,
+            apps::PatternMatchType::kMimeType);
+  EXPECT_EQ(file_cond.condition_values[0]->value, "text/plain");
+  EXPECT_EQ(file_cond.condition_values[1]->match_type,
+            apps::PatternMatchType::kFileExtension);
+  EXPECT_EQ(file_cond.condition_values[1]->value, ".txt");
+}
+
 class WebAppPublisherHelperTest_WebLockScreenApi
     : public WebAppPublisherHelperTest {
   base::test::ScopedFeatureList features{features::kWebLockScreenApi};
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc
index 9f70ef5..eeb5990 100644
--- a/chrome/browser/web_applications/web_app_database.cc
+++ b/chrome/browser/web_applications/web_app_database.cc
@@ -1291,6 +1291,8 @@
     if (local_data.tab_strip().has_home_tab_visibility()) {
       tab_strip.home_tab = ProtoToTabStripVisibility(
           local_data.tab_strip().home_tab_visibility());
+    } else {
+      tab_strip.home_tab = blink::Manifest::HomeTabParams();
     }
 
     if (local_data.tab_strip().has_new_tab_button_visibility()) {
diff --git a/chrome/browser/web_applications/web_app_install_utils.cc b/chrome/browser/web_applications/web_app_install_utils.cc
index a7fc98a..402dfa1 100644
--- a/chrome/browser/web_applications/web_app_install_utils.cc
+++ b/chrome/browser/web_applications/web_app_install_utils.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <array>
+#include <iterator>
 #include <map>
 #include <ostream>
 #include <set>
@@ -17,6 +18,8 @@
 #include "base/check.h"
 #include "base/check_op.h"
 #include "base/containers/contains.h"
+#include "base/containers/cxx20_erase_map.h"
+#include "base/containers/extend.h"
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
 #include "base/containers/flat_tree.h"
@@ -26,6 +29,7 @@
 #include "base/metrics/histogram_base.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/notreached.h"
+#include "base/ranges/algorithm.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -42,6 +46,7 @@
 #include "chrome/browser/web_applications/web_app_sources.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
 #include "chrome/common/chrome_features.h"
+#include "components/services/app_service/public/cpp/file_handler.h"
 #include "components/services/app_service/public/cpp/icon_info.h"
 #include "components/services/app_service/public/cpp/protocol_handler_info.h"
 #include "components/services/app_service/public/cpp/share_target.h"
@@ -595,38 +600,66 @@
   web_app_info->tab_strip = manifest.tab_strip;
 }
 
-base::flat_set<GURL> GetValidIconUrlsToDownload(
-    const WebAppInstallInfo& web_app_info) {
-  base::flat_set<GURL> web_app_info_icon_urls;
-  // App icons.
+namespace {
+
+std::vector<GURL> GetAppIconUrls(const WebAppInstallInfo& web_app_info) {
+  std::vector<GURL> urls;
+
   for (const apps::IconInfo& info : web_app_info.manifest_icons) {
-    if (!info.url.is_valid())
-      continue;
-    web_app_info_icon_urls.insert(info.url);
+    urls.push_back(info.url);
   }
 
-  // Shortcut icons.
-  for (const auto& shortcut : web_app_info.shortcuts_menu_item_infos) {
+  return urls;
+}
+
+std::vector<GURL> GetShortcutIcons(const WebAppInstallInfo& web_app_info) {
+  std::vector<GURL> urls;
+  for (const WebAppShortcutsMenuItemInfo& shortcut :
+       web_app_info.shortcuts_menu_item_infos) {
     for (IconPurpose purpose : kIconPurposes) {
-      for (const auto& icon :
+      for (const WebAppShortcutsMenuItemInfo::Icon& icon :
            shortcut.GetShortcutIconInfosForPurpose(purpose)) {
-        if (!icon.url.is_valid())
-          continue;
-        web_app_info_icon_urls.insert(icon.url);
+        urls.push_back(icon.url);
       }
     }
   }
 
-  // File handling icons.
-  for (const auto& file_handler : web_app_info.file_handlers) {
-    for (const auto& icon : file_handler.downloaded_icons) {
-      if (!icon.url.is_valid())
-        continue;
-      web_app_info_icon_urls.insert(icon.url);
+  return urls;
+}
+
+std::vector<GURL> GetFileHandlingIcons(const WebAppInstallInfo& web_app_info) {
+  std::vector<GURL> urls;
+
+  for (const apps::FileHandler& file_handler : web_app_info.file_handlers) {
+    for (const apps::IconInfo& icon : file_handler.downloaded_icons) {
+      urls.push_back(icon.url);
     }
   }
 
-  return web_app_info_icon_urls;
+  return urls;
+}
+
+base::flat_set<GURL> RemoveDuplicates(const std::vector<GURL>& from_urls) {
+  return base::flat_set<GURL>{from_urls};
+}
+
+void RemoveInvalidUrls(std::vector<GURL>& urls) {
+  base::EraseIf(urls, [](const GURL& url) { return !url.is_valid(); });
+}
+
+}  // namespace
+
+base::flat_set<GURL> GetValidIconUrlsToDownload(
+    const WebAppInstallInfo& web_app_info) {
+  std::vector<GURL> icon_urls;
+
+  base::Extend(icon_urls, GetAppIconUrls(web_app_info));
+  base::Extend(icon_urls, GetShortcutIcons(web_app_info));
+  base::Extend(icon_urls, GetFileHandlingIcons(web_app_info));
+
+  RemoveInvalidUrls(std::ref(icon_urls));
+
+  return RemoveDuplicates(icon_urls);
 }
 
 void PopulateOtherIcons(WebAppInstallInfo* web_app_info,
diff --git a/chrome/browser/web_applications/web_app_registrar.cc b/chrome/browser/web_applications/web_app_registrar.cc
index 41c8609..f213ae75 100644
--- a/chrome/browser/web_applications/web_app_registrar.cc
+++ b/chrome/browser/web_applications/web_app_registrar.cc
@@ -493,6 +493,23 @@
   return GetAppStartUrl(app_id);
 }
 
+absl::optional<GURL> WebAppRegistrar::GetAppPinnedHomeTabUrl(
+    const AppId& app_id) const {
+  if (IsTabbedWindowModeEnabled(app_id)) {
+    const WebApp* web_app = GetAppById(app_id);
+    if (!web_app)
+      return absl::nullopt;
+
+    if (web_app->tab_strip() &&
+        absl::holds_alternative<blink::Manifest::HomeTabParams>(
+            web_app->tab_strip().value().home_tab)) {
+      return GetAppStartUrl(app_id);
+    }
+  }
+  // Apps with home_tab set to 'auto' will not have a home tab.
+  return absl::nullopt;
+}
+
 #if BUILDFLAG(IS_MAC)
 bool WebAppRegistrar::AlwaysShowToolbarInFullscreen(const AppId& app_id) const {
   auto* web_app = GetAppById(app_id);
diff --git a/chrome/browser/web_applications/web_app_registrar.h b/chrome/browser/web_applications/web_app_registrar.h
index 07b84eb..0b49f5d9 100644
--- a/chrome/browser/web_applications/web_app_registrar.h
+++ b/chrome/browser/web_applications/web_app_registrar.h
@@ -323,6 +323,10 @@
 
   GURL GetAppNewTabUrl(const AppId& app_id) const;
 
+  // Returns the URL of the pinned home tab for tabbed apps which have this
+  // enabled, otherwise returns nullopt.
+  absl::optional<GURL> GetAppPinnedHomeTabUrl(const AppId& app_id) const;
+
 #if BUILDFLAG(IS_MAC)
   bool AlwaysShowToolbarInFullscreen(const AppId& app_id) const;
   void NotifyAlwaysShowToolbarInFullscreenChanged(const AppId& app_id,
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 18ee8c52..458b9222 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1659981512-9489d4121107498551f593fcb771020a7870ec63.profdata
+chrome-linux-main-1660003083-4890d7890d9816daa12070107ce5093a02393104.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index d4a9751..fddaec3 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1659981512-5904991f53ae3ae1a9cf6ffbe5bce549133e8853.profdata
+chrome-mac-arm-main-1660003083-e38b612656209cb1b6388c2043e369a6693e1dde.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 627e20c..321abd5 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1659981512-e8c4198bbd0969d549c78f6834eed72288d785fa.profdata
+chrome-mac-main-1660003083-a98a26bf6c2a13b90acb9230aa890ede9a665407.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 28da40a5..f468fd8 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1659981512-ec3635f9ca3c0ab09281bffcb8f707977f1329cc.profdata
+chrome-win32-main-1660013219-5b00dc42df737cae641ae0a0593d1dfe45877740.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 8b73eb04..b081a3bb 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1659992396-076313df7a80214795503f85c11c9f6d11aee2bb.profdata
+chrome-win64-main-1660013219-c5e63a8a61d0a23d4c3fa3f16e92f77d35bdb889.profdata
diff --git a/chrome/common/accessibility/read_anything.mojom b/chrome/common/accessibility/read_anything.mojom
index ec4a65d1..76b7fb0 100644
--- a/chrome/common/accessibility/read_anything.mojom
+++ b/chrome/common/accessibility/read_anything.mojom
@@ -7,6 +7,16 @@
 
 import "ui/accessibility/mojom/ax_tree_update.mojom";
 
+// Used to represent the current user choices for the Read Anything visual
+// presentation/theme. This includes font name, size, spacing, and colors.
+struct ReadAnythingTheme {
+  // The name of the user's font choice.
+  string font_name;
+
+  // The px value of the user's font size.
+  float font_size;
+};
+
 // Used by the WebUI page to bootstrap bidirectional communication.
 interface PageHandlerFactory {
   // The WebUI calls this method when the page is first initialized.
@@ -29,9 +39,6 @@
   OnAXTreeDistilled(ax.mojom.AXTreeUpdate snapshot,
                     array<int32> content_node_ids);
 
-  // Send an updated font name to front end.
-  OnFontNameChange(string new_font_name);
-
-  // Send an updated font size to front end.
-  OnFontSizeChanged(float new_font_size);
+  // Send an updated theme to front end.
+  OnThemeChanged(ReadAnythingTheme new_theme);
 };
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.cc b/chrome/renderer/accessibility/read_anything_app_controller.cc
index eb47758e..dd0ed1c 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller.cc
+++ b/chrome/renderer/accessibility/read_anything_app_controller.cc
@@ -27,6 +27,9 @@
 #include "v8/include/v8-context.h"
 #include "v8/include/v8-microtask-queue.h"
 
+using read_anything::mojom::ReadAnythingTheme;
+using read_anything::mojom::ReadAnythingThemePtr;
+
 namespace {
 
 // The following methods convert v8::Value types to an AXTreeUpdate. This is not
@@ -197,20 +200,13 @@
   render_frame_->ExecuteJavaScript(base::ASCIIToUTF16(script));
 }
 
-void ReadAnythingAppController::OnFontNameChange(
-    const std::string& new_font_name) {
-  font_name_ = new_font_name;
+void ReadAnythingAppController::OnThemeChanged(ReadAnythingThemePtr new_theme) {
+  font_name_ = new_theme->font_name;
+  font_size_ = new_theme->font_size;
+
   // TODO(abigailbklein): Use v8::Function rather than javascript. If possible,
   // replace this function call with firing an event.
-  std::string script = "chrome.readAnything.updateFontName();";
-  render_frame_->ExecuteJavaScript(base::ASCIIToUTF16(script));
-}
-
-void ReadAnythingAppController::OnFontSizeChanged(const float new_font_size) {
-  font_size_ = new_font_size;
-
-  // TODO: Use v*::Function rather than javascript.
-  std::string script = "chrome.readAnything.updateFontSize();";
+  std::string script = "chrome.readAnything.updateTheme();";
   render_frame_->ExecuteJavaScript(base::ASCIIToUTF16(script));
 }
 
@@ -232,8 +228,8 @@
       .SetMethod("onConnected", &ReadAnythingAppController::OnConnected)
       .SetMethod("setContentForTesting",
                  &ReadAnythingAppController::SetContentForTesting)
-      .SetMethod("setFontNameForTesting",
-                 &ReadAnythingAppController::SetFontNameForTesting);
+      .SetMethod("setThemeForTesting",
+                 &ReadAnythingAppController::SetThemeForTesting);
 }
 
 std::vector<ui::AXNodeID> ReadAnythingAppController::ContentNodeIds() {
@@ -321,9 +317,9 @@
       std::move(page_handler_factory_receiver));
 }
 
-void ReadAnythingAppController::SetFontNameForTesting(
-    std::string new_font_name) {
-  OnFontNameChange(new_font_name);
+void ReadAnythingAppController::SetThemeForTesting(const std::string& font_name,
+                                                   float font_size) {
+  OnThemeChanged(ReadAnythingTheme::New(font_name, font_size));
 }
 
 void ReadAnythingAppController::SetContentForTesting(
diff --git a/chrome/renderer/accessibility/read_anything_app_controller.h b/chrome/renderer/accessibility/read_anything_app_controller.h
index f4010a1..a9dc29f 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller.h
+++ b/chrome/renderer/accessibility/read_anything_app_controller.h
@@ -66,8 +66,8 @@
   void OnAXTreeDistilled(
       const ui::AXTreeUpdate& snapshot,
       const std::vector<ui::AXNodeID>& content_node_ids) override;
-  void OnFontNameChange(const std::string& new_font_name) override;
-  void OnFontSizeChanged(const float new_font_size) override;
+  void OnThemeChanged(
+      read_anything::mojom::ReadAnythingThemePtr new_theme) override;
 
   // gin templates:
   std::vector<ui::AXNodeID> ContentNodeIds();
@@ -102,7 +102,7 @@
   //   };
   void SetContentForTesting(v8::Local<v8::Value> v8_snapshot_lite,
                             std::vector<ui::AXNodeID> content_node_ids);
-  void SetFontNameForTesting(std::string new_font_name);
+  void SetThemeForTesting(const std::string& font_name, float font_size);
 
   ui::AXNode* GetAXNode(ui::AXNodeID ax_node_id);
 
diff --git a/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc b/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
index e5b94b99..9d4a93f2 100644
--- a/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
+++ b/chrome/renderer/accessibility/read_anything_app_controller_browsertest.cc
@@ -34,10 +34,9 @@
     basic_snapshot_.nodes[3].id = 4;
   }
 
-  void OnFontNameChange(const std::string& new_font_name) {
-    controller_->OnFontNameChange(new_font_name);
+  void SetThemeForTesting(const std::string& font_name, float font_size) {
+    controller_->SetThemeForTesting(font_name, font_size);
   }
-
   void OnAXTreeDistilled(const ui::AXTreeUpdate& snapshot,
                          const std::vector<ui::AXNodeID>& content_node_ids) {
     controller_->OnAXTreeDistilled(snapshot, content_node_ids);
@@ -49,6 +48,8 @@
 
   std::string FontName() { return controller_->FontName(); }
 
+  float FontSize() { return controller_->FontSize(); }
+
   std::vector<ui::AXNodeID> GetChildren(ui::AXNodeID ax_node_id) {
     return controller_->GetChildren(ax_node_id);
   }
@@ -89,10 +90,12 @@
   ReadAnythingAppController* controller_ = nullptr;
 };
 
-TEST_F(ReadAnythingAppControllerTest, FontName) {
+TEST_F(ReadAnythingAppControllerTest, Theme) {
   std::string font_name = "Roboto";
-  OnFontNameChange(font_name);
+  float font_size = 18.0;
+  SetThemeForTesting(font_name, font_size);
   EXPECT_EQ(font_name, FontName());
+  EXPECT_EQ(font_size, FontSize());
 }
 
 TEST_F(ReadAnythingAppControllerTest, ContentNodeIds) {
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index a02fc7c6..75dfd7b6 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3514,7 +3514,6 @@
     if (is_chromeos_ash) {
       sources += [
         "../browser/apps/app_service/browser_app_instance_tracker_browsertest.cc",
-        "../browser/apps/app_service/intent_util_browsertest.cc",
         "../browser/apps/app_service/media_access_browsertest.cc",
         "../browser/apps/app_service/metrics/app_platform_metrics_browsertest.cc",
         "../browser/apps/app_service/metrics/website_metrics_browsertest.cc",
@@ -4011,6 +4010,7 @@
         "../browser/ui/webui/signin/inline_login_handler_chromeos_browsertest.cc",
         "../browser/ui/webui/signin/signin_helper_chromeos_browsertest.cc",
         "../browser/ui/window_sizer/window_sizer_chromeos_uitest.cc",
+        "../browser/web_applications/app_service/web_app_publisher_helper_browsertest.cc",
         "../browser/web_applications/app_service/web_apps_browsertest.cc",
         "../browser/web_applications/app_service/web_apps_chromeos_browsertest.cc",
         "../browser/webshare/chromeos/sharesheet_client_browsertest.cc",
@@ -7979,12 +7979,13 @@
 
     if (is_chromeos) {
       sources += [
+        "../browser/chromeos/extensions/contact_center_insights/contact_center_insights_extension_manager_unittest.cc",
         "../browser/chromeos/extensions/login_screen/login/external_logout_request/external_logout_request_event_handler_unittest.cc",
         "../browser/chromeos/extensions/login_screen/login_state/login_state_api_unittest.cc",
-        "//chrome/browser/chromeos/extensions/contact_center_insights/contact_center_insights_extension_manager_unittest.cc",
 
         # TODO(b/207754758): Move the following file into the appropriate target
-        "//chrome/browser/chromeos/extensions/telemetry/api/api_guard_delegate_unittest.cc",
+        "../browser/chromeos/extensions/telemetry/api/api_guard_delegate_unittest.cc",
+        "../browser/chromeos/reporting/network/network_bandwidth_sampler_unittest.cc",
       ]
       deps += [
         "//chrome/browser/chromeos/extensions/telemetry/api",
@@ -7992,6 +7993,7 @@
         "//chrome/browser/chromeos/extensions/telemetry/api:unit_tests",
         "//chrome/common/chromeos/extensions",
         "//chromeos/dbus/missive:missive",
+        "//components/reporting/proto:metric_data_proto",
       ]
     }
 
diff --git a/chrome/test/data/web_apps/tab_strip_customizations.html b/chrome/test/data/web_apps/tab_strip_customizations.html
new file mode 100644
index 0000000..8a5a49a
--- /dev/null
+++ b/chrome/test/data/web_apps/tab_strip_customizations.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <link rel="manifest" href="tab_strip_customizations.json">
+  <link rel="icon" href="basic-48.png">
+</head>
+<body>
+  <h1>Web app with tab strip</h1>
+  <script>
+    navigator.serviceWorker.register('/web_apps/service_worker.js');
+  </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/chrome/test/data/banners/manifest_tab_strip_customizations.json b/chrome/test/data/web_apps/tab_strip_customizations.json
similarity index 73%
rename from chrome/test/data/banners/manifest_tab_strip_customizations.json
rename to chrome/test/data/web_apps/tab_strip_customizations.json
index 1282143..b5dde37 100644
--- a/chrome/test/data/banners/manifest_tab_strip_customizations.json
+++ b/chrome/test/data/web_apps/tab_strip_customizations.json
@@ -7,12 +7,13 @@
       "type": "image/png"
     }
   ],
-  "start_url": "manifest_test_page.html",
+  "start_url": "tab_strip_customizations.html",
   "display": "standalone",
   "display_override": [ "tabbed" ],
   "tab_strip": {
+    "home_tab": {},
     "new_tab_button": {
-      "url": "theme-color.html"
+      "url": "favicon_only.html"
     }
   }
 }
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/file_attachment_test.js b/chrome/test/data/webui/chromeos/os_feedback_ui/file_attachment_test.js
index 0cfc29e..95ddc38 100644
--- a/chrome/test/data/webui/chromeos/os_feedback_ui/file_attachment_test.js
+++ b/chrome/test/data/webui/chromeos/os_feedback_ui/file_attachment_test.js
@@ -156,6 +156,9 @@
     assertEquals('Replace file', getElement('#replaceFileButton').ariaLabel);
     // Verify the i18n string is added.
     assertTrue(page.i18nExists('replaceFileArialLabel'));
+    // Verify the image container is not visible for non-image files.
+    const selectedImageButton = getElement('#selectedImageButton');
+    assertFalse(isVisible(selectedImageButton));
   });
 
   // Test that when there is not a file selected, getAttachedFile returns null.
@@ -288,8 +291,10 @@
     const selectedImage = getElement('#selectedFileImage');
     assertTrue(!!selectedImage.src);
     assertEquals(imageUrl, selectedImage.src);
-    assertEquals(
-        'Preview fake.png', getElement('#selectedImageButton').ariaLabel);
+    const selectedImageButton = getElement('#selectedImageButton');
+    assertEquals('Preview fake.png', selectedImageButton.ariaLabel);
+    // Verify the image container is visible for image files.
+    assertTrue(isVisible(selectedImageButton));
   });
 
   // Test that clicking the image will open preview dialog and set the
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.js b/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.js
index 66eb111..04bfbae 100644
--- a/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.js
+++ b/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.js
@@ -122,6 +122,10 @@
     assertTrue(page.i18nExists('attachFilesLabel'));
     assertEquals('Attach files', getElementContent('#attachFilesLabel'));
 
+    // Verify the add files Icon is in the page.
+    const addFilesIcon = getElement('#attachFilesIcon');
+    assertTrue(!!addFilesIcon);
+
     // Verify the user email label is in the page.
     assertTrue(page.i18nExists('userEmailLabel'));
     assertEquals('Email', getElementContent('#userEmailLabel'));
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_enter_rsu_wp_disable_code_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_enter_rsu_wp_disable_code_page_test.js
index a0edfbd..6263925 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/onboarding_enter_rsu_wp_disable_code_page_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/onboarding_enter_rsu_wp_disable_code_page_test.js
@@ -81,7 +81,7 @@
   test('EnterRsuWpDisableCodePageRendersQrCode', async () => {
     await initializeEnterRsuWpDisableCodePage('', '');
 
-    const expectedCanvasSize = 60;
+    const expectedCanvasSize = 20;
 
 
     assertEquals(suppressedComponentCanvasSize_(component), expectedCanvasSize);
diff --git a/chrome/test/data/webui/chromeos/shimless_rma/reimaging_provisioning_page_test.js b/chrome/test/data/webui/chromeos/shimless_rma/reimaging_provisioning_page_test.js
index dd4a2284..063d8772 100644
--- a/chrome/test/data/webui/chromeos/shimless_rma/reimaging_provisioning_page_test.js
+++ b/chrome/test/data/webui/chromeos/shimless_rma/reimaging_provisioning_page_test.js
@@ -7,7 +7,7 @@
 import {setShimlessRmaServiceForTesting} from 'chrome://shimless-rma/mojo_interface_provider.js';
 import {ReimagingProvisioningPage} from 'chrome://shimless-rma/reimaging_provisioning_page.js';
 import {ShimlessRma} from 'chrome://shimless-rma/shimless_rma.js';
-import {ProvisioningError, ProvisioningStatus} from 'chrome://shimless-rma/shimless_rma_types.js';
+import {ProvisioningError, ProvisioningStatus, RmadErrorCode} from 'chrome://shimless-rma/shimless_rma_types.js';
 
 import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 import {flushTasks} from '../../test_util.js';
@@ -111,6 +111,14 @@
   test('ProvisioningFailedNonWpError', async () => {
     await initializeWaitForProvisioningPage();
 
+    let hardwareErrorEventFired = false;
+
+    const eventHandler = (event) => {
+      hardwareErrorEventFired = true;
+      assertEquals(RmadErrorCode.kProvisioningFailed, event.detail);
+    };
+    component.addEventListener('fatal-hardware-error', eventHandler);
+
     const wpEnabledDialog =
         component.shadowRoot.querySelector('#wpEnabledDialog');
     assertTrue(!!wpEnabledDialog);
@@ -122,5 +130,8 @@
     await flushTasks();
 
     assertFalse(wpEnabledDialog.open);
+    assertTrue(hardwareErrorEventFired);
+
+    component.removeEventListener('fatal-hardware-error', eventHandler);
   });
 }
diff --git a/chrome/test/data/webui/settings/chromeos/device_page_tests.js b/chrome/test/data/webui/settings/chromeos/device_page_tests.js
index 3513deb..948689b 100644
--- a/chrome/test/data/webui/settings/chromeos/device_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/device_page_tests.js
@@ -14,7 +14,7 @@
 
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 
-import {crosAudioConfigFakeMicJack, crosAudioConfigFakeSpeaker, defaultFakeAudioSystemProperties, FakeCrosAudioConfig} from './fake_cros_audio_config.js';
+import {crosAudioConfigActiveFakeSpeaker, crosAudioConfigDefaultFakeMicJack, crosAudioConfigDefaultFakeSpeaker, crosAudioConfigInactiveFakeMicJack, defaultFakeAudioSystemProperties, FakeCrosAudioConfig} from './fake_cros_audio_config.js';
 import {FakeSystemDisplay} from './fake_system_display.js';
 
 /** @enum {string} */
@@ -715,6 +715,7 @@
     let crosAudioConfig;
 
     // Static test audio system properties.
+    /** @type {!AudioSystemProperties} */
     const maxVolumePercentFakeAudioSystemProperties = {
       outputVolumePercent: 100,
 
@@ -722,9 +723,13 @@
       outputMuteState: crosAudioConfigMojomWebui.MuteState.kNotMuted,
 
       /** @type {!Array<!AudioDevice>} */
-      outputDevices: [crosAudioConfigFakeSpeaker, crosAudioConfigFakeMicJack],
+      outputDevices: [
+        crosAudioConfigDefaultFakeSpeaker,
+        crosAudioConfigDefaultFakeMicJack,
+      ],
     };
 
+    /** @type {!AudioSystemProperties} */
     const minVolumePercentFakeAudioSystemProperties = {
       outputVolumePercent: 0,
 
@@ -732,9 +737,13 @@
       outputMuteState: crosAudioConfigMojomWebui.MuteState.kNotMuted,
 
       /** @type {!Array<!AudioDevice>} */
-      outputDevices: [crosAudioConfigFakeSpeaker, crosAudioConfigFakeMicJack],
+      outputDevices: [
+        crosAudioConfigDefaultFakeSpeaker,
+        crosAudioConfigDefaultFakeMicJack,
+      ],
     };
 
+    /** @type {!AudioSystemProperties} */
     const mutedByUserFakeAudioSystemProperties = {
       outputVolumePercent: 75,
 
@@ -742,9 +751,13 @@
       outputMuteState: crosAudioConfigMojomWebui.MuteState.kMutedByUser,
 
       /** @type {!Array<!AudioDevice>} */
-      outputDevices: [crosAudioConfigFakeSpeaker, crosAudioConfigFakeMicJack],
+      outputDevices: [
+        crosAudioConfigDefaultFakeSpeaker,
+        crosAudioConfigDefaultFakeMicJack,
+      ],
     };
 
+    /** @type {!AudioSystemProperties} */
     const mutedByPolicyFakeAudioSystemProperties = {
       outputVolumePercent: 75,
 
@@ -752,7 +765,35 @@
       outputMuteState: crosAudioConfigMojomWebui.MuteState.kMutedByPolicy,
 
       /** @type {!Array<!AudioDevice>} */
-      outputDevices: [crosAudioConfigFakeSpeaker, crosAudioConfigFakeMicJack],
+      outputDevices: [
+        crosAudioConfigDefaultFakeSpeaker,
+        crosAudioConfigDefaultFakeMicJack,
+      ],
+    };
+
+    /** @type {!AudioSystemProperties} */
+    const emptyOutputDevicesFakeAudioSystemProperties = {
+      outputVolumePercent: 75,
+
+      /** @type {!MuteState} */
+      outputMuteState: crosAudioConfigMojomWebui.MuteState.kNotMuted,
+
+      /** @type {!Array<!AudioDevice>} */
+      outputDevices: [],
+    };
+
+    /** @type {!AudioSystemProperties} */
+    const activeSpeakerFakeAudioSystemProperties = {
+      outputVolumePercent: 75,
+
+      /** @type {!MuteState} */
+      outputMuteState: crosAudioConfigMojomWebui.MuteState.kNotMuted,
+
+      /** @type {!Array<!AudioDevice>} */
+      outputDevices: [
+        crosAudioConfigActiveFakeSpeaker,
+        crosAudioConfigInactiveFakeMicJack,
+      ],
     };
 
     setup(async function() {
@@ -819,6 +860,40 @@
       assertTrue(audioPage.getIsOutputMutedForTest());
       assertTrue(outputVolumeSlider.disabled);
     });
+
+    test('output device mojo test', async function() {
+      const outputDeviceDropdown =
+          audioPage.shadowRoot.querySelector('#audioOutputDeviceDropdown');
+
+      // Test default properties.
+      assertEquals(
+          crosAudioConfigDefaultFakeMicJack.id,
+          BigInt(outputDeviceDropdown.value));
+      assertEquals(
+          defaultFakeAudioSystemProperties.outputDevices.length,
+          outputDeviceDropdown.length);
+
+      // Test empty output devices case.
+      crosAudioConfig.setAudioSystemProperties(
+          emptyOutputDevicesFakeAudioSystemProperties);
+      await flushTasks();
+      assertTrue(!outputDeviceDropdown.value);
+      assertEquals(
+          emptyOutputDevicesFakeAudioSystemProperties.outputDevices.length,
+          outputDeviceDropdown.length);
+
+      // Test active speaker case.
+      crosAudioConfig.setAudioSystemProperties(
+          activeSpeakerFakeAudioSystemProperties);
+      await flushTasks();
+      assertEquals(
+          crosAudioConfigActiveFakeSpeaker.id,
+          BigInt(outputDeviceDropdown.value));
+      assertEquals(
+          activeSpeakerFakeAudioSystemProperties.outputDevices.length,
+          outputDeviceDropdown.length);
+    });
+
   });
 
   suite(assert(TestNames.Pointers), function() {
diff --git a/chrome/test/data/webui/settings/chromeos/fake_cros_audio_config.js b/chrome/test/data/webui/settings/chromeos/fake_cros_audio_config.js
index 35707b9..fa60999 100644
--- a/chrome/test/data/webui/settings/chromeos/fake_cros_audio_config.js
+++ b/chrome/test/data/webui/settings/chromeos/fake_cros_audio_config.js
@@ -46,24 +46,9 @@
 };
 
 /** @type {!ash.audioConfig.mojom.AudioDevice} */
-export const crosAudioConfigFakeSpeaker = {
+export const crosAudioConfigDefaultFakeMicJack = {
   /** @type {bigint} */
-  id: BigInt(10001),
-
-  /** @type {string} */
-  displayName: 'Speaker',
-
-  /** @type {boolean} */
-  isActive: false,
-
-  /** @type {!ash.audioConfig.mojom.AudioDeviceType} */
-  deviceType: CrosAudioConfigAudioDeviceType.kInternalSpeaker,
-};
-
-/** @type {!ash.audioConfig.mojom.AudioDevice} */
-export const crosAudioConfigFakeMicJack = {
-  /** @type {bigint} */
-  id: BigInt(10010),
+  id: BigInt(1),
 
   /** @type {string} */
   displayName: 'Mic Jack',
@@ -75,10 +60,56 @@
   deviceType: CrosAudioConfigAudioDeviceType.kInternalMic,
 };
 
+/** @type {!ash.audioConfig.mojom.AudioDevice} */
+export const crosAudioConfigActiveFakeSpeaker = {
+  /** @type {bigint} */
+  id: BigInt(2),
+
+  /** @type {string} */
+  displayName: 'Speaker',
+
+  /** @type {boolean} */
+  isActive: true,
+
+  /** @type {!ash.audioConfig.mojom.AudioDeviceType} */
+  deviceType: CrosAudioConfigAudioDeviceType.kInternalSpeaker,
+};
+
+/** @type {!ash.audioConfig.mojom.AudioDevice} */
+export const crosAudioConfigInactiveFakeMicJack = {
+  /** @type {bigint} */
+  id: BigInt(3),
+
+  /** @type {string} */
+  displayName: 'Mic Jack',
+
+  /** @type {boolean} */
+  isActive: false,
+
+  /** @type {!ash.audioConfig.mojom.AudioDeviceType} */
+  deviceType: CrosAudioConfigAudioDeviceType.kInternalSpeaker,
+};
+
+/** @type {!ash.audioConfig.mojom.AudioDevice} */
+export const crosAudioConfigDefaultFakeSpeaker = {
+  /** @type {bigint} */
+  id: BigInt(4),
+
+  /** @type {string} */
+  displayName: 'Speaker',
+
+  /** @type {boolean} */
+  isActive: false,
+
+  /** @type {!ash.audioConfig.mojom.AudioDeviceType} */
+  deviceType: CrosAudioConfigAudioDeviceType.kInternalSpeaker,
+};
+
 /** @type {!ash.audioConfig.mojom.AudioSystemProperties} */
 export const defaultFakeAudioSystemProperties = {
   /** @type {!Array<!ash.audioConfig.mojom.AudioDevice>} */
-  outputDevices: [crosAudioConfigFakeSpeaker, crosAudioConfigFakeMicJack],
+  outputDevices:
+      [crosAudioConfigDefaultFakeSpeaker, crosAudioConfigDefaultFakeMicJack],
 
   outputVolumePercent: 75,
 
diff --git a/chrome/test/data/webui/settings/clear_browsing_data_test.ts b/chrome/test/data/webui/settings/clear_browsing_data_test.ts
index 0be26cc7..c5224154 100644
--- a/chrome/test/data/webui/settings/clear_browsing_data_test.ts
+++ b/chrome/test/data/webui/settings/clear_browsing_data_test.ts
@@ -14,7 +14,7 @@
 import {TestClearBrowsingDataBrowserProxy} from './test_clear_browsing_data_browser_proxy.js';
 import {TestSyncBrowserProxy} from './test_sync_browser_proxy.js';
 
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 import {Router, routes} from 'chrome://settings/settings.js';
 import {isChildVisible} from 'chrome://webui-test/test_util.js';
 // </if>
@@ -134,7 +134,7 @@
         '#clearBrowsingDataDialog [slot=footer]'));
 
     // The footer is never shown on Lacros.
-    // <if expr="not chromeos_ash and not chromeos_lacros">
+    // <if expr="not is_chromeos">
     // Syncing: the footer is shown, with the normal sync info.
     webUIListenerCallback('sync-status-changed', {
       signedIn: true,
@@ -187,7 +187,7 @@
   });
 
   // The footer is never shown on Lacros.
-  // <if expr="not chromeos_ash and not chromeos_lacros">
+  // <if expr="not is_chromeos">
   test('ClearBrowsingDataPauseSyncDesktop', function() {
     webUIListenerCallback('sync-status-changed', {
       signedIn: true,
@@ -636,7 +636,7 @@
     });
   });
 
-  // <if expr="chromeos_ash or chromeos_lacros">
+  // <if expr="is_chromeos">
   // On ChromeOS the footer is never shown.
   test('ClearBrowsingDataSyncAccountInfo', function() {
     assertTrue(element.$.clearBrowsingDataDialog.open);
diff --git a/chrome/test/data/webui/settings/password_edit_dialog_test.ts b/chrome/test/data/webui/settings/password_edit_dialog_test.ts
index 164f126..b463af1 100644
--- a/chrome/test/data/webui/settings/password_edit_dialog_test.ts
+++ b/chrome/test/data/webui/settings/password_edit_dialog_test.ts
@@ -813,7 +813,7 @@
     assertEquals('', noteElement!.value);
   });
 
-  // <if expr="not chromeos_ash and not chromeos_lacros">
+  // <if expr="not is_chromeos">
   // On ChromeOS/Lacros the behavior is different (on failure we request token
   // and retry).
   test(
diff --git a/chrome/test/data/webui/settings/people_page_test.ts b/chrome/test/data/webui/settings/people_page_test.ts
index 5a1e1f6..60963f1 100644
--- a/chrome/test/data/webui/settings/people_page_test.ts
+++ b/chrome/test/data/webui/settings/people_page_test.ts
@@ -6,12 +6,12 @@
 import 'chrome://settings/lazy_load.js';
 
 import {webUIListenerCallback} from 'chrome://resources/js/cr.m.js';
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 import {listenOnce} from 'chrome://resources/js/util.m.js';
 // </if>
 
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 import {CrCheckboxElement} from 'chrome://settings/lazy_load.js';
 // </if>
 
@@ -21,14 +21,14 @@
 
 import {pageVisibility, ProfileInfoBrowserProxyImpl, Router, routes, SettingsPeoplePageElement, StatusAction, SyncBrowserProxyImpl} from 'chrome://settings/settings.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 import {assertLT} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks, waitBeforeNextRender} from 'chrome://webui-test/test_util.js';
 
 // </if>
 
 import {simulateSyncStatus} from './sync_test_util.js';
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 import {simulateStoredAccounts} from './sync_test_util.js';
 // </if>
 
@@ -99,7 +99,7 @@
   });
 });
 
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 suite('SigninDisallowedTests', function() {
   setup(function() {
     loadTimeData.overrideValues({signinAllowed: false});
diff --git a/chrome/test/data/webui/settings/personalization_options_test.ts b/chrome/test/data/webui/settings/personalization_options_test.ts
index c26a031..1928620 100644
--- a/chrome/test/data/webui/settings/personalization_options_test.ts
+++ b/chrome/test/data/webui/settings/personalization_options_test.ts
@@ -11,9 +11,8 @@
 import {loadTimeData, PrivacyPageBrowserProxyImpl, SettingsToggleButtonElement, StatusAction, SyncBrowserProxyImpl} from 'chrome://settings/settings.js';
 import {assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {isVisible} from 'chrome://webui-test/test_util.js';
-// <if expr="not chromeos_ash and not chromeos_lacros">
+// <if expr="not is_chromeos">
 import {eventToPromise} from 'chrome://webui-test/test_util.js';
-
 // </if>
 
 import {TestPrivacyPageBrowserProxy} from './test_privacy_page_browser_proxy.js';
@@ -90,7 +89,7 @@
         !!testElement.shadowRoot!.querySelector('#driveSuggestControl'));
   });
 
-  // <if expr="not chromeos_ash and not chromeos_lacros">
+  // <if expr="not is_chromeos">
   test('signinAllowedToggle', function() {
     const toggle = testElement.$.signinAllowedToggle;
     assertTrue(isVisible(toggle));
diff --git a/chrome/test/data/webui/settings/privacy_page_test.ts b/chrome/test/data/webui/settings/privacy_page_test.ts
index c187fe6..0dd95bda 100644
--- a/chrome/test/data/webui/settings/privacy_page_test.ts
+++ b/chrome/test/data/webui/settings/privacy_page_test.ts
@@ -129,14 +129,14 @@
     // All redesigned pages, except notifications, protocol handlers, pdf
     // documents and protected content (except chromeos and win), will use a
     // settings-category-default-radio-group.
-    // <if expr="chromeos_ash or chromeos_lacros or is_win">
+    // <if expr="is_chromeos or is_win">
     assertEquals(
         page.shadowRoot!
             .querySelectorAll('settings-category-default-radio-group')
             .length,
         redesignedPages.length - 3);
     // </if>
-    // <if expr="not chromeos_ash and not chromeos_lacros and not is_win">
+    // <if expr="not is_chromeos and not is_win">
     assertEquals(
         page.shadowRoot!
             .querySelectorAll('settings-category-default-radio-group')
diff --git a/chrome/test/data/webui/settings/route_tests.ts b/chrome/test/data/webui/settings/route_tests.ts
index 3e99862..7a7f0f68 100644
--- a/chrome/test/data/webui/settings/route_tests.ts
+++ b/chrome/test/data/webui/settings/route_tests.ts
@@ -262,7 +262,7 @@
     // </if>
 
     assertFalse(routes.PRIVACY.isNavigableDialog);
-    // <if expr="not chromeos_ash and not chromeos_lacros">
+    // <if expr="not is_chromeos">
     assertFalse(routes.DEFAULT_BROWSER.isNavigableDialog);
     // </if>
   });
diff --git a/chrome/test/data/webui/settings/settings_menu_test.ts b/chrome/test/data/webui/settings/settings_menu_test.ts
index d61861c..f7753daf 100644
--- a/chrome/test/data/webui/settings/settings_menu_test.ts
+++ b/chrome/test/data/webui/settings/settings_menu_test.ts
@@ -93,7 +93,7 @@
     function assertPagesHidden(expectedHidden: boolean) {
       const ids = [
         'accessibility', 'appearance',
-        // <if expr="not chromeos_ash and not chromeos_lacros">
+        // <if expr="not is_chromeos">
         'defaultBrowser',
         // </if>
         'downloads', 'languages', 'onStartup', 'people', 'reset',
diff --git a/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts b/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts
index 75706811..658b5c5 100644
--- a/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/read_anything_app_test.ts
@@ -20,6 +20,7 @@
     document.body.innerHTML = '';
     readAnythingApp = document.createElement('read-anything-app');
     document.body.appendChild(readAnythingApp);
+    chrome.readAnything.setThemeForTesting('default', 18.0);
   });
 
   function assertFontName(fontFamily: string) {
@@ -27,35 +28,45 @@
     assertEquals(fontFamily, getComputedStyle(container!).fontFamily);
   }
 
+  function assertFontSize(fontSize: string) {
+    const container = readAnythingApp.shadowRoot!.getElementById('container');
+    assertEquals(fontSize, getComputedStyle(container!).fontSize);
+  }
+
   function assertContainerInnerHTML(expected: string) {
     const actual: string =
         readAnythingApp.shadowRoot!.getElementById('container')!.innerHTML;
     assertEquals(actual, expected);
   }
 
-  test('updateFontName', () => {
-    chrome.readAnything.setFontNameForTesting('Standard font');
+  test('updateTheme fontName', () => {
+    chrome.readAnything.setThemeForTesting('Standard font', 18.0);
     assertFontName('"Standard font"');
 
-    chrome.readAnything.setFontNameForTesting('Sans-serif');
+    chrome.readAnything.setThemeForTesting('Sans-serif', 18.0);
     assertFontName('sans-serif');
 
-    chrome.readAnything.setFontNameForTesting('Serif');
+    chrome.readAnything.setThemeForTesting('Serif', 18.0);
     assertFontName('serif');
 
-    chrome.readAnything.setFontNameForTesting('Avenir');
+    chrome.readAnything.setThemeForTesting('Avenir', 18.0);
     assertFontName('avenir');
 
-    chrome.readAnything.setFontNameForTesting('Comic Neue');
+    chrome.readAnything.setThemeForTesting('Comic Neue', 18.0);
     assertFontName('"Comic Neue"');
 
-    chrome.readAnything.setFontNameForTesting('Comic Sans MS');
+    chrome.readAnything.setThemeForTesting('Comic Sans MS', 18.0);
     assertFontName('"Comic Sans MS"');
 
-    chrome.readAnything.setFontNameForTesting('Poppins');
+    chrome.readAnything.setThemeForTesting('Poppins', 18.0);
     assertFontName('poppins');
   });
 
+  test('updateTheme fontSize', () => {
+    chrome.readAnything.setThemeForTesting('Standard font', 27.0);
+    assertFontSize('27px');
+  });
+
   test('updateContent paragraph', () => {
     // root id=1
     // ++paragraph id=2
diff --git a/chromeos/ash/components/network/cellular_esim_profile.cc b/chromeos/ash/components/network/cellular_esim_profile.cc
index 28cb955..e086adfe 100644
--- a/chromeos/ash/components/network/cellular_esim_profile.cc
+++ b/chromeos/ash/components/network/cellular_esim_profile.cc
@@ -7,7 +7,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "dbus/object_path.h"
 
-namespace chromeos {
+namespace ash {
 namespace {
 
 // Keys used by ToDictionaryValue() and FromDictionaryValue().
@@ -116,4 +116,4 @@
   return !(*this == other);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/cellular_esim_profile.h b/chromeos/ash/components/network/cellular_esim_profile.h
index c4a4fb31..bce633c 100644
--- a/chromeos/ash/components/network/cellular_esim_profile.h
+++ b/chromeos/ash/components/network/cellular_esim_profile.h
@@ -12,7 +12,7 @@
 #include "dbus/object_path.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace chromeos {
+namespace ash {
 
 // Metadata representing an eSIM profile.
 class COMPONENT_EXPORT(CHROMEOS_NETWORK) CellularESimProfile {
@@ -92,11 +92,6 @@
   std::string activation_code_;
 };
 
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove after the migration is finished.
-namespace ash {
-using ::chromeos::CellularESimProfile;
-}
+}  // namespace ash
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_CELLULAR_ESIM_PROFILE_H_
diff --git a/chromeos/ash/components/network/cellular_esim_profile_unittest.cc b/chromeos/ash/components/network/cellular_esim_profile_unittest.cc
index b1762f1..42362b5 100644
--- a/chromeos/ash/components/network/cellular_esim_profile_unittest.cc
+++ b/chromeos/ash/components/network/cellular_esim_profile_unittest.cc
@@ -10,7 +10,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace chromeos {
+namespace ash {
 
 TEST(CellularESimProfileTest, ConvertToAndFromDictionary) {
   CellularESimProfile profile(CellularESimProfile::State::kPending,
@@ -48,4 +48,4 @@
   EXPECT_FALSE(from_dictionary);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/cellular_utils.h b/chromeos/ash/components/network/cellular_utils.h
index ff3a33e..64a1e9c 100644
--- a/chromeos/ash/components/network/cellular_utils.h
+++ b/chromeos/ash/components/network/cellular_utils.h
@@ -8,8 +8,6 @@
 #include <vector>
 
 #include "base/component_export.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/cellular_esim_profile.h"
 #include "chromeos/ash/components/network/device_state.h"
 
 namespace dbus {
@@ -18,6 +16,8 @@
 
 namespace ash {
 
+class CellularESimProfile;
+
 // Generates a list of CellularESimProfile objects for all Hermes esim profile
 // objects available through its dbus clients. Note that this function returns
 // an empty array if CellularESimProfileHandler::RefreshProfileList has not
diff --git a/chromeos/ash/components/network/certificate_helper.cc b/chromeos/ash/components/network/certificate_helper.cc
index 5b6af64..175e892 100644
--- a/chromeos/ash/components/network/certificate_helper.cc
+++ b/chromeos/ash/components/network/certificate_helper.cc
@@ -16,8 +16,7 @@
 #include "net/cert/nss_cert_database_chromeos.h"
 #include "net/cert/x509_util_nss.h"
 
-namespace chromeos {
-namespace certificate {
+namespace ash::certificate {
 
 namespace {
 
@@ -93,5 +92,4 @@
   return Stringize(CERT_GetCommonName(&cert_handle->subject), alternative_text);
 }
 
-}  // namespace certificate
-}  // namespace chromeos
+}  // namespace ash::certificate
diff --git a/chromeos/ash/components/network/certificate_helper.h b/chromeos/ash/components/network/certificate_helper.h
index 9f70414..3ab7f97 100644
--- a/chromeos/ash/components/network/certificate_helper.h
+++ b/chromeos/ash/components/network/certificate_helper.h
@@ -11,8 +11,7 @@
 #include "base/component_export.h"
 #include "net/cert/cert_type.h"
 
-namespace chromeos {
-namespace certificate {
+namespace ash::certificate {
 
 // Selected functions from chrome/common/net/x509_certificate_model.cc
 
@@ -50,12 +49,6 @@
 COMPONENT_EXPORT(CHROMEOS_NETWORK)
 std::string GetCertAsciiNameOrNickname(CERTCertificate* cert_handle);
 
-}  // namespace certificate
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove when it moved to ash.
-namespace ash {
-namespace certificate = ::chromeos::certificate;
-}
+}  // namespace ash::certificate
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_CERTIFICATE_HELPER_H_
diff --git a/chromeos/ash/components/network/certificate_helper_unittest.cc b/chromeos/ash/components/network/certificate_helper_unittest.cc
index 4b9e8079..efd90b3 100644
--- a/chromeos/ash/components/network/certificate_helper_unittest.cc
+++ b/chromeos/ash/components/network/certificate_helper_unittest.cc
@@ -11,7 +11,7 @@
 #include "net/test/test_with_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 
 // Required to register an observer from the constructor of
 // net::NSSCertDatabase.
@@ -89,4 +89,4 @@
   EXPECT_EQ(net::SERVER_CERT, certificate::GetCertType(cert.get()));
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/firewall_hole.cc b/chromeos/ash/components/network/firewall_hole.cc
index d768d86..c6c1a33 100644
--- a/chromeos/ash/components/network/firewall_hole.cc
+++ b/chromeos/ash/components/network/firewall_hole.cc
@@ -17,7 +17,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chromeos/dbus/permission_broker/permission_broker_client.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -121,4 +121,4 @@
       interface_(interface),
       lifeline_fd_(std::move(lifeline_fd)) {}
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/firewall_hole.h b/chromeos/ash/components/network/firewall_hole.h
index 7697f554..23a912f 100644
--- a/chromeos/ash/components/network/firewall_hole.h
+++ b/chromeos/ash/components/network/firewall_hole.h
@@ -14,7 +14,7 @@
 #include "base/component_export.h"
 #include "base/files/scoped_file.h"
 
-namespace chromeos {
+namespace ash {
 
 // This class works with the Chrome OS permission broker to open a port in the
 // system firewall. It is closed on destruction.
@@ -58,11 +58,6 @@
   base::ScopedFD lifeline_fd_;
 };
 
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove when moved to ash.
-namespace ash {
-using ::chromeos::FirewallHole;
 }  // namespace ash
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_FIREWALL_HOLE_H_
diff --git a/chromeos/ash/components/network/firewall_hole_unittest.cc b/chromeos/ash/components/network/firewall_hole_unittest.cc
index 4ffe8422..a4bbf13 100644
--- a/chromeos/ash/components/network/firewall_hole_unittest.cc
+++ b/chromeos/ash/components/network/firewall_hole_unittest.cc
@@ -14,9 +14,11 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 namespace {
 
+using ::chromeos::FakePermissionBrokerClient;
+
 void CopyFirewallHole(base::RunLoop* run_loop,
                       std::unique_ptr<FirewallHole>* out_hole,
                       std::unique_ptr<FirewallHole> hole) {
@@ -86,4 +88,4 @@
 }
 
 }  // namespace
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/managed_network_configuration_handler.h b/chromeos/ash/components/network/managed_network_configuration_handler.h
index d6c3815..7f5d39a 100644
--- a/chromeos/ash/components/network/managed_network_configuration_handler.h
+++ b/chromeos/ash/components/network/managed_network_configuration_handler.h
@@ -14,8 +14,6 @@
 #include "chromeos/ash/components/network/client_cert_util.h"
 #include "chromeos/ash/components/network/network_handler.h"
 #include "chromeos/ash/components/network/network_handler_callbacks.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_profile.h"
 #include "components/onc/onc_constants.h"
 
 namespace base {
@@ -27,6 +25,7 @@
 class NetworkConfigurationHandler;
 class NetworkDeviceHandler;
 class NetworkPolicyObserver;
+struct NetworkProfile;
 class NetworkProfileHandler;
 class NetworkStateHandler;
 
diff --git a/chromeos/ash/components/network/managed_network_configuration_handler_impl.h b/chromeos/ash/components/network/managed_network_configuration_handler_impl.h
index a885c9f5..b034a041 100644
--- a/chromeos/ash/components/network/managed_network_configuration_handler_impl.h
+++ b/chromeos/ash/components/network/managed_network_configuration_handler_impl.h
@@ -17,8 +17,6 @@
 #include "chromeos/ash/components/network/client_cert_util.h"
 #include "chromeos/ash/components/network/managed_network_configuration_handler.h"
 #include "chromeos/ash/components/network/network_handler_callbacks.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_profile.h"
 #include "chromeos/ash/components/network/network_profile_observer.h"
 #include "chromeos/ash/components/network/policy_applicator.h"
 #include "chromeos/ash/components/network/profile_policies.h"
@@ -32,6 +30,7 @@
 class CellularPolicyHandler;
 class ManagedCellularPrefHandler;
 class NetworkConfigurationHandler;
+struct NetworkProfile;
 class NetworkProfileHandler;
 class NetworkStateHandler;
 
diff --git a/chromeos/ash/components/network/network_cert_loader.cc b/chromeos/ash/components/network/network_cert_loader.cc
index 84b71b5..83a7b46 100644
--- a/chromeos/ash/components/network/network_cert_loader.cc
+++ b/chromeos/ash/components/network/network_cert_loader.cc
@@ -28,7 +28,7 @@
 #include "net/cert/nss_cert_database_chromeos.h"
 #include "net/cert/x509_util_nss.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -591,4 +591,4 @@
   UpdateCertificates();
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/network_cert_loader.h b/chromeos/ash/components/network/network_cert_loader.h
index cdaca9c4..f645853 100644
--- a/chromeos/ash/components/network/network_cert_loader.h
+++ b/chromeos/ash/components/network/network_cert_loader.h
@@ -22,7 +22,7 @@
 class NSSCertDatabase;
 }
 
-namespace chromeos {
+namespace ash {
 
 // This class is responsible for loading certificates once the TPM is
 // initialized. It is expected to be constructed on the UI thread and public
@@ -276,12 +276,11 @@
   base::WeakPtrFactory<NetworkCertLoader> weak_factory_{this};
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove after the //chrome/browser/chromeos
-// source migration is finished.
-namespace ash {
-using ::chromeos::NetworkCertLoader;
+// TODO(https://crbug.com/1164001): remove when the migration is finished.
+namespace chromeos {
+using ::ash::NetworkCertLoader;
 }
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_CERT_LOADER_H_
diff --git a/chromeos/ash/components/network/network_cert_loader_unittest.cc b/chromeos/ash/components/network/network_cert_loader_unittest.cc
index 94c0c32..f95e5475 100644
--- a/chromeos/ash/components/network/network_cert_loader_unittest.cc
+++ b/chromeos/ash/components/network/network_cert_loader_unittest.cc
@@ -24,7 +24,7 @@
 #include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 namespace {
 
 class FakePolicyCertificateProvider : public PolicyCertificateProvider {
@@ -873,4 +873,4 @@
   ASSERT_EQ(0U, GetAndResetCertificatesLoadedEventsCount());
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/network_connect.cc b/chromeos/ash/components/network/network_connect.cc
index 74c68a9..7e84f22a 100644
--- a/chromeos/ash/components/network/network_connect.cc
+++ b/chromeos/ash/components/network/network_connect.cc
@@ -25,7 +25,7 @@
 #include "chromeos/login/login_state/login_state.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -554,4 +554,4 @@
 
 NetworkConnect::~NetworkConnect() = default;
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/network_connect.h b/chromeos/ash/components/network/network_connect.h
index e04cfec..4b5d15e 100644
--- a/chromeos/ash/components/network/network_connect.h
+++ b/chromeos/ash/components/network/network_connect.h
@@ -8,14 +8,14 @@
 #include <string>
 
 #include "base/component_export.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_type_pattern.h"
 
 namespace base {
 class Value;
 }
 
-namespace chromeos {
+namespace ash {
+
+class NetworkTypePattern;
 
 // NetworkConnect is a state machine designed to handle the complex UI flows
 // associated with connecting to a network (and related tasks). Any showing
@@ -81,9 +81,8 @@
   // Enables or disables a network technology. If |technology| refers to
   // cellular and the device cannot be enabled due to a SIM lock, this function
   // will launch the SIM unlock dialog.
-  virtual void SetTechnologyEnabled(
-      const chromeos::NetworkTypePattern& technology,
-      bool enabled_state) = 0;
+  virtual void SetTechnologyEnabled(const NetworkTypePattern& technology,
+                                    bool enabled_state) = 0;
 
   // Determines whether or not a network requires a connection to activate or
   // setup and either shows a notification or opens the mobile setup dialog.
@@ -115,11 +114,11 @@
   NetworkConnect();
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when moved to ash
-namespace ash {
-using ::chromeos::NetworkConnect;
+// TODO(https://crbug.com/1164001): remove when the migration is finished.
+namespace chromeos {
+using ::ash::NetworkConnect;
 }
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_CONNECT_H_
diff --git a/chromeos/ash/components/network/network_connect_unittest.cc b/chromeos/ash/components/network/network_connect_unittest.cc
index 2076007..625d218 100644
--- a/chromeos/ash/components/network/network_connect_unittest.cc
+++ b/chromeos/ash/components/network/network_connect_unittest.cc
@@ -29,7 +29,7 @@
 using testing::NiceMock;
 using testing::Return;
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -339,4 +339,4 @@
   base::RunLoop().RunUntilIdle();
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/network_ip_config.cc b/chromeos/ash/components/network/network_ip_config.cc
index ed49b24..f91f140 100644
--- a/chromeos/ash/components/network/network_ip_config.cc
+++ b/chromeos/ash/components/network/network_ip_config.cc
@@ -6,7 +6,7 @@
 
 #include "base/notreached.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 #define ENUM_CASE(x) case x: return std::string(#x)
@@ -50,4 +50,4 @@
       + " name_servers: " + name_servers;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/network_ip_config.h b/chromeos/ash/components/network/network_ip_config.h
index 10c5147a00..240929fe 100644
--- a/chromeos/ash/components/network/network_ip_config.h
+++ b/chromeos/ash/components/network/network_ip_config.h
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "base/component_export.h"
 
-namespace chromeos {
+namespace ash {
 
 // ipconfig types (see flimflam/files/doc/ipconfig-api.txt)
 enum IPConfigType {
@@ -44,6 +44,6 @@
 
 typedef std::vector<NetworkIPConfig> NetworkIPConfigVector;
 
-}  // namespace chromeos
+}  // namespace ash
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_IP_CONFIG_H_
diff --git a/chromeos/ash/components/network/network_profile.cc b/chromeos/ash/components/network/network_profile.cc
index eea7fd55..97f15d7d 100644
--- a/chromeos/ash/components/network/network_profile.cc
+++ b/chromeos/ash/components/network/network_profile.cc
@@ -7,7 +7,7 @@
 #include "base/notreached.h"
 #include "base/strings/stringprintf.h"
 
-namespace chromeos {
+namespace ash {
 
 std::string NetworkProfile::ToDebugString() const {
   if (type() == NetworkProfile::TYPE_SHARED) {
@@ -22,4 +22,4 @@
   return std::string();
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/network_profile.h b/chromeos/ash/components/network/network_profile.h
index bdba0f7..e46fc07 100644
--- a/chromeos/ash/components/network/network_profile.h
+++ b/chromeos/ash/components/network/network_profile.h
@@ -9,7 +9,7 @@
 
 #include "base/component_export.h"
 
-namespace chromeos {
+namespace ash {
 
 struct COMPONENT_EXPORT(CHROMEOS_NETWORK) NetworkProfile {
   enum Type {
@@ -33,11 +33,11 @@
   std::string ToDebugString() const;
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
-// TODO(https://crbug.com/1164001): remove when it moved to ash.
-namespace ash {
-using ::chromeos::NetworkProfile;
+// TODO(https://crbug.com/1164001): remove when the migration is finished.
+namespace chromeos {
+using ::ash::NetworkProfile;
 }
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_PROFILE_H_
diff --git a/chromeos/ash/components/network/network_profile_observer.h b/chromeos/ash/components/network/network_profile_observer.h
index e06e891..d9e27a9e 100644
--- a/chromeos/ash/components/network/network_profile_observer.h
+++ b/chromeos/ash/components/network/network_profile_observer.h
@@ -5,11 +5,10 @@
 #ifndef CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_PROFILE_OBSERVER_H_
 #define CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_PROFILE_OBSERVER_H_
 
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_profile.h"
-
 namespace ash {
 
+struct NetworkProfile;
+
 class NetworkProfileObserver {
  public:
   NetworkProfileObserver& operator=(const NetworkProfileObserver&) = delete;
diff --git a/chromeos/ash/components/network/network_ui_data.cc b/chromeos/ash/components/network/network_ui_data.cc
index 62ec8ad..964c6f5 100644
--- a/chromeos/ash/components/network/network_ui_data.cc
+++ b/chromeos/ash/components/network/network_ui_data.cc
@@ -11,7 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -131,4 +131,4 @@
   return EnumToString(kONCSourceTable, onc_source_);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/network_ui_data.h b/chromeos/ash/components/network/network_ui_data.h
index 1c841e1..d549418 100644
--- a/chromeos/ash/components/network/network_ui_data.h
+++ b/chromeos/ash/components/network/network_ui_data.h
@@ -12,7 +12,7 @@
 #include "base/values.h"
 #include "components/onc/onc_constants.h"
 
-namespace chromeos {
+namespace ash {
 
 // Helper for accessing and setting values in the network's UI data dictionary.
 // Accessing values is done via static members that take the network as an
@@ -51,11 +51,6 @@
   base::Value user_settings_;
 };
 
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove when it moved to ash.
-namespace ash {
-using ::chromeos::NetworkUIData;
-}
+}  // namespace ash
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_NETWORK_UI_DATA_H_
diff --git a/chromeos/ash/components/network/network_ui_data_unittest.cc b/chromeos/ash/components/network/network_ui_data_unittest.cc
index 9a0fddc..df9f3134 100644
--- a/chromeos/ash/components/network/network_ui_data_unittest.cc
+++ b/chromeos/ash/components/network/network_ui_data_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 
 TEST(NetworkUIDataTest, ONCSource) {
   base::Value ui_data_dict(base::Value::Type::DICTIONARY);
@@ -30,4 +30,4 @@
   }
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/network_util.h b/chromeos/ash/components/network/network_util.h
index a2a81f6..3c1a2cee 100644
--- a/chromeos/ash/components/network/network_util.h
+++ b/chromeos/ash/components/network/network_util.h
@@ -20,13 +20,12 @@
 #include "base/component_export.h"
 #include "base/time/time.h"
 #include "base/values.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_state.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_type_pattern.h"
 
 namespace ash {
 
+class NetworkState;
+class NetworkTypePattern;
+
 // Struct for passing wifi access point data.
 struct COMPONENT_EXPORT(CHROMEOS_NETWORK) WifiAccessPoint {
   WifiAccessPoint();
diff --git a/chromeos/ash/components/network/policy_applicator.cc b/chromeos/ash/components/network/policy_applicator.cc
index 1f289fcd..51281438c 100644
--- a/chromeos/ash/components/network/policy_applicator.cc
+++ b/chromeos/ash/components/network/policy_applicator.cc
@@ -28,7 +28,7 @@
 #include "dbus/object_path.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -471,4 +471,4 @@
   handler_->OnPoliciesApplied(profile_, new_cellular_policy_guids_);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/policy_applicator.h b/chromeos/ash/components/network/policy_applicator.h
index 9ca8d6f0..979d279 100644
--- a/chromeos/ash/components/network/policy_applicator.h
+++ b/chromeos/ash/components/network/policy_applicator.h
@@ -15,12 +15,11 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "base/values.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/managed_cellular_pref_handler.h"
 #include "chromeos/ash/components/network/network_profile.h"
 
-namespace chromeos {
+namespace ash {
 
+class ManagedCellularPrefHandler;
 class NetworkUIData;
 
 // This class compares (entry point is Run()) |modified_policies| with the
@@ -166,11 +165,6 @@
   base::WeakPtrFactory<PolicyApplicator> weak_ptr_factory_{this};
 };
 
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove when it moved to ash.
-namespace ash {
-using ::chromeos::PolicyApplicator;
-}
+}  // namespace ash
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_POLICY_APPLICATOR_H_
diff --git a/chromeos/ash/components/network/policy_certificate_provider.h b/chromeos/ash/components/network/policy_certificate_provider.h
index cba2c9d1..cb4ff5c 100644
--- a/chromeos/ash/components/network/policy_certificate_provider.h
+++ b/chromeos/ash/components/network/policy_certificate_provider.h
@@ -17,7 +17,7 @@
 using CertificateList = std::vector<scoped_refptr<X509Certificate>>;
 }  // namespace net
 
-namespace chromeos {
+namespace ash {
 
 // An interface for a class which makes server and authority certificates
 // available from enterprise policy. Clients of this interface can register as
@@ -70,6 +70,6 @@
       const = 0;
 };
 
-}  // namespace chromeos
+}  // namespace ash
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_POLICY_CERTIFICATE_PROVIDER_H_
diff --git a/chromeos/ash/components/network/policy_util.h b/chromeos/ash/components/network/policy_util.h
index 54e315d..7a4054e 100644
--- a/chromeos/ash/components/network/policy_util.h
+++ b/chromeos/ash/components/network/policy_util.h
@@ -8,14 +8,16 @@
 #include <string>
 
 #include "base/component_export.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_profile.h"
 
 namespace base {
 class Value;
 }
 
-namespace ash::policy_util {
+namespace ash {
+
+struct NetworkProfile;
+
+namespace policy_util {
 
 // This fake credential contains a random postfix which is extremely unlikely to
 // be used by any user. Used to determine saved but unknown credential
@@ -72,7 +74,8 @@
 // If there is no SMDPAddress, returns nullptr.
 const std::string* GetSMDPAddressFromONC(const base::Value& onc_config);
 
-}  // namespace ash::policy_util
+}  // namespace policy_util
+}  // namespace ash
 
 // TODO(https://crbug.com/1164001): remove when the migration is finished.
 namespace chromeos {
diff --git a/chromeos/ash/components/network/profile_policies.cc b/chromeos/ash/components/network/profile_policies.cc
index 01cbe99..98128db9 100644
--- a/chromeos/ash/components/network/profile_policies.cc
+++ b/chromeos/ash/components/network/profile_policies.cc
@@ -19,7 +19,7 @@
 #include "components/onc/onc_constants.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -272,4 +272,4 @@
   return iter != guid_to_policy_.end() ? &(iter->second) : nullptr;
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/profile_policies.h b/chromeos/ash/components/network/profile_policies.h
index da1b17cb..29855541 100644
--- a/chromeos/ash/components/network/profile_policies.h
+++ b/chromeos/ash/components/network/profile_policies.h
@@ -15,7 +15,7 @@
 #include "chromeos/ash/components/network/client_cert_util.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
-namespace chromeos {
+namespace ash {
 
 // Stores network policies for a shill profile.
 // Understands some ONC (OpenNetworkConfiguration) concepts such as
@@ -200,11 +200,6 @@
   base::flat_map<std::string, std::string> profile_wide_expansions_;
 };
 
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove when it moved to ash.
-namespace ash {
-using ::chromeos::ProfilePolicies;
-}
+}  // namespace ash
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_PROFILE_POLICIES_H_
diff --git a/chromeos/ash/components/network/profile_policies_unittest.cc b/chromeos/ash/components/network/profile_policies_unittest.cc
index 1775fdf..6d78350 100644
--- a/chromeos/ash/components/network/profile_policies_unittest.cc
+++ b/chromeos/ash/components/network/profile_policies_unittest.cc
@@ -13,7 +13,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -584,4 +584,4 @@
   EXPECT_FALSE(change_had_effect);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/proxy/proxy_config_handler.cc b/chromeos/ash/components/network/proxy/proxy_config_handler.cc
index 385767b..b44300d2 100644
--- a/chromeos/ash/components/network/proxy/proxy_config_handler.cc
+++ b/chromeos/ash/components/network/proxy/proxy_config_handler.cc
@@ -26,7 +26,7 @@
 #include "dbus/object_path.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -120,4 +120,4 @@
 
 }  // namespace proxy_config
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/proxy/proxy_config_handler.h b/chromeos/ash/components/network/proxy/proxy_config_handler.h
index a918d01..4a0e72d 100644
--- a/chromeos/ash/components/network/proxy/proxy_config_handler.h
+++ b/chromeos/ash/components/network/proxy/proxy_config_handler.h
@@ -8,16 +8,15 @@
 #include <memory>
 
 #include "base/component_export.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_profile_handler.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_state.h"
 #include "components/onc/onc_constants.h"
 
 class PrefService;
 class ProxyConfigDictionary;
 
-namespace chromeos {
+namespace ash {
+
+class NetworkProfileHandler;
+class NetworkState;
 
 namespace proxy_config {
 
@@ -38,15 +37,6 @@
                               const NetworkState& network);
 
 }  // namespace proxy_config
-
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove after the migration is finished.
-namespace ash {
-namespace proxy_config {
-using ::chromeos::proxy_config::GetProxyConfigForNetwork;
-using ::chromeos::proxy_config::SetProxyConfigForNetwork;
-}  // namespace proxy_config
 }  // namespace ash
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_PROXY_PROXY_CONFIG_HANDLER_H_
diff --git a/chromeos/ash/components/network/proxy/proxy_config_service_impl.cc b/chromeos/ash/components/network/proxy/proxy_config_service_impl.cc
index ac9c0ef..35a48152 100644
--- a/chromeos/ash/components/network/proxy/proxy_config_service_impl.cc
+++ b/chromeos/ash/components/network/proxy/proxy_config_service_impl.cc
@@ -26,7 +26,7 @@
 #include "components/proxy_config/proxy_prefs.h"
 #include "components/user_manager/user_manager.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -281,4 +281,4 @@
   }
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/proxy/proxy_config_service_impl.h b/chromeos/ash/components/network/proxy/proxy_config_service_impl.h
index 05f1914..b6733e04 100644
--- a/chromeos/ash/components/network/proxy/proxy_config_service_impl.h
+++ b/chromeos/ash/components/network/proxy/proxy_config_service_impl.h
@@ -10,14 +10,14 @@
 #include "base/compiler_specific.h"
 #include "base/component_export.h"
 #include "base/task/single_thread_task_runner.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_state.h"
 #include "chromeos/ash/components/network/network_state_handler_observer.h"
 #include "components/onc/onc_constants.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
 
-namespace chromeos {
+namespace ash {
+
+class NetworkState;
 
 // Implementation of proxy config service for chromeos that:
 // - extends PrefProxyConfigTrackerImpl (and so lives and runs entirely on UI
@@ -105,11 +105,6 @@
   base::WeakPtrFactory<ProxyConfigServiceImpl> pointer_factory_{this};
 };
 
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove after the migration is finished.
-namespace ash {
-using ::chromeos::ProxyConfigServiceImpl;
-}
+}  // namespace ash
 
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_PROXY_PROXY_CONFIG_SERVICE_IMPL_H_
diff --git a/chromeos/ash/components/network/proxy/proxy_config_service_impl_unittest.cc b/chromeos/ash/components/network/proxy/proxy_config_service_impl_unittest.cc
index 819bea0..ee7f7e2 100644
--- a/chromeos/ash/components/network/proxy/proxy_config_service_impl_unittest.cc
+++ b/chromeos/ash/components/network/proxy/proxy_config_service_impl_unittest.cc
@@ -17,7 +17,7 @@
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 namespace {
 
 const char kFixedPacUrl[] = "http://fixed/";
@@ -123,4 +123,4 @@
   proxy_tracker.DetachFromPrefService();
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/shill_property_util.h b/chromeos/ash/components/network/shill_property_util.h
index a6d0226..bc028ac 100644
--- a/chromeos/ash/components/network/shill_property_util.h
+++ b/chromeos/ash/components/network/shill_property_util.h
@@ -9,15 +9,17 @@
 #include <string>
 
 #include "base/component_export.h"
-// TODO(https://crbug.com/1164001): move to forward declaration
-#include "chromeos/ash/components/network/network_ui_data.h"
 #include "components/onc/onc_constants.h"
 
 namespace base {
 class Value;
 }
 
-namespace ash::shill_property_util {
+namespace ash {
+
+class NetworkUIData;
+
+namespace shill_property_util {
 
 // Sets the |ssid| in |properties|.
 COMPONENT_EXPORT(CHROMEOS_NETWORK)
@@ -93,7 +95,8 @@
 // be relied upon).
 bool IsLoggableShillProperty(const std::string& key);
 
-}  // namespace ash::shill_property_util
+}  // namespace shill_property_util
+}  // namespace ash
 
 // TODO(https://crbug.com/1164001): remove when the migration is finished.
 namespace chromeos {
diff --git a/chromeos/ash/components/network/system_token_cert_db_storage.cc b/chromeos/ash/components/network/system_token_cert_db_storage.cc
index 148da96..9aac9e1 100644
--- a/chromeos/ash/components/network/system_token_cert_db_storage.cc
+++ b/chromeos/ash/components/network/system_token_cert_db_storage.cc
@@ -14,7 +14,7 @@
 #include "base/timer/timer.h"
 #include "net/cert/nss_cert_database.h"
 
-namespace chromeos {
+namespace ash {
 
 namespace {
 
@@ -114,4 +114,4 @@
       /*nss_cert_database=*/nullptr);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/network/system_token_cert_db_storage.h b/chromeos/ash/components/network/system_token_cert_db_storage.h
index 2025a9e..25b3c88 100644
--- a/chromeos/ash/components/network/system_token_cert_db_storage.h
+++ b/chromeos/ash/components/network/system_token_cert_db_storage.h
@@ -19,7 +19,7 @@
 class NSSCertDatabase;
 }
 
-namespace chromeos {
+namespace ash {
 
 // Used by SystemTokenCertDbInitializer to save the system token certificate
 // database when it is ready.
@@ -109,11 +109,11 @@
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
-}  // namespace chromeos
-
-// TODO(https://crbug.com/1164001): remove when moved to ash.
-namespace ash {
-using ::chromeos::SystemTokenCertDbStorage;
 }  // namespace ash
 
+// TODO(https://crbug.com/1164001): remove when the migration is finished.
+namespace chromeos {
+using ::ash::SystemTokenCertDbStorage;
+}
+
 #endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_SYSTEM_TOKEN_CERT_DB_STORAGE_H_
diff --git a/chromeos/ash/components/network/system_token_cert_db_storage_unittest.cc b/chromeos/ash/components/network/system_token_cert_db_storage_unittest.cc
index d7c15219..5ea94ff 100644
--- a/chromeos/ash/components/network/system_token_cert_db_storage_unittest.cc
+++ b/chromeos/ash/components/network/system_token_cert_db_storage_unittest.cc
@@ -17,7 +17,7 @@
 #include "net/cert/nss_cert_database.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace ash {
 
 class SystemTokenCertDbStorageTest : public testing::Test {
  public:
@@ -200,4 +200,4 @@
       get_system_token_cert_db_callback_wrapper_2.IsDbRetrievalSucceeded());
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chromeos/ash/components/string_matching/fuzzy_tokenized_string_match_unittest.cc b/chromeos/ash/components/string_matching/fuzzy_tokenized_string_match_unittest.cc
index 51c3b47..6aa8475 100644
--- a/chromeos/ash/components/string_matching/fuzzy_tokenized_string_match_unittest.cc
+++ b/chromeos/ash/components/string_matching/fuzzy_tokenized_string_match_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
 #include "chromeos/ash/components/string_matching/sequence_matcher.h"
 #include "chromeos/ash/components/string_matching/tokenized_string.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -15,6 +16,10 @@
 
 namespace {
 
+// An upper limit for the purposes of catching regressions. Not for benchmarking
+// of typical expected time performance, which is much faster.
+constexpr base::TimeDelta kCalculationTimeUpperBound = base::Milliseconds(20);
+
 constexpr double kEps = 1e-5;
 constexpr double kCompleteMatchScore = 1.0;
 constexpr double kCompleteMismatchScore = 0.0;
@@ -711,6 +716,28 @@
   ExpectStrictlyIncreasing(scores);
 }
 
+TEST_F(FuzzyTokenizedStringMatchTest,
+       BenchmarkPrefixOfVaryingLengthMultiToken) {
+  std::u16string text = u"ghijkl abcdef";
+  std::vector<std::u16string> queries = {u"a",    u"ab",    u"abc",
+                                         u"abcd", u"abcde", u"abcdef"};
+
+  std::vector<double> scores;
+  for (const auto& query : queries) {
+    const double relevance = CalculateRelevance(query, text);
+    VLOG(1) << FormatRelevanceResult(query, text, relevance,
+                                     /*query_first*/ false);
+    scores.push_back(relevance);
+  }
+
+  // Intuitively, it seems desirable that, for a fixed text, the longer the
+  // prefix match between text and a query, the greater the relevance score
+  // should be. Check for this behavior here, but revisit the utility of this
+  // later as it relates to text-length agnosticism.
+
+  ExpectStrictlyIncreasing(scores);
+}
+
 TEST_F(FuzzyTokenizedStringMatchTest, BenchmarkPrefixVsNonPrefixSingleToken) {
   std::u16string text = u"abcdefg";
   std::vector<std::u16string> queries = {u"ab", u"bc", u"cd",
@@ -813,6 +840,189 @@
   //   query:   abc
 }
 
+TEST_F(FuzzyTokenizedStringMatchTest,
+       BenchmarkPrefixVsContiguousBlockMultiToken) {
+  std::u16string text = u"abxyz wabc";
+  std::u16string query = u"abc";
+
+  const double relevance = CalculateRelevance(query, text);
+  VLOG(1) << FormatRelevanceResult(query, text, relevance,
+                                   /*query_first*/ false);
+
+  // See also BenchmarkPrefixVsContiguousBlockSingleToken above, for note on
+  // prefix matching vs. longest contiguous block matching.
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest,
+       BenchmarkPrefixVsSameLengthNonPrefixMultiToken) {
+  FuzzyTokenizedStringMatch match;
+  std::u16string text = u"xyzabc abcdef";
+  std::u16string query = u"abc";
+  const double relevance = match.Relevance(
+      TokenizedString(query), TokenizedString(text), kUseWeightedRatio,
+      kUseEditDistance, kPartialMatchPenaltyRate);
+
+  VLOG(1) << FormatRelevanceResult(query, text, relevance,
+                                   /*query_first*/ false);
+
+  EXPECT_EQ(match.hits().size(), 1u);
+
+  // TODO(crbug.com/1336160): Currently the "abc" of "xyzabc" is matched.
+  // Consider an implementation which instead matches to the "abc" of "abcdef",
+  // i.e.:
+  //
+  //   EXPECT_EQ(match.hits()[0].start(), 7u);
+  //   EXPECT_EQ(match.hits()[0].end(), 10u);
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest,
+       BenchmarkPrefixVariedWordOrderMultiToken) {
+  std::u16string text = u"abcd efgh ijkl";
+  std::vector<std::u16string> queries = {u"abcd ef", u"abcd ij", u"efgh ab",
+                                         u"efgh ij", u"ijkl ab", u"ijkl ef"};
+  std::vector<double> scores;
+  for (const auto& query : queries) {
+    const double relevance = CalculateRelevance(query, text);
+    VLOG(1) << FormatRelevanceResult(query, text, relevance,
+                                     /*query_first*/ false);
+    scores.push_back(relevance);
+  }
+  // Currently, "abcd ef" and "efgh ij" score very highly due to being long
+  // contiguous matches.
+  //
+  // TODO(crbug.com/1336160): Support word order variation, so that we can e.g.:
+  //
+  //   ExpectAllNearlyEqual(scores);
+
+  // TODO(crbug.com/1336160): Consider a score boost for when a matched token is
+  // the first token of both text and query.
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest,
+       BenchmarkPrefixMultipleSameLengthMatchesMultiToken) {
+  FuzzyTokenizedStringMatch match;
+  std::u16string text = u"abcde abfgh abijk";
+  std::u16string query = u"ab";
+
+  const double relevance = match.Relevance(
+      TokenizedString(query), TokenizedString(text), kUseWeightedRatio,
+      kUseEditDistance, kPartialMatchPenaltyRate);
+  VLOG(1) << FormatRelevanceResult(query, text, relevance,
+                                   /*query_first*/ false);
+
+  // Where multiple same-length token prefix matches are possible, prioritize
+  // the earliest match.
+  EXPECT_EQ(match.hits().size(), 1u);
+  EXPECT_EQ(match.hits()[0].start(), 0u);
+  EXPECT_EQ(match.hits()[0].end(), 2u);
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest,
+       BenchmarkPrefixMultiplePossibleVariedLengthMatchesMultiToken) {
+  FuzzyTokenizedStringMatch match;
+  std::u16string text = u"abxyz abcwv abcdt";
+  std::u16string query = u"abcde";
+
+  const double relevance = match.Relevance(
+      TokenizedString(query), TokenizedString(text), kUseWeightedRatio,
+      kUseEditDistance, kPartialMatchPenaltyRate);
+  VLOG(1) << FormatRelevanceResult(query, text, relevance,
+                                   /*query_first*/ false);
+
+  // Expect a single hit, for the "abcd" of "abcdt".
+  EXPECT_EQ(match.hits().size(), 1u);
+  EXPECT_EQ(match.hits()[0].start(), 12u);
+  EXPECT_EQ(match.hits()[0].end(), 16u);
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest, BenchmarkStressTestLongText) {
+  // Same as BenchmarkStressTestLongQuery, with the roles of text and query
+  // reversed.
+
+  std::u16string text(300, 'a');
+
+  std::u16string query_high_match(25, 'a');
+  std::u16string query_low_match(u"bbbbbcccccbbbbbaaaaabbbbbcccccbbbbb");
+  std::u16string query_no_match(25, 'b');
+  std::vector<std::u16string> queries = {query_high_match, query_low_match,
+                                         query_no_match};
+
+  for (const auto& query : queries) {
+    base::Time start_time = base::Time::NowFromSystemTime();
+    const double relevance = CalculateRelevance(query, text);
+    base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time;
+
+    EXPECT_LT(elapsed_time, kCalculationTimeUpperBound);
+    VLOG(1) << FormatRelevanceResult(query, text, relevance,
+                                     /*query_first*/ false);
+    VLOG(1) << "Elapsed time (ms): " << elapsed_time.InMillisecondsF();
+  }
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest, BenchmarkStressTestLongQuery) {
+  // Same as BenchmarkStressTestLongText, with the roles of text and query
+  // reversed.
+  std::u16string query(300, 'a');
+
+  std::u16string text_high_match(25, 'a');
+  std::u16string text_low_match(u"bbbbbcccccbbbbbaaaaabbbbbcccccbbbbb");
+  std::u16string text_no_match(25, 'b');
+  std::vector<std::u16string> texts = {text_high_match, text_low_match,
+                                       text_no_match};
+
+  for (const auto& text : texts) {
+    base::Time start_time = base::Time::NowFromSystemTime();
+    const double relevance = CalculateRelevance(query, text);
+    base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time;
+
+    EXPECT_LT(elapsed_time, kCalculationTimeUpperBound);
+    VLOG(1) << FormatRelevanceResult(query, text, relevance,
+                                     /*query_first*/ true);
+    VLOG(1) << "Elapsed time (ms): " << elapsed_time.InMillisecondsF();
+  }
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest, BenchmarkStressTestLongTextLongQuery) {
+  std::u16string text(300, 'a');
+
+  std::u16string query_high_match(300, 'a');
+  std::u16string query_low_match = std::u16string(140, 'b') +
+                                   std::u16string(20, 'a') +
+                                   std::u16string(140, 'b');
+  std::u16string query_no_match(300, 'b');
+  std::vector<std::u16string> queries = {query_high_match, query_low_match,
+                                         query_no_match};
+
+  for (const auto& query : queries) {
+    base::Time start_time = base::Time::NowFromSystemTime();
+    const double relevance = CalculateRelevance(query, text);
+    base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time;
+
+    EXPECT_LT(elapsed_time, kCalculationTimeUpperBound);
+    VLOG(1) << FormatRelevanceResult(query, text, relevance,
+                                     /*query_first*/ false);
+    VLOG(1) << "Elapsed time (ms): " << elapsed_time.InMillisecondsF();
+  }
+}
+
+TEST_F(FuzzyTokenizedStringMatchTest, BenchmarkStressTestManyTokens) {
+  std::u16string text =
+      u"aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm nnn ooo ppp qqq "
+      u"rrr sss ttt uuu vvv www xxx yyy zzz";
+  std::u16string query =
+      u"zzz yyy xxx www vvv uuu ttt sss rrr qqq ppp ooo nnn mmm lll kkk jjj "
+      u"iii hhh ggg fff eee ddd ccc bbb aaa";
+
+  base::Time start_time = base::Time::NowFromSystemTime();
+  const double relevance = CalculateRelevance(query, text);
+  base::TimeDelta elapsed_time = base::Time::NowFromSystemTime() - start_time;
+
+  EXPECT_LT(elapsed_time, kCalculationTimeUpperBound);
+  VLOG(1) << FormatRelevanceResult(query, text, relevance,
+                                   /*query_first*/ false);
+  VLOG(1) << "Elapsed time (ms): " << elapsed_time.InMillisecondsF();
+}
+
 /**********************************************************************
  * Benchmarking section 2 - Non-abstract test cases                   *
  **********************************************************************/
diff --git a/chromeos/ash/components/trash_service/public/cpp/BUILD.gn b/chromeos/ash/components/trash_service/public/cpp/BUILD.gn
index 5448dfd4..fbecb78 100644
--- a/chromeos/ash/components/trash_service/public/cpp/BUILD.gn
+++ b/chromeos/ash/components/trash_service/public/cpp/BUILD.gn
@@ -8,6 +8,8 @@
 
 source_set("cpp") {
   sources = [
+    "trash_info_parser.cc",
+    "trash_info_parser.h",
     "trash_service.cc",
     "trash_service.h",
   ]
diff --git a/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.cc b/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.cc
new file mode 100644
index 0000000..961d9ce2
--- /dev/null
+++ b/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.cc
@@ -0,0 +1,57 @@
+// Copyright 2022 The Chromium 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/ash/components/trash_service/public/cpp/trash_info_parser.h"
+
+#include "base/files/file.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/time/time.h"
+
+namespace chromeos::trash_service {
+
+namespace {
+
+base::File GetReadOnlyFileFromPath(const base::FilePath& path) {
+  return base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+}
+
+}  // namespace
+
+TrashInfoParser::TrashInfoParser(
+    base::OnceCallback<void()> disconnect_callback) {
+  auto trash_pending_remote = LaunchTrashService();
+  service_ = mojo::Remote<mojom::TrashService>(std::move(trash_pending_remote));
+  service_.set_disconnect_handler(std::move(disconnect_callback));
+}
+
+TrashInfoParser::~TrashInfoParser() = default;
+
+void TrashInfoParser::ParseTrashInfoFile(const base::FilePath& path,
+                                         ParseTrashInfoCallback callback) {
+  if (!service_) {
+    LOG(ERROR) << "Trash service is not connected";
+    std::move(callback).Run(base::File::FILE_ERROR_FAILED, base::FilePath(),
+                            base::Time());
+    return;
+  }
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()},
+      base::BindOnce(&GetReadOnlyFileFromPath, std::move(path)),
+      base::BindOnce(&TrashInfoParser::OnGotFile,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void TrashInfoParser::OnGotFile(ParseTrashInfoCallback callback,
+                                base::File file) {
+  if (!file.IsValid()) {
+    LOG(ERROR) << "Trash info file is not valid " << file.error_details();
+    std::move(callback).Run(file.error_details(), base::FilePath(),
+                            base::Time());
+    return;
+  }
+  service_->ParseTrashInfoFile(std::move(file), std::move(callback));
+}
+
+}  // namespace chromeos::trash_service
diff --git a/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.h b/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.h
new file mode 100644
index 0000000..fe740252
--- /dev/null
+++ b/chromeos/ash/components/trash_service/public/cpp/trash_info_parser.h
@@ -0,0 +1,39 @@
+// Copyright 2022 The Chromium 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_ASH_COMPONENTS_TRASH_SERVICE_PUBLIC_CPP_TRASH_INFO_PARSER_H_
+#define CHROMEOS_ASH_COMPONENTS_TRASH_SERVICE_PUBLIC_CPP_TRASH_INFO_PARSER_H_
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "chromeos/ash/components/trash_service/public/cpp/trash_service.h"
+#include "chromeos/ash/components/trash_service/public/mojom/trash_service.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace chromeos::trash_service {
+
+// A class that manages the lifetime and mojo connection of the Trash service.
+class TrashInfoParser {
+ public:
+  explicit TrashInfoParser(base::OnceCallback<void()> disconnect_callback);
+  ~TrashInfoParser();
+
+  TrashInfoParser(const TrashInfoParser&) = delete;
+  TrashInfoParser& operator=(const TrashInfoParser&) = delete;
+
+  void ParseTrashInfoFile(const base::FilePath& path,
+                          ParseTrashInfoCallback callback);
+
+ private:
+  void OnGotFile(ParseTrashInfoCallback callback, base::File file);
+
+  // A connection to the underlying TrashService.
+  mojo::Remote<mojom::TrashService> service_;
+  base::WeakPtrFactory<TrashInfoParser> weak_ptr_factory_{this};
+};
+
+}  // namespace chromeos::trash_service
+
+#endif  // CHROMEOS_ASH_COMPONENTS_TRASH_SERVICE_PUBLIC_CPP_TRASH_INFO_PARSER_H_
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 5710a64a..8b89290 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -3445,6 +3445,9 @@
       <message name="IDS_FEEDBACK_TOOL_ADD_FILE_LABEL" desc="Label for the field of adding a file">
         Add file
       </message>
+      <message name="IDS_FEEDBACK_TOOL_ATTACH_FILE_LABEL_TOOLTIP" desc="Label for the tooltip content on attach files icon.">
+        Files will be sent to Google for debugging
+      </message>
       <message name="IDS_FEEDBACK_TOOL_ATTACH_FILE_CHECKBOX_ARIA_LABEL" desc="Aria Label of the checkbox to select the picked file">
         Attach file
       </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_FEEDBACK_TOOL_ATTACH_FILE_LABEL_TOOLTIP.png.sha1 b/chromeos/chromeos_strings_grd/IDS_FEEDBACK_TOOL_ATTACH_FILE_LABEL_TOOLTIP.png.sha1
new file mode 100644
index 0000000..a0a08a8
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_FEEDBACK_TOOL_ATTACH_FILE_LABEL_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+b17d6befb770e69ad90c0112dc9b90aed4a6cd4d
\ No newline at end of file
diff --git a/chromeos/components/onc/onc_utils.h b/chromeos/components/onc/onc_utils.h
index 76d6e921..a214ffd 100644
--- a/chromeos/components/onc/onc_utils.h
+++ b/chromeos/components/onc/onc_utils.h
@@ -126,6 +126,7 @@
 
 // TODO(https://crbug.com/1164001): remove when it moved to ash.
 namespace ash::onc {
+using ::chromeos::onc::ExpandStringsInOncObject;
 using ::chromeos::onc::FillInHexSSIDField;
 using ::chromeos::onc::FillInHexSSIDFieldsInOncObject;
 using ::chromeos::onc::MaskCredentialsInOncObject;
diff --git a/chromeos/system/scheduler_configuration_manager_base.cc b/chromeos/system/scheduler_configuration_manager_base.cc
index b206b830..18513422 100644
--- a/chromeos/system/scheduler_configuration_manager_base.cc
+++ b/chromeos/system/scheduler_configuration_manager_base.cc
@@ -17,7 +17,7 @@
 }
 
 void SchedulerConfigurationManagerBase::RemoveObserver(
-    const SchedulerConfigurationManagerBase::Observer* obs) {
+    SchedulerConfigurationManagerBase::Observer* obs) {
   observer_list_.RemoveObserver(obs);
 }
 
diff --git a/chromeos/system/scheduler_configuration_manager_base.h b/chromeos/system/scheduler_configuration_manager_base.h
index 4a4ec70..83de9bc5 100644
--- a/chromeos/system/scheduler_configuration_manager_base.h
+++ b/chromeos/system/scheduler_configuration_manager_base.h
@@ -40,7 +40,7 @@
   virtual absl::optional<std::pair<bool, size_t>> GetLastReply() const = 0;
 
   void AddObserver(Observer* obs);
-  void RemoveObserver(const Observer* obs);
+  void RemoveObserver(Observer* obs);
 
  protected:
   base::ObserverList<Observer> observer_list_;
diff --git a/chromeos/version/version_loader.h b/chromeos/version/version_loader.h
index 74b3818..5ed799e 100644
--- a/chromeos/version/version_loader.h
+++ b/chromeos/version/version_loader.h
@@ -53,15 +53,4 @@
 }  // namespace version_loader
 }  // namespace chromeos
 
-// TODO(https://crbug.com/1164001): remove when //chromeos/dbus moved to ash.
-namespace ash {
-namespace version_loader {
-using ::chromeos::version_loader::GetFirmware;
-using ::chromeos::version_loader::GetVersion;
-using ::chromeos::version_loader::VERSION_FULL;
-using ::chromeos::version_loader::VERSION_SHORT;
-using ::chromeos::version_loader::VERSION_SHORT_WITH_DATE;
-}  // namespace version_loader
-}  // namespace ash
-
 #endif  // CHROMEOS_VERSION_VERSION_LOADER_H_
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 280c5436..71a819b45 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -187,6 +187,8 @@
     "form_parsing/field_candidates.h",
     "form_parsing/form_field.cc",
     "form_parsing/form_field.h",
+    "form_parsing/iban_field.cc",
+    "form_parsing/iban_field.h",
     "form_parsing/merchant_promo_code_field.cc",
     "form_parsing/merchant_promo_code_field.h",
     "form_parsing/name_field.cc",
@@ -819,6 +821,7 @@
     "form_parsing/credit_card_field_unittest.cc",
     "form_parsing/field_candidates_unittest.cc",
     "form_parsing/form_field_unittest.cc",
+    "form_parsing/iban_field_unittest.cc",
     "form_parsing/merchant_promo_code_field_unittest.cc",
     "form_parsing/name_field_unittest.cc",
     "form_parsing/parsing_test_utils.cc",
diff --git a/components/autofill/core/browser/autofill_regex_constants.h b/components/autofill/core/browser/autofill_regex_constants.h
index c560393..73a92dc9 100644
--- a/components/autofill/core/browser/autofill_regex_constants.h
+++ b/components/autofill/core/browser/autofill_regex_constants.h
@@ -581,12 +581,17 @@
     u"yesbankltd"
     u")$";
 
-// Used to match field data that might be an International Bank Account Number.
+// Used to match the HTML name and label for International Bank Account Number
+// (IBAN).
+inline constexpr char16_t kIBANRe[] =
+    u"(\\biban(\\b|_)|international bank account number)";
+
+// Used to match field value that might be an International Bank Account Number.
 // TODO(crbug.com/977377): The regex doesn't match IBANs for Saint Lucia (LC),
 // Kazakhstan (KZ) and Romania (RO). Consider replace the regex with something
 // like "(?:IT|SM)\d{2}[A-Z]\d{22}|CY\d{2}[A-Z]\d{23}...". For reference:
 //    - https://www.swift.com/resource/iban-registry-pdf
-inline constexpr char16_t kInternationalBankAccountNumberRe[] =
+inline constexpr char16_t kInternationalBankAccountNumberValueRe[] =
     u"^[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}$";
 
 // Matches all 3 and 4 digit numbers.
diff --git a/components/autofill/core/browser/field_types.cc b/components/autofill/core/browser/field_types.cc
index 20ee50f8e..7c9c79c 100644
--- a/components/autofill/core/browser/field_types.cc
+++ b/components/autofill/core/browser/field_types.cc
@@ -101,9 +101,8 @@
     case UPI_VPA:
       return base::FeatureList::IsEnabled(features::kAutofillSaveAndFillVPA);
 
-    // TODO(crbug/1335549) to return true when the flag is enabled.
     case IBAN_VALUE:
-      return false;
+      return base::FeatureList::IsEnabled(features::kAutofillParseIBANFields);
 
     case COMPANY_NAME:
       return true;
diff --git a/components/autofill/core/browser/field_types.h b/components/autofill/core/browser/field_types.h
index 496ab51..16ff815 100644
--- a/components/autofill/core/browser/field_types.h
+++ b/components/autofill/core/browser/field_types.h
@@ -239,7 +239,9 @@
   PHONE_HOME_NUMBER_PREFIX = 123,
   PHONE_HOME_NUMBER_SUFFIX = 124,
 
-  // IBAN data.
+  // International Bank Account Number (IBAN) details are usually entered on
+  // banking and merchant websites used to make international transactions.
+  // See https://en.wikipedia.org/wiki/International_Bank_Account_Number.
   IBAN_VALUE = 125,
   // No new types can be added without a corresponding change to the Autofill
   // server.
diff --git a/components/autofill/core/browser/form_parsing/form_field.cc b/components/autofill/core/browser/form_parsing/form_field.cc
index 336f3ec4..2b3fd810 100644
--- a/components/autofill/core/browser/form_parsing/form_field.cc
+++ b/components/autofill/core/browser/form_parsing/form_field.cc
@@ -25,6 +25,7 @@
 #include "components/autofill/core/browser/form_parsing/birthdate_field.h"
 #include "components/autofill/core/browser/form_parsing/credit_card_field.h"
 #include "components/autofill/core/browser/form_parsing/email_field.h"
+#include "components/autofill/core/browser/form_parsing/iban_field.h"
 #include "components/autofill/core/browser/form_parsing/merchant_promo_code_field.h"
 #include "components/autofill/core/browser/form_parsing/name_field.h"
 #include "components/autofill/core/browser/form_parsing/phone_field.h"
@@ -184,6 +185,12 @@
                         field_candidates, page_language, pattern_source,
                         log_manager);
   }
+
+  // IBAN pass.
+  if (base::FeatureList::IsEnabled(features::kAutofillParseIBANFields)) {
+    ParseFormFieldsPass(IBANField::Parse, processed_fields, field_candidates,
+                        page_language, pattern_source, log_manager);
+  }
 }
 
 // static
@@ -494,7 +501,7 @@
 
 // static
 bool FormField::IsSingleFieldParseableType(ServerFieldType field_type) {
-  return field_type == MERCHANT_PROMO_CODE;
+  return field_type == MERCHANT_PROMO_CODE || field_type == IBAN_VALUE;
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/form_parsing/form_field.h b/components/autofill/core/browser/form_parsing/form_field.h
index f589368..254478a 100644
--- a/components/autofill/core/browser/form_parsing/form_field.h
+++ b/components/autofill/core/browser/form_parsing/form_field.h
@@ -92,13 +92,14 @@
   // Initial values assigned to FieldCandidates by their corresponding parsers.
   // There's an implicit precedence determined by the values assigned here.
   // Email is currently the most important followed by Phone, Travel, Address,
-  // Birthdate, Credit Card, Price, Name, Merchant promo code, and Search.
+  // Birthdate, Credit Card, IBAN, Price, Name, Merchant promo code, and Search.
   static constexpr float kBaseEmailParserScore = 1.4f;
   static constexpr float kBasePhoneParserScore = 1.3f;
   static constexpr float kBaseTravelParserScore = 1.2f;
   static constexpr float kBaseAddressParserScore = 1.1f;
   static constexpr float kBaseBirthdateParserScore = 1.05f;
   static constexpr float kBaseCreditCardParserScore = 1.0f;
+  static constexpr float kBaseIBANParserScore = 0.975f;
   static constexpr float kBasePriceParserScore = 0.95f;
   static constexpr float kBaseNameParserScore = 0.9f;
   static constexpr float kBaseMerchantPromoCodeParserScore = 0.85f;
diff --git a/components/autofill/core/browser/form_parsing/form_field_unittest.cc b/components/autofill/core/browser/form_parsing/form_field_unittest.cc
index 3c5e8e45..6395a2f 100644
--- a/components/autofill/core/browser/form_parsing/form_field_unittest.cc
+++ b/components/autofill/core/browser/form_parsing/form_field_unittest.cc
@@ -196,7 +196,7 @@
 }
 
 // Test that `ParseSingleFieldForms` parses single field promo codes.
-TEST_P(FormFieldTest, ParseSingleFieldFormsPromoCode) {
+TEST_P(FormFieldTest, ParseFormFieldsForSingleFieldPromoCode) {
   base::test::ScopedFeatureList scoped_feature;
   scoped_feature.InitAndEnableFeature(
       features::kAutofillParseMerchantPromoCodeFields);
@@ -214,6 +214,31 @@
   TestClassificationExpectations();
 }
 
+#if BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE)
+// TODO(crbug.com/1350411): Disabling on linux-chromeos for now as it appears to
+// be having trouble enabling this particular feature correctly.
+#define MAYBE_ParseSingleFieldFormsIban DISABLED_ParseSingleFieldFormsIban
+#else
+#define MAYBE_ParseSingleFieldFormsIban ParseSingleFieldFormsIban
+#endif
+// Test that `ParseSingleFieldForms` parses single field IBAN.
+TEST_P(FormFieldTest, MAYBE_ParseSingleFieldFormsIban) {
+  base::test::ScopedFeatureList scoped_feature;
+  scoped_feature.InitAndEnableFeature(features::kAutofillParseIBANFields);
+
+  // Parse single field IBAN.
+  AddTextFormFieldData("", "IBAN", IBAN_VALUE);
+  EXPECT_EQ(1, ParseSingleFieldForms());
+  TestClassificationExpectations();
+
+  // Don't parse other fields.
+  // UNKNOWN_TYPE is used as the expected type, which prevents it from being
+  // part of the expectations in `TestClassificationExpectations()`.
+  AddTextFormFieldData("", "Address line 1", UNKNOWN_TYPE);
+  EXPECT_EQ(1, ParseSingleFieldForms());
+  TestClassificationExpectations();
+}
+
 struct ParseInAnyOrderTestcase {
   // An nxn matrix, describing that field i is matched by parser j.
   std::vector<std::vector<bool>> field_matches_parser;
diff --git a/components/autofill/core/browser/form_parsing/iban_field.cc b/components/autofill/core/browser/form_parsing/iban_field.cc
new file mode 100644
index 0000000..f65f6a27
--- /dev/null
+++ b/components/autofill/core/browser/form_parsing/iban_field.cc
@@ -0,0 +1,42 @@
+// Copyright 2022 The Chromium 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/autofill/core/browser/form_parsing/iban_field.h"
+
+#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_regex_constants.h"
+#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+
+namespace autofill {
+
+// static
+std::unique_ptr<FormField> IBANField::Parse(AutofillScanner* scanner,
+                                            const LanguageCode& page_language,
+                                            PatternSource pattern_source,
+                                            LogManager* log_manager) {
+  if (!base::FeatureList::IsEnabled(features::kAutofillParseIBANFields))
+    return nullptr;
+
+  AutofillField* field;
+  base::span<const MatchPatternRef> iban_patterns =
+      GetMatchPatterns(IBAN_VALUE, page_language, pattern_source);
+
+  if (ParseFieldSpecifics(scanner, kIBANRe,
+                          kDefaultMatchParamsWith<MatchFieldType::kNumber,
+                                                  MatchFieldType::kTextArea>,
+                          iban_patterns, &field, {log_manager, "kIBANRe"})) {
+    return std::make_unique<IBANField>(field);
+  }
+
+  return nullptr;
+}
+
+IBANField::IBANField(const AutofillField* field) : field_(field) {}
+
+void IBANField::AddClassifications(FieldCandidatesMap* field_candidates) const {
+  AddClassification(field_, IBAN_VALUE, kBaseIBANParserScore, field_candidates);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/form_parsing/iban_field.h b/components/autofill/core/browser/form_parsing/iban_field.h
new file mode 100644
index 0000000..639f4e40
--- /dev/null
+++ b/components/autofill/core/browser/form_parsing/iban_field.h
@@ -0,0 +1,42 @@
+// Copyright 2022 The Chromium 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_AUTOFILL_CORE_BROWSER_FORM_PARSING_IBAN_FIELD_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_IBAN_FIELD_H_
+
+#include <memory>
+
+#include "base/memory/raw_ptr.h"
+#include "components/autofill/core/browser/form_parsing/form_field.h"
+#include "components/autofill/core/common/language_code.h"
+
+namespace autofill {
+
+class AutofillField;
+class AutofillScanner;
+class LogManager;
+
+// A form field that accepts International Bank Account Number (IBAN).
+class IBANField : public FormField {
+ public:
+  static std::unique_ptr<FormField> Parse(AutofillScanner* scanner,
+                                          const LanguageCode& page_language,
+                                          PatternSource pattern_source,
+                                          LogManager* log_manager);
+
+  explicit IBANField(const AutofillField* field);
+
+  IBANField(const IBANField&) = delete;
+  IBANField& operator=(const IBANField&) = delete;
+
+ protected:
+  void AddClassifications(FieldCandidatesMap* field_candidates) const override;
+
+ private:
+  raw_ptr<const AutofillField> field_;
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_PARSING_IBAN_FIELD_H_
diff --git a/components/autofill/core/browser/form_parsing/iban_field_unittest.cc b/components/autofill/core/browser/form_parsing/iban_field_unittest.cc
new file mode 100644
index 0000000..3bf1199
--- /dev/null
+++ b/components/autofill/core/browser/form_parsing/iban_field_unittest.cc
@@ -0,0 +1,90 @@
+// Copyright 2022 The Chromium 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/autofill/core/browser/form_parsing/iban_field.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/browser/form_parsing/parsing_test_utils.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+
+namespace autofill {
+
+class IBANFieldTest
+    : public FormFieldTestBase,
+      public testing::TestWithParam<PatternProviderFeatureState> {
+ public:
+  IBANFieldTest() : FormFieldTestBase(GetParam()) {}
+  IBANFieldTest(const IBANFieldTest&) = delete;
+  IBANFieldTest& operator=(const IBANFieldTest&) = delete;
+
+  void SetUp() override {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kAutofillParseIBANFields);
+  }
+
+ protected:
+  std::unique_ptr<FormField> Parse(
+      AutofillScanner* scanner,
+      const LanguageCode& page_language = LanguageCode("en")) override {
+    return IBANField::Parse(scanner, page_language, GetActivePatternSource(),
+                            /*log_manager=*/nullptr);
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    IBANFieldTest,
+    IBANFieldTest,
+    ::testing::ValuesIn(PatternProviderFeatureState::All()));
+
+#if BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE)
+// TODO(crbug.com/1350411): Disabling on linux-chromeos for now as it appears to
+// be having trouble enabling this particular feature correctly.
+#define MAYBE_ParseIban DISABLED_ParseIban
+#else
+#define MAYBE_ParseIban ParseIban
+#endif
+// Match IBAN
+TEST_P(IBANFieldTest, MAYBE_ParseIban) {
+  AddTextFormFieldData("iban-field", "Enter account number", IBAN_VALUE);
+
+  ClassifyAndVerify(ParseResult::PARSED);
+}
+
+#if BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE)
+// TODO(crbug.com/1350411): Disabling on linux-chromeos for now as it appears to
+// be having trouble enabling this particular feature correctly.
+#define MAYBE_ParseIbanBanks DISABLED_ParseIbanBanks
+#else
+#define MAYBE_ParseIbanBanks ParseIbanBanks
+#endif
+// Match IBAN on banks
+TEST_P(IBANFieldTest, MAYBE_ParseIbanBanks) {
+  AddTextFormFieldData("accountNumber", "IBAN*", IBAN_VALUE);
+
+  ClassifyAndVerify(ParseResult::PARSED);
+}
+
+TEST_P(IBANFieldTest, ParseNonIban) {
+  AddTextFormFieldData("other-field", "Field for Account Number", UNKNOWN_TYPE);
+
+  ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+
+#if BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_CHROMEOS_DEVICE)
+// TODO(crbug.com/1350411): Disabling on linux-chromeos for now as it appears to
+// be having trouble enabling this particular feature correctly.
+#define MAYBE_ParseIbanFlagOff DISABLED_ParseIbanFlagOff
+#else
+#define MAYBE_ParseIbanFlagOff ParseIbanFlagOff
+#endif
+TEST_P(IBANFieldTest, MAYBE_ParseIbanFlagOff) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(features::kAutofillParseIBANFields);
+  AddTextFormFieldData("iban-field", "Enter IBAN here", IBAN_VALUE);
+
+  ClassifyAndVerify(ParseResult::NOT_PARSED);
+}
+}  // namespace autofill
diff --git a/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json b/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
index a4217b5a..d03eae03 100644
--- a/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
+++ b/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
@@ -3315,5 +3315,17 @@
         "match_field_input_types": [0]
       }
     ]
+  },
+    "IBAN_VALUE": {
+    "en": [
+      {
+        "pattern_identifier": "en_iban_preserving",
+        "positive_pattern": "(\\biban(\\b|_)|international bank account number)",
+        "positive_score": 0.975,
+        "negative_pattern": null,
+        "match_field_attributes": [0, 1],
+        "match_field_input_types": [0]
+      }
+    ]
   }
 }
diff --git a/components/autofill/core/browser/validation.cc b/components/autofill/core/browser/validation.cc
index 2e9eae6..d81a9b46 100644
--- a/components/autofill/core/browser/validation.cc
+++ b/components/autofill/core/browser/validation.cc
@@ -350,7 +350,7 @@
 bool IsInternationalBankAccountNumber(const std::u16string& value) {
   std::u16string no_spaces;
   base::RemoveChars(value, u" ", &no_spaces);
-  return MatchesRegex<kInternationalBankAccountNumberRe>(no_spaces);
+  return MatchesRegex<kInternationalBankAccountNumberValueRe>(no_spaces);
 }
 
 bool IsPlausibleCreditCardCVCNumber(const std::u16string& value) {
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java
index 294653c..c063f9be 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java
@@ -14,6 +14,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.Bundle;
 import android.provider.Settings;
@@ -39,6 +40,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.UsedByReflection;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
@@ -97,6 +99,13 @@
      */
     public static final String EXTRA_SELECTED_DOMAINS = "selected_domains";
 
+    /**
+     * {@link SharedPreferences} key that indicates whether the desktop site global setting was
+     * enabled by the user.
+     */
+    public static final String USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY =
+            "Chrome.RequestDesktopSiteGlobalSetting.UserEnabled";
+
     // The list that contains preferences.
     private RecyclerView mListView;
     // The item for searching the list of items.
@@ -487,6 +496,12 @@
                 } else if (type == SiteSettingsCategory.Type.REQUEST_DESKTOP_SITE) {
                     recordSiteLayoutChanged((boolean) newValue);
                     updateDesktopSiteSecondaryControls();
+                    // TODO(crbug.com/1069897): Use SharedPreferencesManager if it is componentized.
+                    ContextUtils.getAppSharedPreferences()
+                            .edit()
+                            .putBoolean(USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY,
+                                    (boolean) newValue)
+                            .apply();
                 }
                 break;
             }
diff --git a/components/offline_items_collection/core/offline_content_aggregator.cc b/components/offline_items_collection/core/offline_content_aggregator.cc
index 21aba2b..6b2ce6b 100644
--- a/components/offline_items_collection/core/offline_content_aggregator.cc
+++ b/components/offline_items_collection/core/offline_content_aggregator.cc
@@ -244,7 +244,8 @@
   if (!pending_providers_.empty()) {
     auto item = std::find_if(aggregated_items_.begin(), aggregated_items_.end(),
                              [id](const OfflineItem& p) { return p.id == id; });
-    aggregated_items_.erase(item);
+    if (item != aggregated_items_.end())
+      aggregated_items_.erase(item);
   }
   NotifyItemRemoved(id);
 }
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 2a3a4288..a9d5690 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -474,6 +474,7 @@
       return omnibox::kCalculatorIcon;
 
     case Type::SEARCH_SUGGEST_TAIL:
+    case Type::NULL_RESULT_MESSAGE:
       return omnibox::kBlankIcon;
 
     case Type::DOCUMENT_SUGGESTION:
@@ -1213,6 +1214,8 @@
     case AutocompleteMatchType::PHYSICAL_WEB_OVERFLOW_DEPRECATED:
     case AutocompleteMatchType::TAB_SEARCH_DEPRECATED:
     case AutocompleteMatchType::PEDAL_DEPRECATED:
+    // NULL_RESULT_MESSAGE suggestions cannot be acted upon, so no need to log.
+    case AutocompleteMatchType::NULL_RESULT_MESSAGE:
     case AutocompleteMatchType::NUM_TYPES:
       break;
   }
diff --git a/components/omnibox/browser/autocomplete_match_type.cc b/components/omnibox/browser/autocomplete_match_type.cc
index d9b0d63e..dd2e47be 100644
--- a/components/omnibox/browser/autocomplete_match_type.cc
+++ b/components/omnibox/browser/autocomplete_match_type.cc
@@ -51,6 +51,7 @@
     "navsuggest-tiles",
     "open-tab",
     "history-cluster",
+    "null-result-message",
   };
   // clang-format on
   static_assert(std::size(strings) == AutocompleteMatchType::NUM_TYPES,
@@ -141,6 +142,7 @@
       0,                                     // TILE_NAVSUGGEST
       0,                                     // OPEN_TAB
       0,                                     // HISTORY_CLUSTER
+      0,                                     // NULL_RESULT_MESSAGE
   };
   static_assert(std::size(message_ids) == AutocompleteMatchType::NUM_TYPES,
                 "message_ids must have NUM_TYPES elements");
diff --git a/components/omnibox/browser/autocomplete_match_type.h b/components/omnibox/browser/autocomplete_match_type.h
index e44cd75..3c1cbe7 100644
--- a/components/omnibox/browser/autocomplete_match_type.h
+++ b/components/omnibox/browser/autocomplete_match_type.h
@@ -77,6 +77,9 @@
     OPEN_TAB                    = 30,  // A URL match amongst the currently open
                                        // tabs.
     HISTORY_CLUSTER             = 31,  // A history cluster suggestion.
+    NULL_RESULT_MESSAGE         = 32,  // A suggestion whose purpose is only to
+                                       // deliver a message. This suggestion
+                                       // cannot be opened or acted upon.
     NUM_TYPES,
   };
   // clang-format on
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index ca8c455..e5fed181 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -62,7 +62,6 @@
 #include "third_party/metrics_proto/omnibox_event.pb.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/window_open_disposition.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/image/image.h"
 #include "url/url_util.h"
@@ -804,24 +803,21 @@
                                  const std::u16string& pasted_text,
                                  size_t index,
                                  base::TimeTicks match_selection_timestamp) {
-  TemplateURLService* service = client_->GetTemplateURLService();
-  bool is_tab_search_mode =
+  // NULL_RESULT_MESSAGE matches are informational only and cannot be acted
+  // upon. Immediately return when attempting to open one.
+  if (match.type == AutocompleteMatchType::NULL_RESULT_MESSAGE) {
+    return;
+  }
+
+  // Switch the window disposition to SWITCH_TO_TAB for open tab matches that
+  // originated while in keyword mode.  This is to support the keyword mode
+  // starter pack's tab search (@tabs) feature, which should open all
+  // suggestions in the existing open tab.
+  bool is_open_tab_match =
       OmniboxFieldTrial::IsSiteSearchStarterPackEnabled() &&
       match.from_keyword &&
-      service->IsKeywordFromStarterPackTabSearch(keyword_);
-  if (is_tab_search_mode) {
-    // The starter pack's tab search feature uses the omnibox's OpenTabProvider
-    // to search through a user's open tabs and does not have a proper landing
-    // page for substituting URL searches. To support this, only allow the user
-    // to open matches from the OpenTabProvider, effectively disabling the 
-    // search-other-engine suggestion that is usually the default suggestion in
-    // keyword mode.
-    if (match.provider->type() != AutocompleteProvider::TYPE_OPEN_TAB) {
-      return;
-    }
-
-    // All suggestions in tab search mode that ARE from the open tab provider
-    // should open in the existing open tab (switch to open tab).
+      match.provider->type() == AutocompleteProvider::TYPE_OPEN_TAB;
+  if (is_open_tab_match) {
     disposition = WindowOpenDisposition::SWITCH_TO_TAB;
   }
 
@@ -930,6 +926,7 @@
                                now - last_omnibox_focus_);
   }
 
+  TemplateURLService* service = client_->GetTemplateURLService();
   TemplateURL* template_url = match.GetTemplateURL(service, false);
   if (template_url) {
     if (ui::PageTransitionTypeIncludingQualifiersIs(
diff --git a/components/omnibox/browser/omnibox_edit_model_unittest.cc b/components/omnibox/browser/omnibox_edit_model_unittest.cc
index c766452..320f6524 100644
--- a/components/omnibox/browser/omnibox_edit_model_unittest.cc
+++ b/components/omnibox/browser/omnibox_edit_model_unittest.cc
@@ -31,7 +31,6 @@
 #include "components/omnibox/browser/test_scheme_classifier.h"
 #include "components/omnibox/common/omnibox_features.h"
 #include "components/prefs/testing_pref_service.h"
-#include "components/search_engines/template_url_starter_pack_data.h"
 #include "components/url_formatter/url_fixer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
@@ -1205,27 +1204,16 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(omnibox::kSiteSearchStarterPack);
 
-  // Populate template URL with starter pack entries
-  std::vector<std::unique_ptr<TemplateURLData>> turls =
-      TemplateURLStarterPackData::GetStarterPackEngines();
-  for (auto& turl : turls) {
-    model()->client()->GetTemplateURLService()->Add(
-        std::make_unique<TemplateURL>(std::move(*turl)));
-  }
-
-  // When the match comes from the Open Tab Provider while in tabs search
-  // keyword mode, the disposition should be set to SWITCH_TO_TAB.
+  // When the match comes from the Open Tab Provider while in keyword mode,
+  // the disposition should be set to SWITCH_TO_TAB.
   AutocompleteMatch match(
       model()->autocomplete_controller()->open_tab_provider(), 0, false,
       AutocompleteMatchType::OPEN_TAB);
   match.destination_url = GURL("https://foo/");
   match.from_keyword = true;
 
-  // Set the keyword to "@tabs" to put us in tab search mode.
-  model()->OnPopupDataChanged(std::u16string(), false, std::u16string(),
-                              std::u16string(), /* keyword = */ u"@tabs", false,
-                              std::u16string());
-
+  model()->OnSetFocus(false);  // Avoids DCHECK in OpenMatch().
+  model()->SetUserText(u"http://abcd");
   model()->OpenMatch(match, WindowOpenDisposition::CURRENT_TAB, GURL(),
                      std::u16string(), 0);
   EXPECT_EQ(controller_->disposition(), WindowOpenDisposition::SWITCH_TO_TAB);
@@ -1242,15 +1230,5 @@
   model()->OpenMatch(match, WindowOpenDisposition::CURRENT_TAB, GURL(),
                      std::u16string(), 0);
   EXPECT_EQ(controller_->disposition(), WindowOpenDisposition::CURRENT_TAB);
-
-  // Suggestions in keyword mode but NOT in tab search should NOT change the
-  // disposition.
-  model()->OnPopupDataChanged(std::u16string(), false, std::u16string(),
-                              std::u16string(), /* keyword = */ u"@history",
-                              false, std::u16string());
-  match.provider = model()->autocomplete_controller()->open_tab_provider();
-  model()->OpenMatch(match, WindowOpenDisposition::CURRENT_TAB, GURL(),
-                     std::u16string(), 0);
-  EXPECT_EQ(controller_->disposition(), WindowOpenDisposition::CURRENT_TAB);
 }
 #endif  // !(BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID))
diff --git a/components/omnibox/browser/open_tab_provider.cc b/components/omnibox/browser/open_tab_provider.cc
index 9b31ae9..d8c450b 100644
--- a/components/omnibox/browser/open_tab_provider.cc
+++ b/components/omnibox/browser/open_tab_provider.cc
@@ -8,14 +8,18 @@
 #include "base/ranges/algorithm.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/omnibox/browser/autocomplete_input.h"
+#include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_match_classification.h"
 #include "components/omnibox/browser/in_memory_url_index_types.h"
 #include "components/omnibox/browser/keyword_provider.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/scoring_functor.h"
 #include "components/omnibox/browser/tab_matcher.h"
 #include "components/query_parser/query_parser.h"
 #include "components/search_engines/template_url.h"
+#include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/url_formatter.h"
+#include "ui/base/l10n/l10n_util.h"
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 #include "content/public/browser/web_contents.h"
@@ -108,6 +112,15 @@
           adjusted_input, web_contents->GetTitle(), url, score, template_url));
     }
   }
+
+  // If there were no open tab results found, and we're in keyword mode,
+  // generate a NULL_RESULT_MESSAGE suggestion to keep the user in keyword mode
+  // and display a no results message.
+  if (OmniboxFieldTrial::IsSiteSearchStarterPackEnabled() &&
+      InKeywordMode(adjusted_input) && matches_.empty()) {
+    matches_.push_back(
+        CreateNullResultMessageMatch(adjusted_input, template_url));
+  }
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 }
 
@@ -164,3 +177,32 @@
 
   return match;
 }
+
+AutocompleteMatch OpenTabProvider::CreateNullResultMessageMatch(
+    const AutocompleteInput& input,
+    const TemplateURL* template_url) {
+  DCHECK(template_url);
+
+  // This value doesn't really matter as this suggestion is only displayed when
+  // no other suggestions were found. Use an arbitrary constant.
+  constexpr int kRelevanceScore = 1000;
+  AutocompleteMatch match(this, kRelevanceScore, /*deletable=*/false,
+                          AutocompleteMatchType::NULL_RESULT_MESSAGE);
+
+  // These fields are filled in to enable the Keyword UI when only this
+  // suggestion is available.
+  match.fill_into_edit = input.text();
+  match.allowed_to_be_default_match = true;
+  match.keyword = template_url->keyword();
+  match.transition = ui::PAGE_TRANSITION_KEYWORD;
+
+  // Use this suggestion's contents field to display a message to the user that
+  // there were no matching results found.
+  match.contents =
+      l10n_util::GetStringUTF16(IDS_OMNIBOX_TAB_SEARCH_NO_RESULTS_FOUND);
+  match.contents_class.push_back(
+      ACMatchClassification(0, ACMatchClassification::NONE));
+  match.from_keyword = true;
+
+  return match;
+}
diff --git a/components/omnibox/browser/open_tab_provider.h b/components/omnibox/browser/open_tab_provider.h
index c53c4c7..0f12f93 100644
--- a/components/omnibox/browser/open_tab_provider.h
+++ b/components/omnibox/browser/open_tab_provider.h
@@ -32,6 +32,14 @@
                                        int score,
                                        const TemplateURL* template_url);
 
+  // This is called when no other matches were found and generates a
+  // NULL_RESULT_MESSAGE match. This match is intended only to display a message
+  // to the user and keep the keyword mode UI.  No action can be taken by
+  // opening this match.
+  AutocompleteMatch CreateNullResultMessageMatch(
+      const AutocompleteInput& input,
+      const TemplateURL* template_url);
+
   raw_ptr<AutocompleteProviderClient> client_;
 };
 
diff --git a/components/omnibox/browser/search_provider.cc b/components/omnibox/browser/search_provider.cc
index b38c1f8..d4d255c 100644
--- a/components/omnibox/browser/search_provider.cc
+++ b/components/omnibox/browser/search_provider.cc
@@ -1114,8 +1114,13 @@
     // Note: in this provider, SEARCH_OTHER_ENGINE must correspond
     // to the keyword verbatim search query.  Do not create other matches
     // of type SEARCH_OTHER_ENGINE.
+    //
+    // In tabs search keyword mode, navigation (switch to open tab) suggestions
+    // are provided, but there's no search results landing page to navigate to,
+    // so it's not possible to open a verbatim search match. Do not provide one.
     if (keyword_url &&
-        (keyword_url->type() != TemplateURL::OMNIBOX_API_EXTENSION)) {
+        (keyword_url->type() != TemplateURL::OMNIBOX_API_EXTENSION) &&
+        (keyword_url->starter_pack_id() != TemplateURLStarterPackData::kTabs)) {
       bool keyword_relevance_from_server;
       const int keyword_verbatim_relevance =
           GetKeywordVerbatimRelevance(&keyword_relevance_from_server);
diff --git a/components/omnibox_strings.grdp b/components/omnibox_strings.grdp
index 6129b5d..2d14629 100644
--- a/components/omnibox_strings.grdp
+++ b/components/omnibox_strings.grdp
@@ -312,4 +312,9 @@
   <message name="IDS_SEARCH_ENGINES_STARTER_PACK_TABS_KEYWORD" desc = "The keyword required to trigger tab search in keyword mode. This will be prepended with an '@'.">
     Tabs
   </message>
+
+  <!-- No results description for the Starter Pack's Tab search feature (@tabs). This appears as the first suggestion when no matching tabs are found. -->
+  <message name="IDS_OMNIBOX_TAB_SEARCH_NO_RESULTS_FOUND" desc = "The string displayed as the first row in the Omnibox when no results are found in Tab Search mode.">
+    No results found
+  </message>
 </grit-part>
diff --git a/components/omnibox_strings_grdp/IDS_OMNIBOX_TAB_SEARCH_NO_RESULTS_FOUND.png.sha1 b/components/omnibox_strings_grdp/IDS_OMNIBOX_TAB_SEARCH_NO_RESULTS_FOUND.png.sha1
new file mode 100644
index 0000000..4f2cb3a1
--- /dev/null
+++ b/components/omnibox_strings_grdp/IDS_OMNIBOX_TAB_SEARCH_NO_RESULTS_FOUND.png.sha1
@@ -0,0 +1 @@
+4ce6b2cf4b41d8fea7f0e28c0e1119eff2469c98
\ No newline at end of file
diff --git a/components/page_load_metrics/browser/BUILD.gn b/components/page_load_metrics/browser/BUILD.gn
index e4817680..bbefe5f 100644
--- a/components/page_load_metrics/browser/BUILD.gn
+++ b/components/page_load_metrics/browser/BUILD.gn
@@ -14,6 +14,8 @@
     "metrics_navigation_throttle.h",
     "metrics_web_contents_observer.cc",
     "metrics_web_contents_observer.h",
+    "observers/assert_page_load_metrics_observer.cc",
+    "observers/assert_page_load_metrics_observer.h",
     "observers/back_forward_cache_page_load_metrics_observer.cc",
     "observers/back_forward_cache_page_load_metrics_observer.h",
     "observers/click_input_tracker.cc",
diff --git a/components/page_load_metrics/browser/observers/assert_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/assert_page_load_metrics_observer.cc
new file mode 100644
index 0000000..4e3b783d
--- /dev/null
+++ b/components/page_load_metrics/browser/observers/assert_page_load_metrics_observer.cc
@@ -0,0 +1,347 @@
+// Copyright 2022 The Chromium 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/page_load_metrics/browser/observers/assert_page_load_metrics_observer.h"
+
+#include "components/page_load_metrics/browser/page_load_metrics_observer_delegate.h"
+#include "components/page_load_metrics/browser/page_load_metrics_util.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/page.h"
+
+using page_load_metrics::PageLoadMetricsObserver;
+using page_load_metrics::PrerenderingState;
+
+AssertPageLoadMetricsObserver::AssertPageLoadMetricsObserver() = default;
+
+AssertPageLoadMetricsObserver::~AssertPageLoadMetricsObserver() {
+  // Restrict the check because this class can't detect
+  // PageLoadTracker::StopTracking case.
+  if (!committed_) {
+    return;
+  }
+
+  DCHECK(destructing_);
+}
+
+const char* AssertPageLoadMetricsObserver::GetObserverName() const {
+  return "AssertPageLoadMetricsObserver";
+}
+
+PageLoadMetricsObserver::ObservePolicy AssertPageLoadMetricsObserver::OnStart(
+    content::NavigationHandle* navigation_handle,
+    const GURL& currently_committed_url,
+    bool started_in_foreground) {
+  DCHECK(!started_);
+  started_ = true;
+
+  return CONTINUE_OBSERVING;
+}
+
+PageLoadMetricsObserver::ObservePolicy
+AssertPageLoadMetricsObserver::OnFencedFramesStart(
+    content::NavigationHandle* navigation_handle,
+    const GURL& currently_committed_url) {
+  DCHECK(!started_);
+  started_ = true;
+
+  // This class uses observer-level forwarding.
+  return FORWARD_OBSERVING;
+}
+
+PageLoadMetricsObserver::ObservePolicy
+AssertPageLoadMetricsObserver::OnPrerenderStart(
+    content::NavigationHandle* navigation_handle,
+    const GURL& currently_committed_url) {
+  DCHECK(!started_);
+  started_ = true;
+
+  return CONTINUE_OBSERVING;
+}
+
+PageLoadMetricsObserver::ObservePolicy
+AssertPageLoadMetricsObserver::OnRedirect(
+    content::NavigationHandle* navigation_handle) {
+  DCHECK(started_);
+  DCHECK(!committed_);
+
+  return CONTINUE_OBSERVING;
+}
+
+PageLoadMetricsObserver::ObservePolicy AssertPageLoadMetricsObserver::OnCommit(
+    content::NavigationHandle* navigation_handle) {
+  DCHECK(started_);
+  DCHECK(!committed_);
+  DCHECK(!activated_);
+  committed_ = true;
+
+  return CONTINUE_OBSERVING;
+}
+
+void AssertPageLoadMetricsObserver::DidActivatePrerenderedPage(
+    content::NavigationHandle* navigation_handle) {
+  DCHECK(started_);
+  DCHECK(committed_);
+  DCHECK(!activated_);
+  activated_ = true;
+}
+
+void AssertPageLoadMetricsObserver::OnFailedProvisionalLoad(
+    const page_load_metrics::FailedProvisionalLoadInfo&
+        failed_provisional_load_info) {
+  DCHECK(started_);
+  DCHECK(!committed_);
+  DCHECK(!activated_);
+  DCHECK(!backforwardcache_entered_);
+  DCHECK(!destructing_);
+  destructing_ = true;
+}
+
+void AssertPageLoadMetricsObserver::OnComplete(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  // Note that the default implementation of
+  // PageLoadMetricsObserver::OnEnterBackForwardCache calls OnComplete and
+  // returns STOP_OBSERVING.
+
+  DCHECK(committed_);
+  DCHECK(!destructing_);
+
+  if (!backforwardcache_entering_) {
+    destructing_ = true;
+  }
+}
+
+PageLoadMetricsObserver::ObservePolicy
+AssertPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  // This is called even for provisional loads.
+  DCHECK(started_);
+
+  return CONTINUE_OBSERVING;
+}
+
+PageLoadMetricsObserver::ObservePolicy
+AssertPageLoadMetricsObserver::ShouldObserveMimeType(
+    const std::string& mime_type) const {
+  // Sets a flag for destructor's assertion.
+
+  ObservePolicy policy =
+      PageLoadMetricsObserver::ShouldObserveMimeType(mime_type);
+
+  if (policy == STOP_OBSERVING) {
+    destructing_ = true;
+  }
+
+  return policy;
+}
+
+PageLoadMetricsObserver::ObservePolicy
+AssertPageLoadMetricsObserver::OnEnterBackForwardCache(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(committed_);
+
+  // If ovserver doesn't override OnEnterBackForwardCache, the observer will be
+  // stopped with OnComplete called.
+  backforwardcache_entering_ = true;
+  PageLoadMetricsObserver::ObservePolicy policy =
+      PageLoadMetricsObserver::OnEnterBackForwardCache(timing);
+  backforwardcache_entering_ = false;
+  DCHECK_EQ(policy, STOP_OBSERVING);
+
+  backforwardcache_entered_ = true;
+
+  return CONTINUE_OBSERVING;
+}
+
+void AssertPageLoadMetricsObserver::ReadyToCommitNextNavigation(
+    content::NavigationHandle* navigation_handle) {
+  DCHECK(committed_);
+}
+
+void AssertPageLoadMetricsObserver::OnCommitSameDocumentNavigation(
+    content::NavigationHandle* navigation_handle) {
+  DCHECK(committed_);
+  // TODO(kenoss): I can't explain why this doesn't hold now. Write description.
+  // if (IsPrerendered()) {
+  //   (DCHECK(activated_));
+  // }
+}
+
+void AssertPageLoadMetricsObserver::OnDidInternalNavigationAbort(
+    content::NavigationHandle* navigation_handle) {
+  DCHECK(started_);
+}
+
+void AssertPageLoadMetricsObserver::OnDidFinishSubFrameNavigation(
+    content::NavigationHandle* navigation_handle) {
+  // Subframe navigations are triggered after the main frame is committed.
+  DCHECK(committed_);
+}
+
+PageLoadMetricsObserver::ObservePolicy
+AssertPageLoadMetricsObserver::OnShown() {
+  DCHECK(started_);
+  // If prerendered, this is called even for provisional loads.
+  // After https://crrev.com/c/3767770, we can assume that `activated_`.
+  // TODO(kenoss): Add DCHECK.
+
+  return CONTINUE_OBSERVING;
+}
+
+PageLoadMetricsObserver::ObservePolicy AssertPageLoadMetricsObserver::OnHidden(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(started_);
+  // If prerendered, this is called even for provisional loads.
+  // After https://crrev.com/c/3767770, we can assume that `activated_`.
+  // TODO(kenoss): Add DCHECK.
+
+  return CONTINUE_OBSERVING;
+}
+
+void AssertPageLoadMetricsObserver::OnTimingUpdate(
+    content::RenderFrameHost* subframe_rfh,
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(started_);
+}
+
+void AssertPageLoadMetricsObserver::OnParseStart(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(started_);
+  DCHECK(timing.parse_timing->parse_start.has_value());
+}
+
+void AssertPageLoadMetricsObserver::OnParseStop(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(started_);
+  DCHECK(timing.parse_timing->parse_stop.has_value());
+}
+
+void AssertPageLoadMetricsObserver::OnDomContentLoadedEventStart(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(started_);
+  DCHECK(timing.document_timing->dom_content_loaded_event_start.has_value());
+}
+
+void AssertPageLoadMetricsObserver::OnLoadEventStart(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(started_);
+  DCHECK(timing.document_timing->load_event_start.has_value());
+}
+
+void AssertPageLoadMetricsObserver::OnFirstPaintInPage(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(committed_);
+  if (IsPrerendered()) {
+    DCHECK(activated_);
+  }
+  DCHECK(timing.paint_timing->first_paint.has_value());
+}
+
+void AssertPageLoadMetricsObserver::OnFirstImagePaintInPage(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(committed_);
+  if (IsPrerendered()) {
+    DCHECK(activated_);
+  }
+  DCHECK(timing.paint_timing->first_image_paint.has_value());
+}
+
+void AssertPageLoadMetricsObserver::OnFirstContentfulPaintInPage(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(committed_);
+  if (IsPrerendered()) {
+    DCHECK(activated_);
+  }
+  DCHECK(timing.paint_timing->first_contentful_paint.has_value());
+}
+
+void AssertPageLoadMetricsObserver::OnFirstMeaningfulPaintInMainFrameDocument(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(committed_);
+  if (IsPrerendered()) {
+    DCHECK(activated_);
+  }
+  DCHECK(timing.paint_timing->first_meaningful_paint.has_value());
+}
+
+void AssertPageLoadMetricsObserver::OnFirstInputInPage(
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(committed_);
+  if (IsPrerendered()) {
+    DCHECK(activated_);
+  }
+  DCHECK(timing.interactive_timing->first_input_delay.has_value());
+}
+
+void AssertPageLoadMetricsObserver::
+    OnFirstPaintAfterBackForwardCacheRestoreInPage(
+        const page_load_metrics::mojom::BackForwardCacheTiming& timing,
+        size_t index) {
+  DCHECK(backforwardcache_entered_);
+  DCHECK(!timing.first_paint_after_back_forward_cache_restore.is_zero());
+}
+
+void AssertPageLoadMetricsObserver::
+    OnFirstInputAfterBackForwardCacheRestoreInPage(
+        const page_load_metrics::mojom::BackForwardCacheTiming& timing,
+        size_t index) {
+  DCHECK(backforwardcache_entered_);
+  DCHECK(timing.first_input_delay_after_back_forward_cache_restore.has_value());
+}
+
+void AssertPageLoadMetricsObserver::
+    OnRequestAnimationFramesAfterBackForwardCacheRestoreInPage(
+        const page_load_metrics::mojom::BackForwardCacheTiming& timing,
+        size_t index) {
+  DCHECK(backforwardcache_entered_);
+  DCHECK_EQ(
+      timing.request_animation_frames_after_back_forward_cache_restore.size(),
+      3u);
+}
+
+void AssertPageLoadMetricsObserver::OnUserInput(
+    const blink::WebInputEvent& event,
+    const page_load_metrics::mojom::PageLoadTiming& timing) {
+  DCHECK(committed_);
+  // If prerendered, input events are triggered after activation.
+  if (IsPrerendered()) {
+    DCHECK(activated_);
+  }
+}
+
+void AssertPageLoadMetricsObserver::OnPageInputTimingUpdate(
+    uint64_t num_input_events) {
+  DCHECK(committed_);
+  // If prerendered, input events are triggered after activation.
+  if (IsPrerendered()) {
+    DCHECK(activated_);
+  }
+}
+
+void AssertPageLoadMetricsObserver::OnInputTimingUpdate(
+    content::RenderFrameHost* subframe_rfh,
+    const page_load_metrics::mojom::InputTiming& input_timing_delta) {
+  // This callback is triggered even if there's no input, even before
+  // activation.
+  DCHECK(committed_);
+}
+
+void AssertPageLoadMetricsObserver::OnRenderFrameDeleted(
+    content::RenderFrameHost* render_frame_host) {
+  DCHECK(started_);
+}
+
+void AssertPageLoadMetricsObserver::OnSubFrameDeleted(int frame_tree_node_id) {
+  DCHECK(started_);
+}
+
+void AssertPageLoadMetricsObserver::OnSubFrameRenderDataUpdate(
+    content::RenderFrameHost* subframe_rfh,
+    const page_load_metrics::mojom::FrameRenderDataUpdate& render_data) {
+  DCHECK(committed_);
+}
+
+bool AssertPageLoadMetricsObserver::IsPrerendered() const {
+  return (GetDelegate().GetPrerenderingState() !=
+          PrerenderingState::kNoPrerendering);
+}
diff --git a/components/page_load_metrics/browser/observers/assert_page_load_metrics_observer.h b/components/page_load_metrics/browser/observers/assert_page_load_metrics_observer.h
new file mode 100644
index 0000000..f253f64
--- /dev/null
+++ b/components/page_load_metrics/browser/observers/assert_page_load_metrics_observer.h
@@ -0,0 +1,143 @@
+// Copyright 2022 The Chromium 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_PAGE_LOAD_METRICS_BROWSER_OBSERVERS_ASSERT_PAGE_LOAD_METRICS_OBSERVER_H_
+#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_OBSERVERS_ASSERT_PAGE_LOAD_METRICS_OBSERVER_H_
+
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+
+// Asserts the constraints of methods of PageLoadMetricsObserver using
+// ovserver-level forwarding (i.e. PageLoadMetricsForwardObserver) as code and
+// checks the behavior in browsertests of PageLoadMetricsObservers.
+//
+// This class will be added iff `DCHECK_IS_ON()`.
+//
+// The list of methods are not complete. For most ones among missing ones, we
+// have no (non trivial) assumption on callback timings.
+class AssertPageLoadMetricsObserver final
+    : public page_load_metrics::PageLoadMetricsObserver {
+ public:
+  AssertPageLoadMetricsObserver();
+  ~AssertPageLoadMetricsObserver() override;
+
+  // PageLoadMetricsObserverInterface implementation:
+  const char* GetObserverName() const override;
+
+  // Initialization and redirect
+  ObservePolicy OnStart(content::NavigationHandle* navigation_handle,
+                        const GURL& currently_committed_url,
+                        bool started_in_foreground) override;
+  ObservePolicy OnFencedFramesStart(
+      content::NavigationHandle* navigation_handle,
+      const GURL& currently_committed_url) override;
+  ObservePolicy OnPrerenderStart(content::NavigationHandle* navigation_handle,
+                                 const GURL& currently_committed_url) override;
+  ObservePolicy OnRedirect(
+      content::NavigationHandle* navigation_handle) override;
+
+  // Commit and activation
+  ObservePolicy OnCommit(content::NavigationHandle* navigation_handle) override;
+  void DidActivatePrerenderedPage(
+      content::NavigationHandle* navigation_handle) override;
+
+  // Termination-like events
+  void OnFailedProvisionalLoad(
+      const page_load_metrics::FailedProvisionalLoadInfo&
+          failed_provisional_load_info) override;
+  void OnComplete(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  ObservePolicy FlushMetricsOnAppEnterBackground(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  ObservePolicy OnEnterBackForwardCache(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+
+  // Override to inspect
+  ObservePolicy ShouldObserveMimeType(
+      const std::string& mime_type) const override;
+
+  // Events for navigations that are not related to PageLoadMetricsObserver's
+  // lifetime
+  void OnDidInternalNavigationAbort(
+      content::NavigationHandle* navigation_handle) override;
+  void ReadyToCommitNextNavigation(
+      content::NavigationHandle* navigation_handle) override;
+  void OnDidFinishSubFrameNavigation(
+      content::NavigationHandle* navigation_handle) override;
+  void OnCommitSameDocumentNavigation(
+      content::NavigationHandle* navigation_handle) override;
+
+  // Visibility changes
+  ObservePolicy OnHidden(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  ObservePolicy OnShown() override;
+
+  // Timing updates
+  //
+  // For more detailed event order, see page_load_metrics_update_dispatcher.cc.
+  void OnTimingUpdate(
+      content::RenderFrameHost* subframe_rfh,
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnParseStart(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnParseStop(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnDomContentLoadedEventStart(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnLoadEventStart(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnFirstPaintInPage(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnFirstImagePaintInPage(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnFirstContentfulPaintInPage(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnFirstPaintAfterBackForwardCacheRestoreInPage(
+      const page_load_metrics::mojom::BackForwardCacheTiming& timing,
+      size_t index) override;
+  void OnFirstInputAfterBackForwardCacheRestoreInPage(
+      const page_load_metrics::mojom::BackForwardCacheTiming& timing,
+      size_t index) override;
+  void OnRequestAnimationFramesAfterBackForwardCacheRestoreInPage(
+      const page_load_metrics::mojom::BackForwardCacheTiming& timing,
+      size_t index) override;
+  void OnFirstMeaningfulPaintInMainFrameDocument(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnFirstInputInPage(
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+
+  // Input events and input timing events
+  void OnUserInput(
+      const blink::WebInputEvent& event,
+      const page_load_metrics::mojom::PageLoadTiming& timing) override;
+  void OnPageInputTimingUpdate(uint64_t num_input_events) override;
+  void OnInputTimingUpdate(
+      content::RenderFrameHost* subframe_rfh,
+      const page_load_metrics::mojom::InputTiming& input_timing_delta) override;
+
+  // Subframe events
+  void OnSubFrameRenderDataUpdate(
+      content::RenderFrameHost* subframe_rfh,
+      const page_load_metrics::mojom::FrameRenderDataUpdate& render_data)
+      override;
+
+  // RenderFrameHost and FrameTreeNode deletion
+  void OnRenderFrameDeleted(
+      content::RenderFrameHost* render_frame_host) override;
+  void OnSubFrameDeleted(int frame_tree_node_id) override;
+
+ private:
+  bool IsPrerendered() const;
+
+  bool started_ = false;
+  // Same to `GetDelegate().DidCommit()`
+  bool committed_ = false;
+  // Same to `GetDelegate().GetPrerenderingData()` is one of
+  // `kActivatedNoActivationStart` and `kActivated`.
+  bool activated_ = false;
+  mutable bool destructing_ = false;
+  bool backforwardcache_entering_ = false;
+  bool backforwardcache_entered_ = false;
+};
+
+#endif  // COMPONENTS_PAGE_LOAD_METRICS_BROWSER_OBSERVERS_ASSERT_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer_interface.h b/components/page_load_metrics/browser/page_load_metrics_observer_interface.h
index 99de0fd1..85f49e16 100644
--- a/components/page_load_metrics/browser/page_load_metrics_observer_interface.h
+++ b/components/page_load_metrics/browser/page_load_metrics_observer_interface.h
@@ -455,24 +455,23 @@
   virtual ObservePolicy FlushMetricsOnAppEnterBackground(
       const mojom::PageLoadTiming& timing) = 0;
 
-  // One of OnComplete or OnFailedProvisionalLoad is invoked for tracked page
-  // loads, immediately before the observer is deleted. These callbacks will not
-  // be invoked for page loads that did not meet the criteria for being tracked
-  // at the time the navigation completed. The PageLoadTiming struct contains
-  // timing data. Other useful data collected over the course of the page load
-  // is exposed by the observer delegate API. Most observers should not need
-  // to implement these callbacks, and should implement the On* timing callbacks
-  // instead.
-
-  // OnComplete is invoked for tracked page loads that committed, immediately
-  // before the observer is deleted. Observers that implement OnComplete may
-  // also want to implement FlushMetricsOnAppEnterBackground, to avoid loss of
-  // data if the application is killed while in the background (this happens
-  // frequently on Android).
+  // A destructor of observer is invoked in the following mutually exclusive
+  // paths:
+  //
+  // - (If an ovserver doesn't override OnEnterBackForwardCache) When
+  //   OnEnterBackForwardCache is invoked, it calls OnComplete and returns
+  //   STOP_OBSERVING, then the ovserver is pruned.
+  // - When some callback returned STOP_OBSERVING, the observer is pruned with
+  //   no more callback.
+  // - When PageLoadTracker destructed, OnComplete is invoked just before
+  //   destruction if the load is committed.
+  // - When PageLoadTracker destructed, OnFailedProvisionalLoad is invoked just
+  //   before destruction if the load is not committed.
+  //
+  // Observers that implement OnComplete may also want to implement
+  // FlushMetricsOnAppEnterBackground, to avoid loss of data if the application
+  // is killed while in the background (this happens frequently on Android).
   virtual void OnComplete(const mojom::PageLoadTiming& timing) = 0;
-
-  // OnFailedProvisionalLoad is invoked for tracked page loads that did not
-  // commit, immediately before the observer is deleted.
   virtual void OnFailedProvisionalLoad(
       const FailedProvisionalLoadInfo& failed_provisional_load_info) = 0;
 
diff --git a/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc b/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
index 818a462..e58002e 100644
--- a/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
+++ b/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
@@ -434,6 +434,10 @@
   // load.
   if (attach_on_tracker_creation_)
     return;
+  // Prevent double registration if a test added expectation before
+  // prerendering navigation.
+  if (did_add_observer_)
+    return;
   AddObserver(tracker);
 }
 
diff --git a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
index 19d6b8b..2af74578 100644
--- a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
+++ b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
@@ -53,7 +53,8 @@
 }
 
 internal::PageLoadTimingStatus IsValidPageLoadTiming(
-    const mojom::PageLoadTiming& timing) {
+    const mojom::PageLoadTiming& timing,
+    bool is_prerendered) {
   if (page_load_metrics::IsEmpty(timing))
     return internal::INVALID_EMPTY_TIMING;
 
@@ -150,11 +151,30 @@
     return internal::INVALID_ORDER_DOM_CONTENT_LOADED_LOAD;
   }
 
-  if (!EventsInOrder(timing.parse_timing->parse_start,
-                     timing.paint_timing->first_paint)) {
-    LOG(ERROR) << "Invalid parse_start " << timing.parse_timing->parse_start
-               << " for first_paint " << timing.paint_timing->first_paint;
-    return internal::INVALID_ORDER_PARSE_START_FIRST_PAINT;
+  // If the page is prerendered, `parse_start <= activation_start <=
+  // first_paint`.
+  // If the page is non prerendered, `parse_start <= first_paint`.
+  if (is_prerendered) {
+    if (!EventsInOrder(timing.parse_timing->parse_start,
+                       timing.activation_start)) {
+      LOG(ERROR) << "Invalid parse_start " << timing.parse_timing->parse_start
+                 << " for activation_start " << timing.activation_start;
+      return internal::INVALID_ORDER_PARSE_START_ACTIVATION_START;
+    }
+
+    if (!EventsInOrder(timing.activation_start,
+                       timing.paint_timing->first_paint)) {
+      LOG(ERROR) << "Invalid activation_start " << timing.activation_start
+                 << " for first_paint " << timing.paint_timing->first_paint;
+      return internal::INVALID_ORDER_ACTIVATION_START_FIRST_PAINT;
+    }
+  } else {
+    if (!EventsInOrder(timing.parse_timing->parse_start,
+                       timing.paint_timing->first_paint)) {
+      LOG(ERROR) << "Invalid parse_start " << timing.parse_timing->parse_start
+                 << " for first_paint " << timing.paint_timing->first_paint;
+      return internal::INVALID_ORDER_PARSE_START_FIRST_PAINT;
+    }
   }
 
   if (!EventsInOrder(timing.paint_timing->first_paint,
@@ -699,7 +719,10 @@
     return;
   }
 
-  internal::PageLoadTimingStatus status = IsValidPageLoadTiming(*new_timing);
+  const bool is_prerendered =
+      (client_->GetPrerenderingState() != PrerenderingState::kNoPrerendering);
+  internal::PageLoadTimingStatus status =
+      IsValidPageLoadTiming(*new_timing, is_prerendered);
   UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status,
                             internal::LAST_PAGE_LOAD_TIMING_STATUS);
   if (status != internal::VALID) {
@@ -877,8 +900,10 @@
 
   current_merged_page_timing_ = pending_merged_page_timing_->Clone();
 
+  const bool is_prerendered =
+      (client_->GetPrerenderingState() != PrerenderingState::kNoPrerendering);
   internal::PageLoadTimingStatus status =
-      IsValidPageLoadTiming(*pending_merged_page_timing_);
+      IsValidPageLoadTiming(*pending_merged_page_timing_, is_prerendered);
   UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingDispatchStatus, status,
                             internal::LAST_PAGE_LOAD_TIMING_STATUS);
 
diff --git a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
index 870ea5d..81676a3 100644
--- a/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
+++ b/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
@@ -13,6 +13,7 @@
 #include "base/timer/timer.h"
 #include "components/page_load_metrics/browser/layout_shift_normalization.h"
 #include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+#include "components/page_load_metrics/browser/page_load_metrics_observer_delegate.h"
 #include "components/page_load_metrics/browser/responsiveness_metrics_normalization.h"
 #include "components/page_load_metrics/common/page_load_metrics.mojom.h"
 
@@ -92,6 +93,10 @@
   // Longest input delay cannot be less than first input delay.
   INVALID_LONGEST_INPUT_DELAY_LESS_THAN_FIRST_INPUT_DELAY,
 
+  // Activation start should be occur between parse start and first paint.
+  INVALID_ORDER_PARSE_START_ACTIVATION_START,
+  INVALID_ORDER_ACTIVATION_START_FIRST_PAINT,
+
   // New values should be added before this final entry.
   LAST_PAGE_LOAD_TIMING_STATUS
 };
@@ -112,6 +117,7 @@
    public:
     virtual ~Client() {}
 
+    virtual PrerenderingState GetPrerenderingState() const = 0;
     virtual bool IsPageMainFrame(content::RenderFrameHost* rfh) const = 0;
     virtual void OnTimingChanged() = 0;
     virtual void OnPageInputTimingChanged(uint64_t num_input_events) = 0;
diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc
index 8cd2c3e4..3012e39 100644
--- a/components/page_load_metrics/browser/page_load_tracker.cc
+++ b/components/page_load_metrics/browser/page_load_tracker.cc
@@ -406,11 +406,18 @@
 }
 
 void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) {
+  // We don't deliver OnCommit() for activation. Prerendered pages will see
+  // DidActivatePrerenderedPage() instead.
+  // Event records below are also not needed as we did them for the initial
+  // navigation on starting prerendering.
+  DCHECK(!navigation_handle->IsPrerenderedPageActivation());
+
   if (parent_tracker_) {
     // Notify the parent of the inner main frame navigation as a sub-frame
     // navigation.
     parent_tracker_->DidFinishSubFrameNavigation(navigation_handle);
   } else if (navigation_handle->IsPrerenderedPageActivation()) {
+    NOTREACHED();
     // We don't deliver OnCommit() for activation. Prerendered pages will see
     // DidActivatePrerenderedPage() instead.
     // Event records below are also not needed as we did them for the initial
diff --git a/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java b/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
index 40133c3..84cfdd8 100644
--- a/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
+++ b/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
@@ -127,9 +127,11 @@
      */
     @Test
     @MediumTest
-    @DisableIf.Build(message = "Test is failing on Android P, see crbug.com/1110939.",
-            sdk_is_greater_than = VERSION_CODES.O_MR1, sdk_is_less_than = VERSION_CODES.Q)
+    @DisableIf.Build(message = "Test is failing on Android P+, see crbug.com/1110939.",
+            sdk_is_greater_than = VERSION_CODES.O_MR1)
+    // clang-format off
     public void linkClickTest() {
+        // clang-format on
         initPlayerManager(false);
         final View playerHostView = mPlayerManager.getView();
 
diff --git a/components/proxy_config/pref_proxy_config_tracker_impl.h b/components/proxy_config/pref_proxy_config_tracker_impl.h
index 539b00cd..05effc4d 100644
--- a/components/proxy_config/pref_proxy_config_tracker_impl.h
+++ b/components/proxy_config/pref_proxy_config_tracker_impl.h
@@ -28,7 +28,7 @@
 // settings (pushed from PrefProxyConfigTrackerImpl) as overrides to the proxy
 // configuration determined by a baseline delegate ProxyConfigService on
 // non-ChromeOS platforms. ChromeOS has its own implementation of overrides in
-// chromeos::ProxyConfigServiceImpl.
+// ash::ProxyConfigServiceImpl.
 class ProxyConfigServiceImpl : public net::ProxyConfigService,
                                public net::ProxyConfigService::Observer {
  public:
diff --git a/components/query_tiles/switches.cc b/components/query_tiles/switches.cc
index 31fab2f9..c89c8997 100644
--- a/components/query_tiles/switches.cc
+++ b/components/query_tiles/switches.cc
@@ -24,6 +24,9 @@
 const base::Feature kQueryTilesDisableCountryOverride{
     "QueryTilesDisableCountryOverride", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kQueryTilesOnStart{
+    "QueryTilesOnStart", base::FEATURE_DISABLED_BY_DEFAULT};
+
 bool IsQueryTilesEnabledForCountry(const std::string& country_code) {
   std::string enabled_countries[] = {"IN", "NG", "JP"};
   for (const auto& country : enabled_countries) {
diff --git a/components/query_tiles/switches.h b/components/query_tiles/switches.h
index 4eb53ef8..3fee1bc 100644
--- a/components/query_tiles/switches.h
+++ b/components/query_tiles/switches.h
@@ -33,6 +33,9 @@
 // Whether to disable the override rules introduced for countries.
 extern const base::Feature kQueryTilesDisableCountryOverride;
 
+// Feature flag to determine whether query tiles should be shown on start surface.
+extern const base::Feature kQueryTilesOnStart;
+
 // Returns whether query tiles are enabled for the country.
 bool IsQueryTilesEnabledForCountry(const std::string& country_code);
 }  // namespace features
diff --git a/components/safe_browsing/content/browser/password_protection/password_protection_request_content.cc b/components/safe_browsing/content/browser/password_protection/password_protection_request_content.cc
index 975fb80..d6b0a36 100644
--- a/components/safe_browsing/content/browser/password_protection/password_protection_request_content.cc
+++ b/components/safe_browsing/content/browser/password_protection/password_protection_request_content.cc
@@ -155,7 +155,6 @@
               &PasswordProtectionRequestContent::OnGetDomFeatureTimeout,
               AsWeakPtr()),
           base::Milliseconds(kDomFeatureTimeoutMs));
-  dom_feature_start_time_ = base::TimeTicks::Now();
 }
 
 void PasswordProtectionRequestContent::OnGetDomFeatures(
@@ -194,9 +193,6 @@
         dom_features_request.model_version());
   }
 
-  UMA_HISTOGRAM_TIMES("PasswordProtection.DomFeatureExtractionDuration",
-                      base::TimeTicks::Now() - dom_feature_start_time_);
-
   if (IsVisualFeaturesEnabled()) {
     MaybeCollectVisualFeatures();
   } else {
diff --git a/components/safe_browsing/content/browser/password_protection/password_protection_request_content.h b/components/safe_browsing/content/browser/password_protection/password_protection_request_content.h
index 9f33fe2c..6cb267b 100644
--- a/components/safe_browsing/content/browser/password_protection/password_protection_request_content.h
+++ b/components/safe_browsing/content/browser/password_protection/password_protection_request_content.h
@@ -154,11 +154,6 @@
   // The Mojo pipe used for extracting DOM features from the renderer.
   mojo::Remote<safe_browsing::mojom::PhishingDetector> phishing_detector_;
 
-  // When we start extracting DOM features. Used to compute the duration of DOM
-  // feature extraction, which is logged at
-  // PasswordProtection.DomFeatureExtractionDuration.
-  base::TimeTicks dom_feature_start_time_;
-
   // Whether the DOM features collection is finished, either by timeout or by
   // successfully gathering the features.
   bool dom_features_collection_complete_;
diff --git a/components/safe_browsing/core/common/proto/csd.proto b/components/safe_browsing/core/common/proto/csd.proto
index f94bc0a..f131533 100644
--- a/components/safe_browsing/core/common/proto/csd.proto
+++ b/components/safe_browsing/core/common/proto/csd.proto
@@ -121,6 +121,9 @@
   // The time when the account-level enhanced safe browsing (A-ESB) bit state
   // was last sent updated on the client. This is an optional field.
   optional int64 aesb_last_update_time_windows_epoch_micros = 16;
+
+  // Server-side only field.
+  reserved 17;
 }
 
 message ClientPhishingRequest {
diff --git a/components/search_engines/template_url_service.cc b/components/search_engines/template_url_service.cc
index a6102e51..2acb1bb 100644
--- a/components/search_engines/template_url_service.cc
+++ b/components/search_engines/template_url_service.cc
@@ -930,13 +930,6 @@
   }
 }
 
-bool TemplateURLService::IsKeywordFromStarterPackTabSearch(
-    const std::u16string& keyword) {
-  const TemplateURL* turl = GetTemplateURLForKeyword(keyword);
-
-  return (turl && turl->starter_pack_id() == TemplateURLStarterPackData::kTabs);
-}
-
 void TemplateURLService::AddObserver(TemplateURLServiceObserver* observer) {
   model_observers_.AddObserver(observer);
 }
diff --git a/components/search_engines/template_url_service.h b/components/search_engines/template_url_service.h
index 69c046bd..1f4e21c 100644
--- a/components/search_engines/template_url_service.h
+++ b/components/search_engines/template_url_service.h
@@ -351,12 +351,6 @@
   // the default search engine entry.
   void RepairStarterPackEngines();
 
-  // Looks up `keyword` and determines whether the best TemplateURL for it is
-  // associated with the starter pack tab search engine.  Returns false if there
-  // is no matching TURL for the given keyword or if it is associated with
-  // another search engine.
-  bool IsKeywordFromStarterPackTabSearch(const std::u16string& keyword);
-
   // Observers used to listen for changes to the model.
   // TemplateURLService does NOT delete the observers when deleted.
   void AddObserver(TemplateURLServiceObserver* observer);
diff --git a/components/services/screen_ai/public/cpp/utilities.cc b/components/services/screen_ai/public/cpp/utilities.cc
index 5062f7d..490ae84 100644
--- a/components/services/screen_ai/public/cpp/utilities.cc
+++ b/components/services/screen_ai/public/cpp/utilities.cc
@@ -21,7 +21,9 @@
 enum {
   PATH_START = 13000,
 
-  DIR_SCREEN_AI_LIBRARY,  // Path from which ScreenAI library is preloaded.
+  // Note that this value is not kept between sessions or shared between
+  // processes.
+  PATH_SCREEN_AI_LIBRARY_BINARY,
 
   PATH_END
 };
@@ -32,15 +34,23 @@
   return base::FilePath(kScreenAISubDirName);
 }
 
-base::FilePath GetLatestLibraryFilePath() {
+base::FilePath GetComponentPath() {
   base::FilePath components_dir;
   base::PathService::Get(component_updater::DIR_COMPONENT_USER,
                          &components_dir);
   if (components_dir.empty())
     return base::FilePath();
 
+  return components_dir.Append(kScreenAISubDirName);
+}
+
+base::FilePath GetLatestLibraryFilePath() {
+  base::FilePath screen_ai_dir = GetComponentPath();
+  if (screen_ai_dir.empty())
+    return base::FilePath();
+
   // Get latest version.
-  base::FileEnumerator enumerator(components_dir.Append(kScreenAISubDirName),
+  base::FileEnumerator enumerator(screen_ai_dir,
                                   /*recursive=*/false,
                                   base::FileEnumerator::DIRECTORIES);
   base::FilePath latest_version_dir;
@@ -58,13 +68,13 @@
   return library_path;
 }
 
-void SetPreloadedLibraryFilePath(const base::FilePath& path) {
-  base::PathService::Override(DIR_SCREEN_AI_LIBRARY, path);
+void StoreLibraryBinaryPath(const base::FilePath& path) {
+  base::PathService::Override(PATH_SCREEN_AI_LIBRARY_BINARY, path);
 }
 
-base::FilePath GetPreloadedLibraryFilePath() {
+base::FilePath GetStoredLibraryBinaryPath() {
   base::FilePath path;
-  base::PathService::Get(DIR_SCREEN_AI_LIBRARY, &path);
+  base::PathService::Get(PATH_SCREEN_AI_LIBRARY_BINARY, &path);
   return path;
 }
 
diff --git a/components/services/screen_ai/public/cpp/utilities.h b/components/services/screen_ai/public/cpp/utilities.h
index b1e13f9..143cb18 100644
--- a/components/services/screen_ai/public/cpp/utilities.h
+++ b/components/services/screen_ai/public/cpp/utilities.h
@@ -15,12 +15,16 @@
 // Returns the install directory relative to components folder.
 base::FilePath GetRelativeInstallDir();
 
-// Stores the path to the preloaded library. This value is set when the library
-// is loaded prior to sandboxing in every session.
-void SetPreloadedLibraryFilePath(const base::FilePath& path);
+// Returns the folder in which ScreenAI component is installed.
+base::FilePath GetComponentPath();
 
-// Returns the preloaded path for the library.
-base::FilePath GetPreloadedLibraryFilePath();
+// Stores the path to the library binary. This value is kept in memory and is
+// not kept between sessions or shared between processes.
+void StoreLibraryBinaryPath(const base::FilePath& path);
+
+// Returns the library binary path if it is already stored by
+// |StoreLibraryBinaryPath|.
+base::FilePath GetStoredLibraryBinaryPath();
 
 }  // namespace screen_ai
 #endif  // COMPONENTS_SERVICES_SCREEN_AI_PUBLIC_CPP_UTILITIES_H_
diff --git a/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc b/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc
index 7ae9b0b..eb72269 100644
--- a/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc
+++ b/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc
@@ -34,7 +34,7 @@
       VLOG(2) << "Screen AI library loaded pre-sandboxing:" << library_path;
     }
   }
-  screen_ai::SetPreloadedLibraryFilePath(library_path);
+  screen_ai::StoreLibraryBinaryPath(library_path);
 
   auto* instance = sandbox::policy::SandboxLinux::GetInstance();
 
diff --git a/components/services/screen_ai/screen_ai_service_impl.cc b/components/services/screen_ai/screen_ai_service_impl.cc
index 9b2eb2a..ef7f8de 100644
--- a/components/services/screen_ai/screen_ai_service_impl.cc
+++ b/components/services/screen_ai/screen_ai_service_impl.cc
@@ -18,12 +18,17 @@
 namespace {
 
 base::FilePath GetLibraryFilePath() {
-  base::FilePath library_path = GetPreloadedLibraryFilePath();
-  if (library_path.empty() && base::CommandLine::ForCurrentProcess()->HasSwitch(
-                                  sandbox::policy::switches::kNoSandbox)) {
-    library_path = GetLatestLibraryFilePath();
-    SetPreloadedLibraryFilePath(library_path);
-  }
+  base::FilePath library_path = GetStoredLibraryBinaryPath();
+
+  if (!library_path.empty())
+    return library_path;
+
+  // Binary file path is set while setting the sandbox on Linux, or the first
+  // time this function is called. So in all other cases we need to look for
+  // the library binary in its component folder.
+  library_path = GetLatestLibraryFilePath();
+  StoreLibraryBinaryPath(library_path);
+
   return library_path;
 }
 
diff --git a/components/services/storage/service_worker/service_worker_database.cc b/components/services/storage/service_worker/service_worker_database.cc
index 914b8a7..dbbc51b 100644
--- a/components/services/storage/service_worker/service_worker_database.cc
+++ b/components/services/storage/service_worker/service_worker_database.cc
@@ -1637,30 +1637,29 @@
       (data.has_fetch_handler())
           ? blink::mojom::ServiceWorkerFetchHandlerType::kNotSkippable
           : blink::mojom::ServiceWorkerFetchHandlerType::kNoHandler;
-  if (data.has_fetch_handler_type()) {
+  if (data.has_fetch_handler_skippable_type()) {
     if (!data.has_fetch_handler()) {
-      DLOG(ERROR) << "has_fetch_handler must be true if fetch_handler_type"
-                  << " is set.";
+      DLOG(ERROR)
+          << "has_fetch_handler must be true if fetch_handler_skippable_type"
+          << " is set.";
       return Status::kErrorCorrupted;
     }
-    if (!ServiceWorkerRegistrationData_FetchHandlerType_IsValid(
-            data.fetch_handler_type())) {
-      DLOG(ERROR) << "Fetch handler type '" << data.fetch_handler_type()
-                  << "' is not valid.";
+    if (!ServiceWorkerRegistrationData_FetchHandlerSkippableType_IsValid(
+            data.fetch_handler_skippable_type())) {
+      DLOG(ERROR) << "Fetch handler type '"
+                  << data.fetch_handler_skippable_type() << "' is not valid.";
       return Status::kErrorCorrupted;
     }
-    switch (data.fetch_handler_type()) {
+    switch (data.fetch_handler_skippable_type()) {
       case ServiceWorkerRegistrationData::NOT_SKIPPABLE:
         (*out)->fetch_handler_type =
             blink::mojom::ServiceWorkerFetchHandlerType::kNotSkippable;
         break;
-      // TODO(crbug.com/1347319): implement other fetch_handler_type.
-      default:
-        // UNKNOWN_FETCH_HANDLER, which must not be stored, should also be
-        // handled here.
-        DLOG(ERROR) << "Fetch handler type '" << data.fetch_handler_type()
-                    << "' is not known.";
-        return Status::kErrorCorrupted;
+      case ServiceWorkerRegistrationData::SKIPPABLE_EMPTY_FETCH_HANDLER:
+        (*out)->fetch_handler_type =
+            blink::mojom::ServiceWorkerFetchHandlerType::kEmptyFetchHandler;
+        break;
+        // TODO(crbug.com/1347319): implement other fetch_handler_type.
     }
   }
   (*out)->last_update_check = base::Time::FromDeltaSinceWindowsEpoch(
@@ -1811,10 +1810,15 @@
   if (data.has_fetch_handler()) {
     switch (registration.fetch_handler_type) {
       case blink::mojom::ServiceWorkerFetchHandlerType::kNotSkippable:
-        data.set_fetch_handler_type(
+        data.set_fetch_handler_skippable_type(
             ServiceWorkerRegistrationData::NOT_SKIPPABLE);
         break;
+      case blink::mojom::ServiceWorkerFetchHandlerType::kEmptyFetchHandler:
+        data.set_fetch_handler_skippable_type(
+            ServiceWorkerRegistrationData::SKIPPABLE_EMPTY_FETCH_HANDLER);
+        break;
       // TODO(crbug.com/1347319): implement other fetch_handler_type.
+      // TODO(crbug.com/1351246): remove default if possible.
       default:
         DCHECK(false) << "Unknown fetch_handler_type is used."
                       << registration.fetch_handler_type;
diff --git a/components/services/storage/service_worker/service_worker_database.h b/components/services/storage/service_worker/service_worker_database.h
index 0fb57346..6be5e5e 100644
--- a/components/services/storage/service_worker/service_worker_database.h
+++ b/components/services/storage/service_worker/service_worker_database.h
@@ -420,6 +420,8 @@
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, InvalidWebFeature);
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest,
                            NoCrossOriginEmbedderPolicyValue);
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, NoFetchHandlerType);
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDatabaseTest, FetchHandlerType);
 };
 
 }  // namespace storage
diff --git a/components/services/storage/service_worker/service_worker_database.proto b/components/services/storage/service_worker/service_worker_database.proto
index 736c530..b52d937 100644
--- a/components/services/storage/service_worker/service_worker_database.proto
+++ b/components/services/storage/service_worker/service_worker_database.proto
@@ -42,9 +42,10 @@
     NORMAL_FRAME = 0;
     FENCED_FRAME = 1;
   }
-  enum FetchHandlerType {
-    UNKNOWN_FETCH_HANDLER = 0;
+  enum FetchHandlerSkippableType {
+    reserved 0;  // Deprecated UNKNOWN_FETCH_HANDLER.
     NOT_SKIPPABLE = 1;
+    SKIPPABLE_EMPTY_FETCH_HANDLER = 2;
   }
 
   required int64 registration_id = 1;
@@ -58,8 +59,7 @@
 
   required bool is_active = 5;
   required bool has_fetch_handler = 6;
-  optional FetchHandlerType fetch_handler_type = 22
-      [default = UNKNOWN_FETCH_HANDLER];
+  optional FetchHandlerSkippableType fetch_handler_skippable_type = 22;
 
   // Serialized by Time::FromDeltaSinceWindowsEpoch().
   required int64 last_update_check_time = 7;
diff --git a/components/services/storage/service_worker/service_worker_database_unittest.cc b/components/services/storage/service_worker/service_worker_database_unittest.cc
index b284e3d..79d8e02 100644
--- a/components/services/storage/service_worker/service_worker_database_unittest.cc
+++ b/components/services/storage/service_worker/service_worker_database_unittest.cc
@@ -2464,7 +2464,8 @@
   data.set_version_id(1);
   data.set_is_active(true);
   data.set_has_fetch_handler(true);
-  data.set_fetch_handler_type(ServiceWorkerRegistrationData::NOT_SKIPPABLE);
+  data.set_fetch_handler_skippable_type(
+      ServiceWorkerRegistrationData::NOT_SKIPPABLE);
   data.set_last_update_check_time(
       base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
 
@@ -2585,7 +2586,8 @@
   data.set_version_id(1);
   data.set_is_active(true);
   data.set_has_fetch_handler(true);
-  data.set_fetch_handler_type(ServiceWorkerRegistrationData::NOT_SKIPPABLE);
+  data.set_fetch_handler_skippable_type(
+      ServiceWorkerRegistrationData::NOT_SKIPPABLE);
   data.set_last_update_check_time(
       base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
 
@@ -2656,4 +2658,147 @@
   EXPECT_FALSE(resources_list.empty());
 }
 
+TEST(ServiceWorkerDatabaseTest, NoFetchHandlerType) {
+  std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
+
+  ServiceWorkerRegistrationData data;
+  data.set_registration_id(1);
+  data.set_scope_url("https://example.com");
+  data.set_script_url("https://example.com/sw");
+  data.set_version_id(1);
+  data.set_is_active(true);
+  data.set_last_update_check_time(
+      base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
+
+  database->next_avail_registration_id_ = 2;
+  database->next_avail_version_id_ = 2;
+
+  blink::StorageKey key =
+      blink::StorageKey::CreateFromStringForTesting(data.scope_url());
+
+  {
+    // has_fetch_handler = true.
+    data.set_has_fetch_handler(true);
+
+    // Write the serialization.
+    std::string value;
+    ASSERT_TRUE(data.SerializeToString(&value));
+
+    // Parse the serialized data. The kNotSkippable if has_fetch_handler is true
+    // and no fetch_handler_type.
+    RegistrationDataPtr registration;
+    ASSERT_EQ(ServiceWorkerDatabase::Status::kOk,
+              database->ParseRegistrationData(value, key, &registration));
+    EXPECT_EQ(blink::mojom::ServiceWorkerFetchHandlerType::kNotSkippable,
+              registration->fetch_handler_type);
+  }
+
+  {
+    // has_fetch_handler = false.
+    data.set_has_fetch_handler(false);
+
+    // Write the serialization.
+    std::string value;
+    ASSERT_TRUE(data.SerializeToString(&value));
+
+    // Parse the serialized data. The kNoHandler if has_fetch_handler is
+    // false and no fetch_handler_type.
+    RegistrationDataPtr registration;
+    ASSERT_EQ(ServiceWorkerDatabase::Status::kOk,
+              database->ParseRegistrationData(value, key, &registration));
+    EXPECT_EQ(blink::mojom::ServiceWorkerFetchHandlerType::kNoHandler,
+              registration->fetch_handler_type);
+  }
+}
+
+TEST(ServiceWorkerDatabaseTest, FetchHandlerType) {
+  std::unique_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
+
+  ServiceWorkerRegistrationData data;
+  data.set_registration_id(1);
+  data.set_scope_url("https://example.com");
+  data.set_script_url("https://example.com/sw");
+  data.set_version_id(1);
+  data.set_is_active(true);
+  data.set_has_fetch_handler(true);
+  data.set_last_update_check_time(
+      base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
+
+  database->next_avail_registration_id_ = 2;
+  database->next_avail_version_id_ = 2;
+
+  blink::StorageKey key =
+      blink::StorageKey::CreateFromStringForTesting(data.scope_url());
+
+  {
+    data.set_fetch_handler_skippable_type(
+        ServiceWorkerRegistrationData::NOT_SKIPPABLE);
+    // Write the serialization.
+    std::string value;
+    ASSERT_TRUE(data.SerializeToString(&value));
+
+    RegistrationDataPtr registration;
+    ASSERT_EQ(ServiceWorkerDatabase::Status::kOk,
+              database->ParseRegistrationData(value, key, &registration));
+    EXPECT_EQ(blink::mojom::ServiceWorkerFetchHandlerType::kNotSkippable,
+              registration->fetch_handler_type);
+  }
+
+  {
+    data.set_fetch_handler_skippable_type(
+        ServiceWorkerRegistrationData::SKIPPABLE_EMPTY_FETCH_HANDLER);
+    // Write the serialization.
+    std::string value;
+    ASSERT_TRUE(data.SerializeToString(&value));
+
+    // Parse the serialized data. The policy is kNone if it's not set.
+    RegistrationDataPtr registration;
+    ASSERT_EQ(ServiceWorkerDatabase::Status::kOk,
+              database->ParseRegistrationData(value, key, &registration));
+    EXPECT_EQ(blink::mojom::ServiceWorkerFetchHandlerType::kEmptyFetchHandler,
+              registration->fetch_handler_type);
+  }
+}
+
+TEST(ServiceWorkerDatabaseTest, FetchHandlerTypeStoreRestore) {
+  auto store_and_restore =
+      [](blink::mojom::ServiceWorkerFetchHandlerType type) {
+        GURL origin("https://example.com");
+        RegistrationData data;
+        data.registration_id = 123;
+        data.scope = URL(origin, "/foo");
+        data.key = blink::StorageKey(url::Origin::Create(data.scope));
+        data.script = URL(origin, "/script.js");
+        data.version_id = 456;
+        data.fetch_handler_type = type;
+        data.resources_total_size_bytes = 100;
+        data.cross_origin_embedder_policy = CrossOriginEmbedderPolicyNone();
+        std::vector<ResourceRecordPtr> resources;
+        resources.push_back(CreateResource(1, data.script, 100));
+
+        // Store.
+        std::unique_ptr<ServiceWorkerDatabase> database(
+            CreateDatabaseInMemory());
+        ServiceWorkerDatabase::DeletedVersion deleted_version;
+        ASSERT_EQ(
+            ServiceWorkerDatabase::Status::kOk,
+            database->WriteRegistration(data, resources, &deleted_version));
+
+        // Restore.
+        std::vector<mojom::ServiceWorkerRegistrationDataPtr> registrations;
+        std::vector<std::vector<ResourceRecordPtr>> resources_list;
+        EXPECT_EQ(ServiceWorkerDatabase::Status::kOk,
+                  database->GetRegistrationsForStorageKey(
+                      blink::StorageKey(url::Origin::Create(origin)),
+                      &registrations, &resources_list));
+
+        // The data must not have been altered.
+        VerifyRegistrationData(data, *registrations[0]);
+      };
+  store_and_restore(blink::mojom::ServiceWorkerFetchHandlerType::kNoHandler);
+  store_and_restore(blink::mojom::ServiceWorkerFetchHandlerType::kNotSkippable);
+  store_and_restore(
+      blink::mojom::ServiceWorkerFetchHandlerType::kEmptyFetchHandler);
+}
+
 }  // namespace storage
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 8cadaf9..02ae6e938 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -322,12 +322,16 @@
   // MakeModeFilter treats fixed color as src, and input color as dst.
   // kDstIn is (srcAlpha * dstColor, srcAlpha * dstAlpha) so this makes the
   // output color equal to input color * alpha.
+  // TODO(michaelludwig): Update to pass alpha_as_color as-is once
+  // skbug.com/13637 is resolved (adds Blend + SkColor4f variation).
   sk_sp<SkColorFilter> opacity =
       SkColorFilters::Blend(alpha_as_color.toSkColor(), SkBlendMode::kDstIn);
-  if (in) {
+  // Opaque (alpha = 1.0) and kDstIn returns nullptr to signal a no-op, so that
+  // case should just return 'in'.
+  if (opacity) {
     return opacity->makeComposed(std::move(in));
   } else {
-    return opacity;
+    return in;
   }
 }
 
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 91a03759..272056e0 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -497,7 +497,7 @@
     // Don't clip bounds. Some screen magnifiers (e.g. ZoomText) prefer to
     // get unclipped bounds so that they can make smooth scrolling calculations.
     gfx::Rect absolute_child_rect = child->RelativeToAbsoluteBounds(
-        child->GetInlineTextRect(local_start, local_end, child_length),
+        child->GetTextContentRangeBoundsUTF16(local_start, local_end),
         ui::AXCoordinateSystem::kRootFrame, clipping_behavior,
         offscreen_result);
     if (bounds.width() == 0 && bounds.height() == 0) {
@@ -602,8 +602,7 @@
   // migrated to that class.
   if (GetRole() == ax::mojom::Role::kInlineTextBox) {
     return RelativeToAbsoluteBounds(
-        GetInlineTextRect(start_offset, end_offset,
-                          GetTextContentUTF16().length()),
+        GetTextContentRangeBoundsUTF16(start_offset, end_offset),
         coordinate_system, clipping_behavior, offscreen_result);
   }
 
@@ -645,62 +644,10 @@
   return bounds;
 }
 
-gfx::RectF BrowserAccessibility::GetInlineTextRect(const int start_offset,
-                                                   const int end_offset,
-                                                   const int max_length) const {
-  // TODO(nektar): Move this method to `AXNode` in the immediate future.
-  DCHECK(start_offset >= 0 && end_offset >= 0 && start_offset <= end_offset);
-  int local_start_offset = start_offset, local_end_offset = end_offset;
-  const std::vector<int32_t>& character_offsets =
-      GetIntListAttribute(ax::mojom::IntListAttribute::kCharacterOffsets);
-  const int character_offsets_length = character_offsets.size();
-  if (character_offsets_length < max_length) {
-    // Blink might not return pixel offsets for all characters. Clamp the
-    // character range to be within the number of provided pixels.
-    local_start_offset = std::min(local_start_offset, character_offsets_length);
-    local_end_offset = std::min(local_end_offset, character_offsets_length);
-  }
-
-  const int start_pixel_offset =
-      local_start_offset > 0 ? character_offsets[local_start_offset - 1] : 0;
-  const int end_pixel_offset =
-      local_end_offset > 0 ? character_offsets[local_end_offset - 1] : 0;
-  const int max_pixel_offset =
-      character_offsets_length > 0
-          ? character_offsets[character_offsets_length - 1]
-          : 0;
-  const gfx::RectF location = GetLocation();
-  const int location_width = location.width();
-  const int location_height = location.height();
-
-  gfx::RectF bounds;
-  switch (static_cast<ax::mojom::WritingDirection>(
-      GetIntAttribute(ax::mojom::IntAttribute::kTextDirection))) {
-    case ax::mojom::WritingDirection::kNone:
-    case ax::mojom::WritingDirection::kLtr:
-      bounds =
-          gfx::RectF(start_pixel_offset, 0,
-                     end_pixel_offset - start_pixel_offset, location_height);
-      break;
-    case ax::mojom::WritingDirection::kRtl: {
-      const int left = max_pixel_offset - end_pixel_offset;
-      const int right = max_pixel_offset - start_pixel_offset;
-      bounds = gfx::RectF(left, 0, right - left, location_height);
-      break;
-    }
-    case ax::mojom::WritingDirection::kTtb:
-      bounds = gfx::RectF(0, start_pixel_offset, location_width,
-                          end_pixel_offset - start_pixel_offset);
-      break;
-    case ax::mojom::WritingDirection::kBtt: {
-      const int top = max_pixel_offset - end_pixel_offset;
-      const int bottom = max_pixel_offset - start_pixel_offset;
-      bounds = gfx::RectF(0, top, location_width, bottom - top);
-      break;
-    }
-  }
-
-  return bounds;
+gfx::RectF BrowserAccessibility::GetTextContentRangeBoundsUTF16(
+    int start_offset,
+    int end_offset) const {
+  return node()->GetTextContentRangeBoundsUTF16(start_offset, end_offset);
 }
 
 BrowserAccessibility* BrowserAccessibility::ApproximateHitTest(
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 9e45fd0..2de6304 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -649,11 +649,9 @@
       const ui::AXClippingBehavior clipping_behavior,
       ui::AXOffscreenResult* offscreen_result = nullptr) const;
 
-  // Return the bounds of inline text in this node's coordinate system (which
-  // is relative to its container node specified in AXRelativeBounds).
-  gfx::RectF GetInlineTextRect(const int start_offset,
-                               const int end_offset,
-                               const int max_length) const;
+  // See `AXNode::GetTextContentRangeBoundsUTF16`.
+  gfx::RectF GetTextContentRangeBoundsUTF16(int start_offset,
+                                            int end_offset) const;
 
   // Recursive helper function for GetInnerTextRangeBounds.
   gfx::Rect GetInnerTextRangeBoundsRectInSubtree(
diff --git a/content/browser/renderer_host/pepper/pepper_socket_utils.cc b/content/browser/renderer_host/pepper/pepper_socket_utils.cc
index 6ee1d14..aef3394a 100644
--- a/content/browser/renderer_host/pepper/pepper_socket_utils.cc
+++ b/content/browser/renderer_host/pepper/pepper_socket_utils.cc
@@ -91,8 +91,8 @@
 }  // namespace
 
 void OpenFirewallHole(const net::IPEndPoint& address,
-                      chromeos::FirewallHole::PortType type,
-                      chromeos::FirewallHole::OpenCallback callback) {
+                      ash::FirewallHole::PortType type,
+                      ash::FirewallHole::OpenCallback callback) {
   if (IsLoopbackAddress(address.address())) {
     std::move(callback).Run(nullptr);
     return;
@@ -103,19 +103,19 @@
   // can be resolved by the address, but the best solution would be to update
   // firewalld to allow filtering by destination address, not just destination
   // port. iptables already support it.
-  chromeos::FirewallHole::Open(type, address.port(), std::string(),
-                               std::move(callback));
+  ash::FirewallHole::Open(type, address.port(), std::string(),
+                          std::move(callback));
 }
 
 void OpenTCPFirewallHole(const net::IPEndPoint& address,
-                         chromeos::FirewallHole::OpenCallback callback) {
-  OpenFirewallHole(address, chromeos::FirewallHole::PortType::TCP,
+                         ash::FirewallHole::OpenCallback callback) {
+  OpenFirewallHole(address, ash::FirewallHole::PortType::TCP,
                    std::move(callback));
 }
 
 void OpenUDPFirewallHole(const net::IPEndPoint& address,
-                         chromeos::FirewallHole::OpenCallback callback) {
-  OpenFirewallHole(address, chromeos::FirewallHole::PortType::UDP,
+                         ash::FirewallHole::OpenCallback callback) {
+  OpenFirewallHole(address, ash::FirewallHole::PortType::UDP,
                    std::move(callback));
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/content/browser/renderer_host/pepper/pepper_socket_utils.h b/content/browser/renderer_host/pepper/pepper_socket_utils.h
index 0a981d2..7414ab4 100644
--- a/content/browser/renderer_host/pepper/pepper_socket_utils.h
+++ b/content/browser/renderer_host/pepper/pepper_socket_utils.h
@@ -45,10 +45,10 @@
 
 // Returns true if the open operation is in progress.
 void OpenTCPFirewallHole(const net::IPEndPoint& address,
-                         chromeos::FirewallHole::OpenCallback callback);
+                         ash::FirewallHole::OpenCallback callback);
 
 void OpenUDPFirewallHole(const net::IPEndPoint& address,
-                         chromeos::FirewallHole::OpenCallback callback);
+                         ash::FirewallHole::OpenCallback callback);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Annotations for TCP and UDP network requests. Defined here to make it easier
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
index 6e57a3f..97f380a 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
@@ -275,7 +275,7 @@
 
 void PepperTCPServerSocketMessageFilter::OnFirewallHoleOpened(
     const ppapi::host::ReplyMessageContext& context,
-    std::unique_ptr<chromeos::FirewallHole> hole) {
+    std::unique_ptr<ash::FirewallHole> hole) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   LOG_IF(WARNING, !hole.get()) << "Firewall hole could not be opened.";
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
index 9dbd247..86aa483 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
+++ b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
@@ -143,7 +143,7 @@
   void OpenFirewallHole(const ppapi::host::ReplyMessageContext& context,
                         const net::IPEndPoint& local_addr);
   void OnFirewallHoleOpened(const ppapi::host::ReplyMessageContext& context,
-                            std::unique_ptr<chromeos::FirewallHole> hole);
+                            std::unique_ptr<ash::FirewallHole> hole);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // Following fields are initialized and used only on the IO thread.
@@ -161,8 +161,7 @@
   PP_NetAddress_Private bound_addr_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  std::unique_ptr<chromeos::FirewallHole,
-                  content::BrowserThread::DeleteOnUIThread>
+  std::unique_ptr<ash::FirewallHole, content::BrowserThread::DeleteOnUIThread>
       firewall_hole_;
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
index 23961d7..384dd8b 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
@@ -1200,7 +1200,7 @@
 
 void PepperTCPSocketMessageFilter::OnFirewallHoleOpened(
     const ppapi::host::ReplyMessageContext& context,
-    std::unique_ptr<chromeos::FirewallHole> hole) {
+    std::unique_ptr<ash::FirewallHole> hole) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(state_.IsPending(TCPSocketState::LISTEN));
   LOG_IF(WARNING, !hole.get()) << "Firewall hole could not be opened.";
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
index 8c3927b..d8e7a87 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
+++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
@@ -230,7 +230,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   void OpenFirewallHole(const ppapi::host::ReplyMessageContext& context);
   void OnFirewallHoleOpened(const ppapi::host::ReplyMessageContext& context,
-                            std::unique_ptr<chromeos::FirewallHole> hole);
+                            std::unique_ptr<ash::FirewallHole> hole);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   void SendBindReply(const ppapi::host::ReplyMessageContext& context,
@@ -315,7 +315,7 @@
   net::IPEndPoint bind_output_ip_endpoint_;
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  std::unique_ptr<chromeos::FirewallHole> firewall_hole_;
+  std::unique_ptr<ash::FirewallHole> firewall_hole_;
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // Bitwise-or of SocketOption flags. This stores the state about whether
diff --git a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
index eb57af01..632c019 100644
--- a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
@@ -602,7 +602,7 @@
     mojo::PendingReceiver<network::mojom::UDPSocketListener> listener_receiver,
     const ppapi::host::ReplyMessageContext& context,
     const PP_NetAddress_Private& net_address,
-    std::unique_ptr<chromeos::FirewallHole> hole) {
+    std::unique_ptr<ash::FirewallHole> hole) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   LOG_IF(WARNING, !hole.get()) << "Firewall hole could not be opened.";
diff --git a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
index 6f9b7abb..500d202 100644
--- a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
+++ b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
@@ -146,7 +146,7 @@
           listener_receiver,
       const ppapi::host::ReplyMessageContext& context,
       const PP_NetAddress_Private& net_address,
-      std::unique_ptr<chromeos::FirewallHole> hole);
+      std::unique_ptr<ash::FirewallHole> hole);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   void StartPendingSend();
   void Close();
@@ -227,8 +227,7 @@
   mojo::Receiver<network::mojom::UDPSocketListener> receiver_{this};
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  std::unique_ptr<chromeos::FirewallHole,
-                  content::BrowserThread::DeleteOnUIThread>
+  std::unique_ptr<ash::FirewallHole, content::BrowserThread::DeleteOnUIThread>
       firewall_hole_;
   // Allows for cancellation of opening a hole in the firewall in the case the
   // network service crashes.
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index 4ac2692..ffbacf6 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -711,6 +711,22 @@
            std::move(timing), version_);
 }
 
+// static
+const char* ServiceWorkerFetchDispatcher::FetchEventResultToSuffix(
+    FetchEventResult result) {
+  // Don't change these returned strings. They are written (in hashed form) into
+  // logs.
+  switch (result) {
+    case ServiceWorkerFetchDispatcher::FetchEventResult::kShouldFallback:
+      return "_SHOULD_FALLBACK";
+    case ServiceWorkerFetchDispatcher::FetchEventResult::kGotResponse:
+      return "_GOT_RESPONSE";
+  }
+  NOTREACHED() << "Got unexpected fetch event result:"
+               << static_cast<int>(result);
+  return "error";
+}
+
 bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload(
     const network::ResourceRequest& original_request,
     scoped_refptr<ServiceWorkerContextWrapper> context_wrapper,
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.h b/content/browser/service_worker/service_worker_fetch_dispatcher.h
index 11a8e684..715317b 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.h
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.h
@@ -34,11 +34,14 @@
 class CONTENT_EXPORT ServiceWorkerFetchDispatcher {
  public:
   // Indicates how the service worker handled a fetch event.
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
   enum class FetchEventResult {
     // Browser should fallback to native fetch.
-    kShouldFallback,
+    kShouldFallback = 0,
     // Service worker provided a ServiceWorkerResponse.
-    kGotResponse
+    kGotResponse = 1,
+    kMaxValue = kGotResponse,
   };
 
   using FetchCallback =
@@ -64,6 +67,8 @@
 
   ~ServiceWorkerFetchDispatcher();
 
+  static const char* FetchEventResultToSuffix(FetchEventResult result);
+
   // If appropriate, starts the navigation preload request and creates
   // |preload_handle_|. Returns true if it started navigation preload.
   bool MaybeStartNavigationPreload(
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.cc b/content/browser/service_worker/service_worker_main_resource_loader.cc
index 6d3d96c..98bdd538 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader.cc
@@ -304,6 +304,10 @@
   response_head_->load_timing.send_end =
       fetch_event_timing_->dispatch_event_time;
 
+  // Records the metrics only if the code has been executed successfully in
+  // the service workers because we aim to see the fallback ratio and timing.
+  RecordFetchEventHandlerMetrics(fetch_result);
+
   if (fetch_result ==
       ServiceWorkerFetchDispatcher::FetchEventResult::kShouldFallback) {
     TransitionToStatus(Status::kCompleted);
@@ -558,6 +562,22 @@
   }
 }
 
+void ServiceWorkerMainResourceLoader::RecordFetchEventHandlerMetrics(
+    ServiceWorkerFetchDispatcher::FetchEventResult fetch_result) {
+  UMA_HISTOGRAM_ENUMERATION("ServiceWorker.MainFrame.MainResource.FetchResult",
+                            fetch_result);
+
+  // Time spent by fetch handlers per |fetch_result|.
+  base::UmaHistogramTimes(
+      base::StrCat({
+          "ServiceWorker.LoadTiming.MainFrame.MainResource."
+          "FetchHandlerStartToFetchHandlerEndByFetchResult",
+          ServiceWorkerFetchDispatcher::FetchEventResultToSuffix(fetch_result),
+      }),
+      fetch_event_timing_->respond_with_settled_time -
+          fetch_event_timing_->dispatch_event_time);
+}
+
 void ServiceWorkerMainResourceLoader::TransitionToStatus(Status new_status) {
 #if DCHECK_IS_ON()
   switch (new_status) {
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.h b/content/browser/service_worker/service_worker_main_resource_loader.h
index 2232cde..3008ddf 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.h
+++ b/content/browser/service_worker/service_worker_main_resource_loader.h
@@ -160,6 +160,10 @@
   // handled the request (i.e. non network fallback case).
   void RecordTimingMetrics(bool handled);
 
+  // Records metrics related to the fetch event handler execution.
+  void RecordFetchEventHandlerMetrics(
+      ServiceWorkerFetchDispatcher::FetchEventResult fetch_result);
+
   void TransitionToStatus(Status new_status);
 
   NavigationLoaderInterceptor::FallbackCallback fallback_callback_;
diff --git a/content/browser/service_worker/service_worker_version_browsertest.cc b/content/browser/service_worker/service_worker_version_browsertest.cc
index d99b503..60c5543f 100644
--- a/content/browser/service_worker/service_worker_version_browsertest.cc
+++ b/content/browser/service_worker/service_worker_version_browsertest.cc
@@ -939,6 +939,8 @@
             blink::ServiceWorkerStatusCode::kOk);
   EXPECT_EQ(ServiceWorkerVersion::FetchHandlerExistence::EXISTS,
             version_->fetch_handler_existence());
+  EXPECT_EQ(ServiceWorkerVersion::FetchHandlerType::kNotSkippable,
+            version_->fetch_handler_type());
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
@@ -948,6 +950,19 @@
             blink::ServiceWorkerStatusCode::kOk);
   EXPECT_EQ(ServiceWorkerVersion::FetchHandlerExistence::DOES_NOT_EXIST,
             version_->fetch_handler_existence());
+  EXPECT_EQ(ServiceWorkerVersion::FetchHandlerType::kNoHandler,
+            version_->fetch_handler_type());
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
+                       InstallEmptyFetchHandler) {
+  StartServerAndNavigateToSetup();
+  ASSERT_EQ(Install("/service_worker/empty_fetch_event.js"),
+            blink::ServiceWorkerStatusCode::kOk);
+  EXPECT_EQ(ServiceWorkerVersion::FetchHandlerExistence::EXISTS,
+            version_->fetch_handler_existence());
+  EXPECT_EQ(ServiceWorkerVersion::FetchHandlerType::kEmptyFetchHandler,
+            version_->fetch_handler_type());
 }
 
 // Check that fetch event handler added in the install event should result in a
diff --git a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
index 9316d7a..1b917e80 100644
--- a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
@@ -1174,7 +1174,7 @@
       "publisher.example.com" /* inner_url_hostname */,
       "/target.html" /* page_inner_url_path */,
       "/script.js" /* script_inner_url_path */,
-      {} /* script_sxg_outer_headers */,
+      {{"Access-Control-Allow-Origin", "*"}} /* script_sxg_outer_headers */,
       "" /* additional_link_element_attributes */,
       0 /* elapsed_time_after_prefetch */, "done" /* expected_title */,
       true /* script_sxg_should_be_stored */,
@@ -1182,6 +1182,28 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SignedExchangeSubresourcePrefetchBrowserTest,
+                       MainResourceSXGAndScriptSXG_CrossOrigin_CorsError) {
+  // This test is similar to MainResourceSXGAndScriptSXG_CrossOrigin, but the
+  // script SXG is served without Access-Control-Allow-Origin. Prefetch of the
+  // script SXG should fail with CORS error.
+  RunPrefetchMainResourceSXGAndScriptSXGTest(
+      "aggregator.example.com" /* prefetch_page_hostname */,
+      "/prefetch.html" /* prefetch_page_path */,
+      "distoributor.example.com" /* page_sxg_hostname */,
+      "/target.sxg" /* page_sxg_path */,
+      "distoributor.example.com" /* script_sxg_hostname */,
+      "/script.sxg" /* script_sxg_path */,
+      "publisher.example.com" /* inner_url_hostname */,
+      "/target.html" /* page_inner_url_path */,
+      "/script.js" /* script_inner_url_path */,
+      {} /* script_sxg_outer_headers */,
+      "" /* additional_link_element_attributes */,
+      0 /* elapsed_time_after_prefetch */, "from server" /* expected_title */,
+      false /* script_sxg_should_be_stored */,
+      1 /* expected_script_fetch_count */);
+}
+
+IN_PROC_BROWSER_TEST_F(SignedExchangeSubresourcePrefetchBrowserTest,
                        MainResourceSXGAndScriptSXG_CrossOrigin_AsDocument) {
   // This test is almost same as MainResourceSXGAndScriptSXG_CrossOrigin. The
   // only difference is that the <link rel=prefetch> element has "as=document"
@@ -1202,7 +1224,7 @@
       "publisher.example.com" /* inner_url_hostname */,
       "/target.html" /* page_inner_url_path */,
       "/script.js" /* script_inner_url_path */,
-      {} /* script_sxg_outer_headers */,
+      {{"Access-Control-Allow-Origin", "*"}} /* script_sxg_outer_headers */,
       "as='document'" /* additional_link_element_attributes */,
       0 /* elapsed_time_after_prefetch */, "done" /* expected_title */,
       true /* script_sxg_should_be_stored */,
@@ -1223,7 +1245,7 @@
       "publisher.example.com" /* inner_url_hostname */,
       "/target.html" /* page_inner_url_path */,
       "/script.js" /* script_inner_url_path */,
-      {} /* script_sxg_outer_headers */,
+      {{"Access-Control-Allow-Origin", "*"}} /* script_sxg_outer_headers */,
       "" /* additional_link_element_attributes */,
       0 /* elapsed_time_after_prefetch */, "from server" /* expected_title */,
       true /* script_sxg_should_be_stored */,
@@ -1898,16 +1920,16 @@
   RegisterRequestHandler(embedded_test_server());
   RegisterRequestHandler(data_server.get());
 
-  // Prefetch requests for alternate SXG should be made with no-cors,
-  // regardless of the crossorigin attribute of Link:rel=preload header that
-  // triggered the prefetch.
+  // Prefetch requests for alternate SXG should be made with cors, regardless of
+  // the crossorigin attribute of Link:rel=preload header that triggered the
+  // prefetch.
   embedded_test_server()->RegisterRequestMonitor(
       base::BindRepeating([](const net::test_server::HttpRequest& request) {
         if (!base::EndsWith(request.relative_url, "_data.sxg"))
           return;
         auto it = request.headers.find("Sec-Fetch-Mode");
         ASSERT_TRUE(it != request.headers.end());
-        EXPECT_EQ(it->second, "no-cors");
+        EXPECT_EQ(it->second, "cors");
       }));
 
   ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 987b3d9a..b822b43d 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -465,20 +465,18 @@
 }
 
 std::unique_ptr<WebAudioDevice> RendererBlinkPlatformImpl::CreateAudioDevice(
-    unsigned input_channels,
-    unsigned channels,
+    unsigned output_channels,
     const blink::WebAudioLatencyHint& latency_hint,
-    WebAudioDevice::RenderCallback* callback,
-    const blink::WebString& input_device_id) {
-  // The |channels| does not exactly identify the channel layout of the
+    WebAudioDevice::RenderCallback* callback) {
+  // The |output_channels| does not exactly identify the channel layout of the
   // device. The switch statement below assigns a best guess to the channel
   // layout based on number of channels.
-  media::ChannelLayout layout = media::GuessChannelLayout(channels);
+  media::ChannelLayout layout = media::GuessChannelLayout(output_channels);
   if (layout == media::CHANNEL_LAYOUT_UNSUPPORTED)
     layout = media::CHANNEL_LAYOUT_DISCRETE;
 
   return RendererWebAudioDeviceImpl::Create(
-      layout, channels, latency_hint, callback,
+      layout, output_channels, latency_hint, callback,
       /*session_id=*/base::UnguessableToken());
 }
 
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 8f4b58d..9718602c 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -116,11 +116,9 @@
   unsigned AudioHardwareOutputChannels() override;
   base::TimeDelta GetHungRendererDelay() override;
   std::unique_ptr<blink::WebAudioDevice> CreateAudioDevice(
-      unsigned input_channels,
-      unsigned channels,
+      unsigned output_channels,
       const blink::WebAudioLatencyHint& latency_hint,
-      blink::WebAudioDevice::RenderCallback* callback,
-      const blink::WebString& input_device_id) override;
+      blink::WebAudioDevice::RenderCallback* callback) override;
   bool DecodeAudioFileData(blink::WebAudioBus* destination_bus,
                            const char* audio_file_data,
                            size_t data_size) override;
diff --git a/content/test/data/service_worker/empty_fetch_event.js b/content/test/data/service_worker/empty_fetch_event.js
new file mode 100644
index 0000000..e05ad54
--- /dev/null
+++ b/content/test/data/service_worker/empty_fetch_event.js
@@ -0,0 +1,5 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+self.addEventListener('fetch', () => {});
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index 1afe471..15d7481 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -1145,7 +1145,7 @@
     # All these tests contain 4 or 8 solid colored rectangles
     # around 50x100 pixels, this should account for possible antialiasing and
     # color cenversion during RGB<->YUV conversions.
-    match_algo = algo.SobelMatchingAlgorithm(max_different_pixels=5000,
+    match_algo = algo.SobelMatchingAlgorithm(max_different_pixels=11000,
                                              pixel_delta_threshold=50,
                                              edge_threshold=30,
                                              ignored_border_thickness=1)
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index b496fc78..0a07392f 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -635,19 +635,19 @@
 # AMD Radeon HD 7800 GPU (1002:679e)
 crbug.com/1276186 [ mac amd-0x679e angle-opengl passthrough ] conformance/rendering/clear-default-framebuffer-with-scissor-test.html [ Failure ]
 crbug.com/1240443 [ mac amd-0x679e angle-opengl passthrough ] conformance/renderbuffers/stencil-renderbuffer-initialization.html [ Failure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/shaderoperator/binary_operator_14.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturefiltering/3d_combinations_24.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturefiltering/3d_sizes_00.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturefiltering/cube_formats_05.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturefiltering/cube_formats_06.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturefiltering/cube_no_edges_visible.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/basic_teximage3d_2d_array_00.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/basic_texsubimage2d_cube_04.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/teximage2d_depth.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/teximage2d_pbo_cube_00.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/teximage3d_depth.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/texstorage2d_format_cube_01.html [ RetryOnFailure ]
-crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/texstorage3d_format_depth_stencil.html [ RetryOnFailure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/shaderoperator/binary_operator_14.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturefiltering/3d_combinations_24.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturefiltering/3d_sizes_00.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturefiltering/cube_formats_05.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturefiltering/cube_formats_06.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturefiltering/cube_no_edges_visible.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/basic_teximage3d_2d_array_00.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/basic_texsubimage2d_cube_04.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/teximage2d_depth.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/teximage2d_pbo_cube_00.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/teximage3d_depth.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/texstorage2d_format_cube_01.html [ Failure ]
+crbug.com/1345755 [ mac amd-0x679e angle-opengl passthrough ] deqp/functional/gles3/texturespecification/texstorage3d_format_depth_stencil.html [ Failure ]
 
 # Mac / M1 / OpenGL
 crbug.com/1130112 [ mac apple-apple-m1 passthrough angle-opengl ] deqp/functional/gles3/texturefiltering/cube_combinations_00.html [ Failure ]
diff --git a/docs/speed/perf_lab_platforms.md b/docs/speed/perf_lab_platforms.md
index 0ec56edb..5006fe7 100644
--- a/docs/speed/perf_lab_platforms.md
+++ b/docs/speed/perf_lab_platforms.md
@@ -28,6 +28,11 @@
  * [lacros-eve-perf](https://ci.chromium.org/p/chrome/builders/ci/lacros-eve-perf): .
  * [lacros-x86-perf](https://ci.chromium.org/p/chrome/builders/ci/lacros-x86-perf): .
 
+## Fuchsia
+
+ * [fuchsia-perf-ast](https://ci.chromium.org/p/chrome/builders/ci/fuchsia-perf-ast): .
+ * [fuchsia-perf-shk](https://ci.chromium.org/p/chrome/builders/ci/fuchsia-perf-shk): .
+
 ## Linux
 
  * [linux-perf](https://ci.chromium.org/p/chrome/builders/ci/linux-perf): Ubuntu-18.04, 8 core, NVIDIA Quadro P400.
diff --git a/extensions/browser/api/socket/app_firewall_hole_manager.cc b/extensions/browser/api/socket/app_firewall_hole_manager.cc
index 6c6ab50..af0edb3 100644
--- a/extensions/browser/api/socket/app_firewall_hole_manager.cc
+++ b/extensions/browser/api/socket/app_firewall_hole_manager.cc
@@ -11,7 +11,7 @@
 #include "content/public/browser/browser_context.h"
 #include "extensions/browser/app_window/app_window.h"
 
-using chromeos::FirewallHole;
+using ::ash::FirewallHole;
 using content::BrowserContext;
 
 namespace extensions {
diff --git a/extensions/browser/api/socket/app_firewall_hole_manager.h b/extensions/browser/api/socket/app_firewall_hole_manager.h
index 93d6f19..730ac44 100644
--- a/extensions/browser/api/socket/app_firewall_hole_manager.h
+++ b/extensions/browser/api/socket/app_firewall_hole_manager.h
@@ -27,7 +27,7 @@
 // closed on destruction.
 class AppFirewallHole {
  public:
-  using PortType = chromeos::FirewallHole::PortType;
+  using PortType = ::ash::FirewallHole::PortType;
 
   ~AppFirewallHole();
 
@@ -44,8 +44,7 @@
                   const std::string& extension_id);
 
   void SetVisible(bool app_visible);
-  void OnFirewallHoleOpened(
-      std::unique_ptr<chromeos::FirewallHole> firewall_hole);
+  void OnFirewallHoleOpened(std::unique_ptr<ash::FirewallHole> firewall_hole);
 
   PortType type_;
   uint16_t port_;
@@ -55,7 +54,7 @@
   base::WeakPtr<AppFirewallHoleManager> manager_;
 
   // This will hold the FirewallHole object if one is opened.
-  std::unique_ptr<chromeos::FirewallHole> firewall_hole_;
+  std::unique_ptr<ash::FirewallHole> firewall_hole_;
 
   base::WeakPtrFactory<AppFirewallHole> weak_factory_{this};
 };
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 3903ce0d..12651ab4 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -75107,7 +75107,7 @@
       }
       experiments {
         key: "luci.buildbucket.omit_python2"
-        value: 100
+        value: 0
       }
       experiments {
         key: "luci.recipes.use_python3"
@@ -76086,7 +76086,7 @@
       }
       experiments {
         key: "luci.buildbucket.omit_python2"
-        value: 100
+        value: 0
       }
       experiments {
         key: "luci.recipes.use_python3"
diff --git a/infra/config/generated/luci/project.cfg b/infra/config/generated/luci/project.cfg
index 4c731471..c23bdfa 100644
--- a/infra/config/generated/luci/project.cfg
+++ b/infra/config/generated/luci/project.cfg
@@ -7,7 +7,7 @@
 name: "chromium"
 access: "group:all"
 lucicfg {
-  version: "1.31.5"
+  version: "1.32.1"
   package_dir: "../.."
   config_dir: "generated/luci"
   entry_point: "main.star"
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
index b508b052..93d4963 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.mac.star
@@ -114,7 +114,7 @@
     main_list_view = "try",
     os = os.MAC_DEFAULT,
     experiments = {
-        "luci.buildbucket.omit_python2": 100,
+        "luci.buildbucket.omit_python2": 0,
     },
 )
 
@@ -150,7 +150,7 @@
     # TODO (crbug.com/1245171): Revert when root issue is fixed
     grace_period = 4 * time.minute,
     experiments = {
-        "luci.buildbucket.omit_python2": 100,
+        "luci.buildbucket.omit_python2": 0,
     },
 )
 
diff --git a/ios/chrome/browser/autofill/form_structure_browsertest.mm b/ios/chrome/browser/autofill/form_structure_browsertest.mm
index c8eaccd..8b739f3 100644
--- a/ios/chrome/browser/autofill/form_structure_browsertest.mm
+++ b/ios/chrome/browser/autofill/form_structure_browsertest.mm
@@ -198,7 +198,9 @@
        // TODO(crbug.com/1190334): Remove once launched.
        autofill::features::kAutofillParseMerchantPromoCodeFields,
        // TODO(crbug.com/1113970): Remove once launched.
-       features::kAutofillSectionUponRedundantNameInfo},
+       features::kAutofillSectionUponRedundantNameInfo,
+       // TODO(crbug.com/1335549): Remove once launched.
+       autofill::features::kAutofillParseIBANFields},
       // Disabled
       {});
 }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_util.mm b/ios/chrome/browser/ui/omnibox/omnibox_util.mm
index c4e1fb6..61641aa 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_util.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_util.mm
@@ -69,6 +69,7 @@
     case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
     case AutocompleteMatchType::TILE_SUGGESTION:
     case AutocompleteMatchType::TILE_NAVSUGGEST:
+    case AutocompleteMatchType::NULL_RESULT_MESSAGE:
     case AutocompleteMatchType::NUM_TYPES:
       NOTREACHED();
       return DEFAULT_FAVICON;
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm
index a940e8d..5f18db3e 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm
@@ -85,6 +85,7 @@
     case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
     case AutocompleteMatchType::TILE_SUGGESTION:
     case AutocompleteMatchType::TILE_NAVSUGGEST:
+    case AutocompleteMatchType::NULL_RESULT_MESSAGE:
     case AutocompleteMatchType::NUM_TYPES:
       NOTREACHED();
       return DEFAULT_FAVICON;
diff --git a/sandbox/linux/services/syscall_wrappers_unittest.cc b/sandbox/linux/services/syscall_wrappers_unittest.cc
index 723ff3b..5664e53b 100644
--- a/sandbox/linux/services/syscall_wrappers_unittest.cc
+++ b/sandbox/linux/services/syscall_wrappers_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/logging.h"
 #include "base/memory/page_size.h"
 #include "base/posix/eintr_wrapper.h"
+#include "base/system/sys_info.h"
 #include "build/build_config.h"
 #include "sandbox/linux/system_headers/linux_signal.h"
 #include "sandbox/linux/system_headers/linux_stat.h"
@@ -245,16 +246,6 @@
     GTEST_FAIL();
   }
 
-  struct kernel_stat stat_info;
-  rc = sys_stat(symlink_name.c_str(), &stat_info);
-  if (rc < 0 && errno == EOVERFLOW) {
-    GTEST_SKIP();
-  }
-  if (rc != 0) {
-    PLOG(ERROR) << "Couldn't sys_stat " << symlink_name;
-    GTEST_FAIL();
-  }
-
   struct kernel_stat tmp_file_stat_info;
   rc = sys_stat(tmp_file.full_file_name(), &tmp_file_stat_info);
   if (rc < 0 && errno == EOVERFLOW) {
@@ -268,6 +259,24 @@
   // lstat should produce information about a symlink.
   ASSERT_TRUE(S_ISLNK(lstat_info.st_mode));
 
+// /tmp is mounted with nosymfollow on ChromeOS so calling
+// sys_stat leads to an error.
+#if BUILDFLAG(IS_CHROMEOS)
+  if (base::SysInfo::IsRunningOnChromeOS()) {
+    GTEST_SKIP();
+  }
+#endif
+
+  struct kernel_stat stat_info;
+  rc = sys_stat(symlink_name.c_str(), &stat_info);
+  if (rc < 0 && errno == EOVERFLOW) {
+    GTEST_SKIP();
+  }
+  if (rc != 0) {
+    PLOG(ERROR) << "Couldn't sys_stat " << symlink_name;
+    GTEST_FAIL();
+  }
+
   // stat-ing symlink_name and tmp_file should produce the same inode.
   ASSERT_EQ(stat_info.st_ino, tmp_file_stat_info.st_ino);
 
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index 85ab279..2a5d947 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -7889,6 +7889,5010 @@
       }
     ]
   },
+  "android-pie-x86-fyi-rel-reviver": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "absl_hardening_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "absl_hardening_tests",
+        "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "android_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "android_browsertests",
+        "test_id_prefix": "ninja://chrome/test:android_browsertests/"
+      },
+      {
+        "args": [
+          "--test-launcher-batch-limit=1",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "android_sync_integration_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "android_sync_integration_tests",
+        "test_id_prefix": "ninja://chrome/test:android_sync_integration_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "android_webview_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "android_webview_unittests",
+        "test_id_prefix": "ninja://android_webview/test:android_webview_unittests/"
+      },
+      {
+        "args": [
+          "-v",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "angle_unittests",
+        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/",
+        "use_isolated_scripts_api": true
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "base_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "base_unittests",
+        "test_id_prefix": "ninja://base:base_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "blink_common_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "blink_common_unittests",
+        "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "blink_heap_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "blink_heap_unittests",
+        "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "blink_platform_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "blink_platform_unittests",
+        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webkit_unit_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "webkit_unit_tests",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 6
+        },
+        "test": "blink_unittests",
+        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "boringssl_crypto_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "boringssl_crypto_tests",
+        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "boringssl_ssl_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "boringssl_ssl_tests",
+        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "breakpad_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "breakpad_unittests",
+        "test_id_prefix": "ninja://third_party/breakpad:breakpad_unittests/"
+      },
+      {
+        "args": [
+          "--gtest_filter=-*UsingRealWebcam*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "capture_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "capture_unittests",
+        "test_id_prefix": "ninja://media/capture:capture_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cast_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "cast_unittests",
+        "test_id_prefix": "ninja://media/cast:cast_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "cc_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "cc_unittests",
+        "test_id_prefix": "ninja://cc:cc_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_java_test_pagecontroller_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "chrome_java_test_pagecontroller_tests",
+        "test_id_prefix": "ninja://chrome/test/android:chrome_java_test_pagecontroller_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "chrome_public_smoke_test",
+        "test_id_prefix": "ninja://chrome/android:chrome_public_smoke_test/"
+      },
+      {
+        "args": [
+          "--gtest_filter=-org.chromium.chrome.browser.contextualsearch.ContextualSearchManagerTest.test*ExternalNavigationWithUserGesture*:org.chromium.shape_detection.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests",
+          "--git-revision=${got_revision}"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "precommit_args": [
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
+        ],
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "e2-standard-8",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 20
+        },
+        "test": "chrome_public_test_apk",
+        "test_id_prefix": "ninja://chrome/android:chrome_public_test_apk/"
+      },
+      {
+        "args": [
+          "--gtest_filter=org.chromium.chrome.browser.contextualsearch.ContextualSearchManagerTest.test*ExternalNavigationWithUserGesture*:org.chromium.shape_detection.*",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests",
+          "--git-revision=${got_revision}"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_test_apk_with_playstore"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "chrome_public_test_apk_with_playstore",
+        "precommit_args": [
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
+        ],
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "chrome_public_test_apk",
+        "test_id_prefix": "ninja://chrome/android:chrome_public_test_apk/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests",
+          "--git-revision=${got_revision}"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "chrome_public_unit_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "precommit_args": [
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}"
+        ],
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 4
+        },
+        "test": "chrome_public_unit_test_apk",
+        "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "components_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "components_browsertests",
+        "test_id_prefix": "ninja://components:components_browsertests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "components_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 6
+        },
+        "test": "components_unittests",
+        "test_id_prefix": "ninja://components:components_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 15
+        },
+        "test": "content_browsertests",
+        "test_id_prefix": "ninja://content/test:content_browsertests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_shell_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 3
+        },
+        "test": "content_shell_test_apk",
+        "test_id_prefix": "ninja://content/shell/android:content_shell_test_apk/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "content_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 3
+        },
+        "test": "content_unittests",
+        "test_id_prefix": "ninja://content/test:content_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "crashpad_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "crashpad_tests",
+        "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "crypto_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "crypto_unittests",
+        "test_id_prefix": "ninja://crypto:crypto_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "device_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "device_unittests",
+        "test_id_prefix": "ninja://device:device_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "display_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "display_unittests",
+        "test_id_prefix": "ninja://ui/display:display_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "events_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "events_unittests",
+        "test_id_prefix": "ninja://ui/events:events_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "gcm_unit_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gcm_unit_tests",
+        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "gfx_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gfx_unittests",
+        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "gin_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gin_unittests",
+        "test_id_prefix": "ninja://gin:gin_unittests/"
+      },
+      {
+        "args": [
+          "--use-cmd-decoder=validating",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "gl_tests_validating"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "gl_tests_validating",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gl_tests",
+        "test_id_prefix": "ninja://gpu:gl_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "gl_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gl_unittests",
+        "test_id_prefix": "ninja://ui/gl:gl_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "google_apis_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "google_apis_unittests",
+        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "gpu_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gpu_unittests",
+        "test_id_prefix": "ninja://gpu:gpu_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "gwp_asan_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "gwp_asan_unittests",
+        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "ipc_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ipc_tests",
+        "test_id_prefix": "ninja://ipc:ipc_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "latency_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "latency_unittests",
+        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "libjingle_xmpp_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "libjingle_xmpp_unittests",
+        "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "liburlpattern_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "liburlpattern_unittests",
+        "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "media_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "media_unittests",
+        "test_id_prefix": "ninja://media:media_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "midi_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "midi_unittests",
+        "test_id_prefix": "ninja://media/midi:midi_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "mojo_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "mojo_test_apk",
+        "test_id_prefix": "ninja://mojo/public/java/system:mojo_test_apk/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "mojo_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "mojo_unittests",
+        "test_id_prefix": "ninja://mojo:mojo_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "monochrome_public_bundle_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "monochrome_public_bundle_smoke_test",
+        "test_id_prefix": "ninja://chrome/android:monochrome_public_bundle_smoke_test/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "monochrome_public_smoke_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "monochrome_public_smoke_test",
+        "test_id_prefix": "ninja://chrome/android:monochrome_public_smoke_test/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "net_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 3
+        },
+        "test": "net_unittests",
+        "test_id_prefix": "ninja://net:net_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "perfetto_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "perfetto_unittests",
+        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "sandbox_linux_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "sandbox_linux_unittests",
+        "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "services_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "services_unittests",
+        "test_id_prefix": "ninja://services:services_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "shell_dialogs_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "shell_dialogs_unittests",
+        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "skia_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "skia_unittests",
+        "test_id_prefix": "ninja://skia:skia_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "sql_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "sql_unittests",
+        "test_id_prefix": "ninja://sql:sql_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "storage_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "storage_unittests",
+        "test_id_prefix": "ninja://storage:storage_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "system_webview_shell_layout_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "system_webview_shell_layout_test_apk",
+        "test_id_prefix": "ninja://android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "ui_android_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ui_android_unittests",
+        "test_id_prefix": "ninja://ui/android:ui_android_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "ui_base_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ui_base_unittests",
+        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "ui_touch_selection_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "ui_touch_selection_unittests",
+        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "unit_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "unit_tests",
+        "test_id_prefix": "ninja://chrome/test:unit_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "url_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "url_unittests",
+        "test_id_prefix": "ninja://url:url_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "viz_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "viz_unittests",
+        "test_id_prefix": "ninja://components/viz:viz_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_browsertests",
+        "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_bundle_test"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_bundle_test",
+        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_bundle_test/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_instrumentation_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_instrumentation_test_apk",
+        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_apk/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_private_instrumentation_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_private_instrumentation_test_apk",
+        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_private_instrumentation_test_apk/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "weblayer_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "weblayer_unittests",
+        "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_cts_tests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "chromium/android_webview/tools/cts_archive",
+              "location": "android_webview/tools/cts_archive",
+              "revision": "qF6dhyFMW7qFOzHo_Lu-bWxpbe-zRfL1KvHPQtQA3d0C"
+            },
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "webview_cts_tests",
+        "test_id_prefix": "ninja://android_webview/test:webview_cts_tests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_instrumentation_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 7
+        },
+        "test": "webview_instrumentation_test_apk",
+        "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "webview_ui_test_app_test_apk"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "webview_ui_test_app_test_apk",
+        "test_id_prefix": "ninja://android_webview/tools/automated_ui_tests:webview_ui_test_app_test_apk/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "wtf_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "wtf_unittests",
+        "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/"
+      },
+      {
+        "args": [
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices",
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "zlib_unittests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "cipd_packages": [
+            {
+              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
+              "location": "bin",
+              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
+            }
+          ],
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "device_os": null,
+              "device_type": null,
+              "machine_type": "n1-standard-4|e2-standard-4",
+              "os": "Ubuntu-18.04",
+              "pool": "chromium.tests.avd"
+            }
+          ],
+          "named_caches": [
+            {
+              "name": "generic_android28",
+              "path": ".android_emulator/generic_android28"
+            }
+          ],
+          "optional_dimensions": {
+            "60": [
+              {
+                "caches": "generic_android28"
+              }
+            ]
+          },
+          "output_links": [
+            {
+              "link": [
+                "https://luci-logdog.appspot.com/v/?s",
+                "=android%2Fswarming%2Flogcats%2F",
+                "${TASK_ID}%2F%2B%2Funified_logcats"
+              ],
+              "name": "shard #${SHARD_INDEX} logcats"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "zlib_unittests",
+        "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/"
+      }
+    ],
+    "scripts": [
+      {
+        "args": [
+          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
+          "--gtest_also_run_disabled_tests"
+        ],
+        "name": "check_network_annotations",
+        "resultdb": {
+          "enable": true,
+          "has_native_resultdb_integration": true
+        },
+        "script": "check_network_annotations.py",
+        "swarming": {}
+      }
+    ]
+  },
   "android-weblayer-11-x86-rel-tests": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 1928ece..bee67d3 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -41302,5010 +41302,6 @@
       }
     ]
   },
-  "android-pie-x86-fyi-rel-reviver": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "absl_hardening_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "absl_hardening_tests",
-        "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "android_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "android_browsertests",
-        "test_id_prefix": "ninja://chrome/test:android_browsertests/"
-      },
-      {
-        "args": [
-          "--test-launcher-batch-limit=1",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "android_sync_integration_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "android_sync_integration_tests",
-        "test_id_prefix": "ninja://chrome/test:android_sync_integration_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "android_webview_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "android_webview_unittests",
-        "test_id_prefix": "ninja://android_webview/test:android_webview_unittests/"
-      },
-      {
-        "args": [
-          "-v",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_unittests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_unittests",
-        "test_id_prefix": "ninja://base:base_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "blink_common_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_common_unittests",
-        "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "blink_heap_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_heap_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "blink_platform_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_platform_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webkit_unit_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "webkit_unit_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "blink_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "boringssl_crypto_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_crypto_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "boringssl_ssl_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_ssl_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "breakpad_unittests",
-        "test_id_prefix": "ninja://third_party/breakpad:breakpad_unittests/"
-      },
-      {
-        "args": [
-          "--gtest_filter=-*UsingRealWebcam*",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "capture_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "capture_unittests",
-        "test_id_prefix": "ninja://media/capture:capture_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cast_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cast_unittests",
-        "test_id_prefix": "ninja://media/cast:cast_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cc_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cc_unittests",
-        "test_id_prefix": "ninja://cc:cc_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_java_test_pagecontroller_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_java_test_pagecontroller_tests",
-        "test_id_prefix": "ninja://chrome/test/android:chrome_java_test_pagecontroller_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_smoke_test"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_public_smoke_test",
-        "test_id_prefix": "ninja://chrome/android:chrome_public_smoke_test/"
-      },
-      {
-        "args": [
-          "--gtest_filter=-org.chromium.chrome.browser.contextualsearch.ContextualSearchManagerTest.test*ExternalNavigationWithUserGesture*:org.chromium.shape_detection.*",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests",
-          "--git-revision=${got_revision}"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "e2-standard-8",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 20
-        },
-        "test": "chrome_public_test_apk",
-        "test_id_prefix": "ninja://chrome/android:chrome_public_test_apk/"
-      },
-      {
-        "args": [
-          "--gtest_filter=org.chromium.chrome.browser.contextualsearch.ContextualSearchManagerTest.test*ExternalNavigationWithUserGesture*:org.chromium.shape_detection.*",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests",
-          "--git-revision=${got_revision}"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_test_apk_with_playstore"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "chrome_public_test_apk_with_playstore",
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_public_test_apk",
-        "test_id_prefix": "ninja://chrome/android:chrome_public_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests",
-          "--git-revision=${got_revision}"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_unit_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test": "chrome_public_unit_test_apk",
-        "test_id_prefix": "ninja://chrome/android:chrome_public_unit_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_browsertests",
-        "test_id_prefix": "ninja://components:components_browsertests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 15
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_shell_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "content_shell_test_apk",
-        "test_id_prefix": "ninja://content/shell/android:content_shell_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "content_unittests",
-        "test_id_prefix": "ninja://content/test:content_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "crashpad_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crashpad_tests",
-        "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "crypto_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crypto_unittests",
-        "test_id_prefix": "ninja://crypto:crypto_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "device_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "device_unittests",
-        "test_id_prefix": "ninja://device:device_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "display_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "display_unittests",
-        "test_id_prefix": "ninja://ui/display:display_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "events_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "events_unittests",
-        "test_id_prefix": "ninja://ui/events:events_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gcm_unit_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gcm_unit_tests",
-        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gfx_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gfx_unittests",
-        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gin_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gin_unittests",
-        "test_id_prefix": "ninja://gin:gin_unittests/"
-      },
-      {
-        "args": [
-          "--use-cmd-decoder=validating",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_tests_validating"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "gl_tests_validating",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_tests",
-        "test_id_prefix": "ninja://gpu:gl_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_unittests",
-        "test_id_prefix": "ninja://ui/gl:gl_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "google_apis_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "google_apis_unittests",
-        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gpu_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gpu_unittests",
-        "test_id_prefix": "ninja://gpu:gpu_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gwp_asan_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gwp_asan_unittests",
-        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ipc_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ipc_tests",
-        "test_id_prefix": "ninja://ipc:ipc_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "latency_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "latency_unittests",
-        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "libjingle_xmpp_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "libjingle_xmpp_unittests",
-        "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "liburlpattern_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "liburlpattern_unittests",
-        "test_id_prefix": "ninja://third_party/liburlpattern:liburlpattern_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "media_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_unittests",
-        "test_id_prefix": "ninja://media:media_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "midi_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "midi_unittests",
-        "test_id_prefix": "ninja://media/midi:midi_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "mojo_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_test_apk",
-        "test_id_prefix": "ninja://mojo/public/java/system:mojo_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "mojo_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_unittests",
-        "test_id_prefix": "ninja://mojo:mojo_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "monochrome_public_bundle_smoke_test"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "monochrome_public_bundle_smoke_test",
-        "test_id_prefix": "ninja://chrome/android:monochrome_public_bundle_smoke_test/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "monochrome_public_smoke_test"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "monochrome_public_smoke_test",
-        "test_id_prefix": "ninja://chrome/android:monochrome_public_smoke_test/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "net_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "net_unittests",
-        "test_id_prefix": "ninja://net:net_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "perfetto_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "perfetto_unittests",
-        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sandbox_linux_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sandbox_linux_unittests",
-        "test_id_prefix": "ninja://sandbox/linux:sandbox_linux_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "services_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "services_unittests",
-        "test_id_prefix": "ninja://services:services_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "shell_dialogs_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "shell_dialogs_unittests",
-        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "skia_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "skia_unittests",
-        "test_id_prefix": "ninja://skia:skia_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sql_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sql_unittests",
-        "test_id_prefix": "ninja://sql:sql_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "storage_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "storage_unittests",
-        "test_id_prefix": "ninja://storage:storage_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "system_webview_shell_layout_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "system_webview_shell_layout_test_apk",
-        "test_id_prefix": "ninja://android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_android_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_android_unittests",
-        "test_id_prefix": "ninja://ui/android:ui_android_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_base_unittests",
-        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_touch_selection_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_touch_selection_unittests",
-        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "unit_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "unit_tests",
-        "test_id_prefix": "ninja://chrome/test:unit_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "url_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "url_unittests",
-        "test_id_prefix": "ninja://url:url_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "viz_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "viz_unittests",
-        "test_id_prefix": "ninja://components/viz:viz_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_browsertests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_browsertests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_bundle_test"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_bundle_test",
-        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_bundle_test/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_instrumentation_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_instrumentation_test_apk",
-        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_instrumentation_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_private_instrumentation_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_private_instrumentation_test_apk",
-        "test_id_prefix": "ninja://weblayer/browser/android/javatests:weblayer_private_instrumentation_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "weblayer_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "weblayer_unittests",
-        "test_id_prefix": "ninja://weblayer/test:weblayer_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webview_cts_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "chromium/android_webview/tools/cts_archive",
-              "location": "android_webview/tools/cts_archive",
-              "revision": "qF6dhyFMW7qFOzHo_Lu-bWxpbe-zRfL1KvHPQtQA3d0C"
-            },
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "webview_cts_tests",
-        "test_id_prefix": "ninja://android_webview/test:webview_cts_tests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webview_instrumentation_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 7
-        },
-        "test": "webview_instrumentation_test_apk",
-        "test_id_prefix": "ninja://android_webview/test:webview_instrumentation_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webview_ui_test_app_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "webview_ui_test_app_test_apk",
-        "test_id_prefix": "ninja://android_webview/tools/automated_ui_tests:webview_ui_test_app_test_apk/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "wtf_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wtf_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "zlib_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "device_os": null,
-              "device_type": null,
-              "machine_type": "n1-standard-4|e2-standard-4",
-              "os": "Ubuntu-18.04",
-              "pool": "chromium.tests.avd"
-            }
-          ],
-          "named_caches": [
-            {
-              "name": "generic_android28",
-              "path": ".android_emulator/generic_android28"
-            }
-          ],
-          "optional_dimensions": {
-            "60": [
-              {
-                "caches": "generic_android28"
-              }
-            ]
-          },
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "zlib_unittests",
-        "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/"
-      }
-    ],
-    "scripts": [
-      {
-        "args": [
-          "--avd-config=../../tools/android/avd/proto/generic_android28.textpb",
-          "--gtest_also_run_disabled_tests"
-        ],
-        "name": "check_network_annotations",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "script": "check_network_annotations.py",
-        "swarming": {}
-      }
-    ]
-  },
   "android-pie-x86-rel": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index 3fb035a5..1336d4c 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -186,12 +186,6 @@
       "base_perftests"
     ]
   },
-  "fuchsia-builder-perf-x64": {
-    "additional_compile_targets": [
-      "chrome_pkg",
-      "base_perftests"
-    ]
-  },
   "fuchsia-perf-atlas-fyi": {
     "isolated_scripts": [
       {
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 6d65684..bfb6a39 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -1353,6 +1353,125 @@
       }
     ]
   },
+  "fuchsia-builder-perf-arm64": {
+    "additional_compile_targets": [
+      "web_engine_shell_pkg",
+      "cast_runner_pkg",
+      "web_runner_pkg",
+      "chromium_builder_perf",
+      "base_perftests"
+    ]
+  },
+  "fuchsia-builder-perf-x64": {
+    "additional_compile_targets": [
+      "chrome_pkg",
+      "base_perftests"
+    ]
+  },
+  "fuchsia-perf-ast": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "-v",
+          "--browser=web-engine-shell",
+          "--upload-results",
+          "--test-shard-map-filename=fuchsia-perf-ast_map.json",
+          "--output-format=histograms",
+          "--experimental-tbmv3-metrics",
+          "-d",
+          "--os-check=update",
+          "--system-image-dir=../../third_party/fuchsia-sdk/images-internal/astro-release/smart_display_eng_arrested"
+        ],
+        "isolate_name": "performance_web_engine_test_suite",
+        "merge": {
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "performance_web_engine_test_suite",
+        "override_compile_targets": [
+          "performance_web_engine_test_suite"
+        ],
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": null,
+              "device_type": "Astro",
+              "os": "Fuchsia",
+              "pool": "chrome.tests"
+            }
+          ],
+          "expiration": 7200,
+          "hard_timeout": 21600,
+          "io_timeout": 21600,
+          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 1
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "requires_simultaneous_shard_dispatch": true,
+          "script": "//testing/trigger_scripts/perf_device_trigger.py"
+        }
+      }
+    ]
+  },
+  "fuchsia-perf-shk": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "-v",
+          "--browser=web-engine-shell",
+          "--upload-results",
+          "--test-shard-map-filename=fuchsia-perf-shk_map.json",
+          "--output-format=histograms",
+          "--experimental-tbmv3-metrics",
+          "-d",
+          "--os-check=update",
+          "--system-image-dir=../../third_party/fuchsia-sdk/images-internal/sherlock-release/smart_display_max_eng_arrested"
+        ],
+        "isolate_name": "performance_web_engine_test_suite",
+        "merge": {
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "performance_web_engine_test_suite",
+        "override_compile_targets": [
+          "performance_web_engine_test_suite"
+        ],
+        "resultdb": {
+          "enable": true
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": null,
+              "device_type": "Sherlock",
+              "os": "Fuchsia",
+              "pool": "chrome.tests"
+            }
+          ],
+          "expiration": 7200,
+          "hard_timeout": 21600,
+          "io_timeout": 21600,
+          "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 1
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "requires_simultaneous_shard_dispatch": true,
+          "script": "//testing/trigger_scripts/perf_device_trigger.py"
+        }
+      }
+    ]
+  },
   "lacros-eve-perf": {
     "isolated_scripts": [
       {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 27a028b..cc58025 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1050,24 +1050,6 @@
         'use_swarming': True,
         'os_type': 'android',
       },
-      # A builder for early prototype of test-reviver in Clank.
-      # TODO(crbug.com/1348392): Remove this builder once we have a way to reuse
-      # the built binaries or a formal solution for test-reviver.
-      'android-pie-x86-fyi-rel-reviver': {
-        'mixins': [
-          'has_native_resultdb_integration',
-          'pie-x86-emulator',
-          'emulator-4-cores',
-          'linux-bionic',
-          'x86-64',
-          'gtest_run_disabled',
-        ],
-        'os_type': 'android',
-        'test_suites': {
-          'gtest_tests': 'android_pie_rel_emulator_gtests',
-          'scripts': 'chromium_android_scripts',
-        }
-      },
       'android-pie-x86-rel': {
         'mixins': [
           'has_native_resultdb_integration',
@@ -1258,6 +1240,24 @@
         'use_swarming': True,
         'os_type': 'android',
       },
+      # A builder for early prototype of test-reviver in Clank.
+      # TODO(crbug.com/1348392): Remove this builder once we have a way to reuse
+      # the built binaries or a formal solution for test-reviver.
+      'android-pie-x86-fyi-rel-reviver': {
+        'mixins': [
+          'has_native_resultdb_integration',
+          'pie-x86-emulator',
+          'emulator-4-cores',
+          'linux-bionic',
+          'x86-64',
+          'gtest_run_disabled',
+        ],
+        'os_type': 'android',
+        'test_suites': {
+          'gtest_tests': 'android_pie_rel_emulator_gtests',
+          'scripts': 'chromium_android_scripts',
+        }
+      },
       'android-weblayer-11-x86-rel-tests': {
         'mixins': [
           'has_native_resultdb_integration',
diff --git a/third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_type.mojom b/third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_type.mojom
index e671a30e..8309a24 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_type.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_type.mojom
@@ -9,4 +9,5 @@
 enum ServiceWorkerFetchHandlerType {
   kNoHandler,
   kNotSkippable,
+  kEmptyFetchHandler,
 };
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index bc4f144b..ad34b623 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -200,21 +200,11 @@
   virtual unsigned AudioHardwareOutputChannels() { return 0; }
   virtual base::TimeDelta GetHungRendererDelay() { return base::TimeDelta(); }
 
-  // SavableResource ----------------------------------------------------
-
-  virtual bool IsURLSavableForSavableResource(const WebURL& url) {
-    return false;
-  }
-
-  // Creates a device for audio I/O.
-  // Pass in (number_of_input_channels > 0) if live/local audio input is
-  // desired.
+  // Creates an audio output device platform interface for Web Audio API.
   virtual std::unique_ptr<WebAudioDevice> CreateAudioDevice(
-      unsigned number_of_input_channels,
-      unsigned number_of_channels,
+      unsigned number_of_output_channels,
       const WebAudioLatencyHint& latency_hint,
-      WebAudioDevice::RenderCallback*,
-      const WebString& device_id) {
+      WebAudioDevice::RenderCallback*) {
     return nullptr;
   }
 
@@ -325,6 +315,12 @@
     return WebString();
   }
 
+  // SavableResource ----------------------------------------------------
+
+  virtual bool IsURLSavableForSavableResource(const WebURL& url) {
+    return false;
+  }
+
   // Threads -------------------------------------------------------
 
   // The two compositor-related functions below are called by the embedder.
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader.cc b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
index c31d5e5..57948b7a 100644
--- a/third_party/blink/renderer/core/frame/attribution_src_loader.cc
+++ b/third_party/blink/renderer/core/frame/attribution_src_loader.cc
@@ -45,6 +45,7 @@
 #include "third_party/blink/renderer/platform/network/http_names.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
@@ -102,6 +103,12 @@
                 /*invalid_parameter=*/json);
 }
 
+bool IsValidReportingOrigin(const SecurityOrigin* origin) {
+  return origin && origin->IsPotentiallyTrustworthy() &&
+         (origin->Protocol() == WTF::g_https_atom ||
+          origin->Protocol() == WTF::g_http_atom);
+}
+
 }  // namespace
 
 bool CanRegisterAttributionInContext(LocalFrame* frame,
@@ -189,17 +196,18 @@
     return attribution_src_token_;
   }
 
-  // Public, may be called if a response was received prior to the client being
-  // added to the resource.
-  void HandleResponseHeaders(const ResourceResponse& response,
-                             uint64_t request_id);
+  void HandleResponseHeaders(
+      scoped_refptr<const SecurityOrigin> reporting_origin,
+      const AtomicString& source_json,
+      const AtomicString& trigger_json,
+      uint64_t request_id);
 
   void Finish();
 
  private:
-  [[nodiscard]] bool CheckReportingOrigin(
-      const SecurityOrigin& reporting_origin,
-      uint64_t request_id);
+  void HandleResponseHeaders(const ResourceResponse& response,
+                             uint64_t request_id);
+
   void HandleSourceRegistration(
       const AtomicString& json,
       scoped_refptr<const SecurityOrigin> reporting_origin,
@@ -287,11 +295,8 @@
     return nullptr;
   }
 
-  if (!src_url.ProtocolIsInHTTPFamily())
-    return nullptr;
-
-  if (!UrlCanRegisterAttribution(src_url, element,
-                                 /*request_id=*/absl::nullopt)) {
+  if (!ReportingOriginForUrlIfValid(src_url, element,
+                                    /*request_id=*/absl::nullopt)) {
     return nullptr;
   }
 
@@ -356,7 +361,8 @@
   return client;
 }
 
-bool AttributionSrcLoader::UrlCanRegisterAttribution(
+scoped_refptr<const SecurityOrigin>
+AttributionSrcLoader::ReportingOriginForUrlIfValid(
     const KURL& url,
     HTMLElement* element,
     absl::optional<uint64_t> request_id) {
@@ -364,16 +370,17 @@
   DCHECK(window);
 
   if (!CanRegisterAttributionInContext(local_frame_, element, request_id))
-    return false;
+    return nullptr;
 
   scoped_refptr<const SecurityOrigin> reporting_origin =
       SecurityOrigin::Create(url);
-  if (!reporting_origin->IsPotentiallyTrustworthy()) {
+  if (!url.ProtocolIsInHTTPFamily() ||
+      !reporting_origin->IsPotentiallyTrustworthy()) {
     LogAuditIssue(window,
                   AttributionReportingIssueType::kUntrustworthyReportingOrigin,
                   element, request_id,
                   /*invalid_parameter=*/reporting_origin->ToString());
-    return false;
+    return nullptr;
   }
 
   UseCounter::Count(window, mojom::blink::WebFeature::kConversionAPIAll);
@@ -383,7 +390,7 @@
     UseCounter::Count(window, mojom::blink::WebFeature::kPrivacySandboxAdsAPIs);
   }
 
-  return true;
+  return reporting_origin;
 }
 
 bool AttributionSrcLoader::MaybeRegisterAttributionHeaders(
@@ -415,10 +422,11 @@
 
   const uint64_t request_id = request.InspectorId();
 
-  if (!UrlCanRegisterAttribution(response.CurrentRequestUrl(),
-                                 /*element=*/nullptr, request_id)) {
+  scoped_refptr<const SecurityOrigin> reporting_origin =
+      ReportingOriginForUrlIfValid(response.CurrentRequestUrl(),
+                                   /*element=*/nullptr, request_id);
+  if (!reporting_origin)
     return false;
-  }
 
   SrcType src_type = SrcType::kUndetermined;
 
@@ -476,7 +484,8 @@
 
   auto* client = MakeGarbageCollected<ResourceClient>(
       this, src_type, /*associated_with_navigation=*/false);
-  client->HandleResponseHeaders(response, resource->InspectorId());
+  client->HandleResponseHeaders(std::move(reporting_origin), source_json,
+                                trigger_json, resource->InspectorId());
   client->Finish();
   return true;
 }
@@ -529,17 +538,33 @@
 void AttributionSrcLoader::ResourceClient::HandleResponseHeaders(
     const ResourceResponse& response,
     uint64_t request_id) {
-  scoped_refptr<const SecurityOrigin> reporting_origin =
-      SecurityOrigin::Create(response.CurrentRequestUrl());
-
-  // TODO(apaseltiner): Avoid redundantly retrieving these headers when this
-  // method is invoked from `MaybeRegisterAttributionHeaders()`.
   const auto& headers = response.HttpHeaderFields();
   const AtomicString& source_json =
       headers.Get(http_names::kAttributionReportingRegisterSource);
   const AtomicString& trigger_json =
       headers.Get(http_names::kAttributionReportingRegisterTrigger);
 
+  if (source_json.IsNull() && trigger_json.IsNull())
+    return;
+
+  scoped_refptr<const SecurityOrigin> reporting_origin =
+      loader_->ReportingOriginForUrlIfValid(response.CurrentRequestUrl(),
+                                            /*element=*/nullptr, request_id);
+  if (!reporting_origin)
+    return;
+
+  HandleResponseHeaders(std::move(reporting_origin), source_json, trigger_json,
+                        request_id);
+}
+
+void AttributionSrcLoader::ResourceClient::HandleResponseHeaders(
+    scoped_refptr<const SecurityOrigin> reporting_origin,
+    const AtomicString& source_json,
+    const AtomicString& trigger_json,
+    uint64_t request_id) {
+  DCHECK(IsValidReportingOrigin(reporting_origin.get()));
+  DCHECK(!source_json.IsNull() || !trigger_json.IsNull());
+
   switch (type_) {
     case SrcType::kSource:
       MaybeLogTriggerIgnored(loader_->local_frame_->DomWindow(), request_id,
@@ -585,30 +610,15 @@
   }
 }
 
-bool AttributionSrcLoader::ResourceClient::CheckReportingOrigin(
-    const SecurityOrigin& reporting_origin,
-    uint64_t request_id) {
-  if (reporting_origin.IsPotentiallyTrustworthy())
-    return true;
-
-  LogAuditIssue(loader_->local_frame_->DomWindow(),
-                AttributionReportingIssueType::kUntrustworthyReportingOrigin,
-                /*element=*/nullptr, request_id,
-                /*invalid_parameter=*/reporting_origin.ToString());
-  return false;
-}
-
 void AttributionSrcLoader::ResourceClient::HandleSourceRegistration(
     const AtomicString& json,
     scoped_refptr<const SecurityOrigin> reporting_origin,
     uint64_t request_id) {
   DCHECK_EQ(type_, SrcType::kSource);
-
-  if (!CheckReportingOrigin(*reporting_origin, request_id))
-    return;
+  DCHECK(!json.IsNull());
+  DCHECK(IsValidReportingOrigin(reporting_origin.get()));
 
   auto source_data = mojom::blink::AttributionSourceData::New();
-
   source_data->reporting_origin = std::move(reporting_origin);
 
   if (!attribution_response_parsing::ParseSourceRegistrationHeader(
@@ -628,12 +638,10 @@
     scoped_refptr<const SecurityOrigin> reporting_origin,
     uint64_t request_id) {
   DCHECK_EQ(type_, SrcType::kTrigger);
-
-  if (!CheckReportingOrigin(*reporting_origin, request_id))
-    return;
+  DCHECK(!json.IsNull());
+  DCHECK(IsValidReportingOrigin(reporting_origin.get()));
 
   auto trigger_data = mojom::blink::AttributionTriggerData::New();
-
   trigger_data->reporting_origin = std::move(reporting_origin);
 
   if (!attribution_response_parsing::ParseTriggerRegistrationHeader(
diff --git a/third_party/blink/renderer/core/frame/attribution_src_loader.h b/third_party/blink/renderer/core/frame/attribution_src_loader.h
index 40883fb..04cefcd 100644
--- a/third_party/blink/renderer/core/frame/attribution_src_loader.h
+++ b/third_party/blink/renderer/core/frame/attribution_src_loader.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "base/memory/scoped_refptr.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/inspector/inspector_audits_issue.h"
@@ -24,6 +25,7 @@
 class Resource;
 class ResourceRequest;
 class ResourceResponse;
+class SecurityOrigin;
 
 struct Impression;
 
@@ -76,11 +78,13 @@
                                  SrcType src_type,
                                  bool associated_with_navigation);
 
-  // Returns whether the attribution is allowed to be registered. Devtool issue
-  // might be reported if it's not allowed.
-  bool UrlCanRegisterAttribution(const KURL& url,
-                                 HTMLElement* element,
-                                 absl::optional<uint64_t> request_id);
+  // Returns the reporting origin corresponding to `url` if its protocol is in
+  // the HTTP family, its origin is potentially trustworthy, and attribution is
+  // allowed. Returns `nullptr` and reports a DevTools issue otherwise.
+  scoped_refptr<const SecurityOrigin> ReportingOriginForUrlIfValid(
+      const KURL& url,
+      HTMLElement* element,
+      absl::optional<uint64_t> request_id);
 
   ResourceClient* CreateAndSendRequest(const KURL& src_url,
                                        HTMLElement* element,
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.cc b/third_party/blink/renderer/core/html/html_frame_set_element.cc
index c5d834f8..8e15bd5 100644
--- a/third_party/blink/renderer/core/html/html_frame_set_element.cc
+++ b/third_party/blink/renderer/core/html/html_frame_set_element.cc
@@ -382,8 +382,10 @@
     if (event.type() == event_type_names::kMousedown && event.IsLeftButton()) {
       gfx::PointF local_pos =
           layout_frame_set.AbsoluteToLocalPoint(event.AbsoluteLocation());
-      StartResizing(layout_frame_set.Columns(), local_pos.x(), resize_cols_);
-      StartResizing(layout_frame_set.Rows(), local_pos.y(), resize_rows_);
+      StartResizing(layout_frame_set.Columns().sizes_, local_pos.x(),
+                    resize_cols_);
+      StartResizing(layout_frame_set.Rows().sizes_, local_pos.y(),
+                    resize_rows_);
       if (resize_cols_.IsResizingSplit() || resize_rows_.IsResizingSplit()) {
         SetIsResizing(true);
         return true;
@@ -394,8 +396,10 @@
         (event.type() == event_type_names::kMouseup && event.IsLeftButton())) {
       gfx::PointF local_pos =
           layout_frame_set.AbsoluteToLocalPoint(event.AbsoluteLocation());
-      ContinueResizing(layout_frame_set.Columns(), local_pos.x(), resize_cols_);
-      ContinueResizing(layout_frame_set.Rows(), local_pos.y(), resize_rows_);
+      ContinueResizing(layout_frame_set.Columns().sizes_, local_pos.x(),
+                       resize_cols_);
+      ContinueResizing(layout_frame_set.Rows().sizes_, local_pos.y(),
+                       resize_rows_);
       if (event.type() == event_type_names::kMouseup && event.IsLeftButton()) {
         SetIsResizing(false);
         return true;
@@ -412,19 +416,19 @@
     frame->GetEventHandler().SetResizingFrameSet(is_resizing ? this : nullptr);
 }
 
-void HTMLFrameSetElement::StartResizing(const LayoutFrameSet::GridAxis& axis,
+void HTMLFrameSetElement::StartResizing(const Vector<LayoutUnit>& sizes,
                                         int position,
                                         ResizeAxis& resize_axis) {
-  int split = HitTestSplit(axis, position);
+  int split = HitTestSplit(sizes, position);
   if (!resize_axis.CanResizeSplitAt(split)) {
     resize_axis.split_being_resized_ = ResizeAxis::kNoSplit;
     return;
   }
   resize_axis.split_being_resized_ = split;
-  resize_axis.split_resize_offset_ = position - SplitPosition(axis, split);
+  resize_axis.split_resize_offset_ = position - SplitPosition(sizes, split);
 }
 
-void HTMLFrameSetElement::ContinueResizing(const LayoutFrameSet::GridAxis& axis,
+void HTMLFrameSetElement::ContinueResizing(const Vector<LayoutUnit>& sizes,
                                            int position,
                                            ResizeAxis& resize_axis) {
   if (GetLayoutObject()->NeedsLayout())
@@ -432,17 +436,17 @@
   if (!resize_axis.IsResizingSplit())
     return;
   const int split_index = resize_axis.split_being_resized_;
-  int current_split_position = SplitPosition(axis, split_index);
+  int current_split_position = SplitPosition(sizes, split_index);
   int delta =
       (position - current_split_position) - resize_axis.split_resize_offset_;
   if (!delta)
     return;
   const LayoutUnit original_size_prev =
-      axis.sizes_[split_index - 1] - resize_axis.deltas_[split_index - 1];
+      sizes[split_index - 1] - resize_axis.deltas_[split_index - 1];
   const LayoutUnit original_size_next =
-      axis.sizes_[split_index] - resize_axis.deltas_[split_index];
-  if ((original_size_prev != 0 && axis.sizes_[split_index - 1] + delta <= 0) ||
-      (original_size_next != 0 && axis.sizes_[split_index] - delta <= 0)) {
+      sizes[split_index] - resize_axis.deltas_[split_index];
+  if ((original_size_prev != 0 && sizes[split_index - 1] + delta <= 0) ||
+      (original_size_next != 0 && sizes[split_index] - delta <= 0)) {
     resize_axis.deltas_.Fill(0);
   } else {
     resize_axis.deltas_[split_index - 1] += delta;
@@ -452,34 +456,34 @@
       layout_invalidation_reason::kSizeChanged);
 }
 
-int HTMLFrameSetElement::SplitPosition(const LayoutFrameSet::GridAxis& axis,
+int HTMLFrameSetElement::SplitPosition(const Vector<LayoutUnit>& sizes,
                                        int split) const {
   if (GetLayoutObject()->NeedsLayout())
     return 0;
 
   int border_thickness = Border(GetLayoutObject()->StyleRef());
 
-  int size = axis.sizes_.size();
+  int size = sizes.size();
   if (!size)
     return 0;
 
   int position = 0;
   for (int i = 0; i < split && i < size; ++i)
-    position += axis.sizes_[i].ToInt() + border_thickness;
+    position += sizes[i].ToInt() + border_thickness;
   return position - border_thickness;
 }
 
 bool HTMLFrameSetElement::CanResizeRow(const gfx::Point& p) const {
-  return resize_rows_.CanResizeSplitAt(
-      HitTestSplit(To<LayoutFrameSet>(GetLayoutObject())->Rows(), p.y()));
+  return resize_rows_.CanResizeSplitAt(HitTestSplit(
+      To<LayoutFrameSet>(GetLayoutObject())->Rows().sizes_, p.y()));
 }
 
 bool HTMLFrameSetElement::CanResizeColumn(const gfx::Point& p) const {
-  return resize_cols_.CanResizeSplitAt(
-      HitTestSplit(To<LayoutFrameSet>(GetLayoutObject())->Columns(), p.x()));
+  return resize_cols_.CanResizeSplitAt(HitTestSplit(
+      To<LayoutFrameSet>(GetLayoutObject())->Columns().sizes_, p.x()));
 }
 
-int HTMLFrameSetElement::HitTestSplit(const LayoutFrameSet::GridAxis& axis,
+int HTMLFrameSetElement::HitTestSplit(const Vector<LayoutUnit>& sizes,
                                       int position) const {
   if (GetLayoutObject()->NeedsLayout())
     return ResizeAxis::kNoSplit;
@@ -488,16 +492,16 @@
   if (border_thickness <= 0)
     return ResizeAxis::kNoSplit;
 
-  wtf_size_t size = axis.sizes_.size();
+  wtf_size_t size = sizes.size();
   if (!size)
     return ResizeAxis::kNoSplit;
 
-  int split_position = axis.sizes_[0].ToInt();
+  int split_position = sizes[0].ToInt();
   for (wtf_size_t i = 1; i < size; ++i) {
     if (position >= split_position &&
         position < split_position + border_thickness)
       return static_cast<int>(i);
-    split_position += border_thickness + axis.sizes_[i].ToInt();
+    split_position += border_thickness + sizes[i].ToInt();
   }
   return ResizeAxis::kNoSplit;
 }
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.h b/third_party/blink/renderer/core/html/html_frame_set_element.h
index 7286573..66bd55a 100644
--- a/third_party/blink/renderer/core/html/html_frame_set_element.h
+++ b/third_party/blink/renderer/core/html/html_frame_set_element.h
@@ -28,7 +28,6 @@
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/html/html_dimension.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
-#include "third_party/blink/renderer/core/layout/layout_frame_set.h"
 
 namespace blink {
 
@@ -122,14 +121,14 @@
 
   bool UserResize(const MouseEvent& event);
   void SetIsResizing(bool is_resizing);
-  void StartResizing(const LayoutFrameSet::GridAxis& axis,
+  void StartResizing(const Vector<LayoutUnit>& sizes,
                      int position,
                      ResizeAxis& resize_axis);
-  void ContinueResizing(const LayoutFrameSet::GridAxis& axis,
+  void ContinueResizing(const Vector<LayoutUnit>& sizes,
                         int position,
                         ResizeAxis& resize_axis);
-  int SplitPosition(const LayoutFrameSet::GridAxis& axis, int split) const;
-  int HitTestSplit(const LayoutFrameSet::GridAxis& axis, int position) const;
+  int SplitPosition(const Vector<LayoutUnit>& sizes, int split) const;
+  int HitTestSplit(const Vector<LayoutUnit>& sizes, int position) const;
 
   void FillFromEdgeInfo(const FrameEdgeInfo& edge_info,
                         wtf_size_t r,
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_cue_layout_algorithm.cc b/third_party/blink/renderer/core/html/track/vtt/vtt_cue_layout_algorithm.cc
index 4560d5b..db9a4be 100644
--- a/third_party/blink/renderer/core/html/track/vtt/vtt_cue_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/html/track/vtt/vtt_cue_layout_algorithm.cc
@@ -270,10 +270,12 @@
 
   // Set adjusted_position to 'top' or 'left' property as a percentage value,
   // which will work well even if the video rendering area is resized.
+  double percentage_position =
+      full_dimension ? (adjusted_position * 100 / full_dimension).ToDouble()
+                     : 100.0;
   cue_.SetInlineStyleProperty(
       is_horizontal ? CSSPropertyID::kTop : CSSPropertyID::kLeft,
-      (adjusted_position * 100 / full_dimension).ToDouble(),
-      CSSPrimitiveValue::UnitType::kPercentage);
+      percentage_position, CSSPrimitiveValue::UnitType::kPercentage);
 }
 
 void VttCueLayoutAlgorithm::AdjustPositionWithoutSnapToLines() {
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni
index aebe220..5d4205d 100644
--- a/third_party/blink/renderer/core/layout/build.gni
+++ b/third_party/blink/renderer/core/layout/build.gni
@@ -343,6 +343,7 @@
   "ng/flex/ng_flex_layout_algorithm.cc",
   "ng/flex/ng_flex_layout_algorithm.h",
   "ng/flex/ng_flex_line.h",
+  "ng/frame_set_layout_data.h",
   "ng/geometry/ng_bfc_offset.cc",
   "ng/geometry/ng_bfc_offset.h",
   "ng/geometry/ng_bfc_rect.h",
@@ -454,6 +455,8 @@
   "ng/layout_ng_button.h",
   "ng/layout_ng_fieldset.cc",
   "ng/layout_ng_fieldset.h",
+  "ng/layout_ng_frame_set.cc",
+  "ng/layout_ng_frame_set.h",
   "ng/layout_ng_mixin.cc",
   "ng/layout_ng_mixin.h",
   "ng/layout_ng_progress.cc",
diff --git a/third_party/blink/renderer/core/layout/layout_frame_set.cc b/third_party/blink/renderer/core/layout/layout_frame_set.cc
index bfe637c6..8d9fc162 100644
--- a/third_party/blink/renderer/core/layout/layout_frame_set.cc
+++ b/third_party/blink/renderer/core/layout/layout_frame_set.cc
@@ -50,8 +50,8 @@
   return base::checked_cast<int>(temp_product.ValueOrDie());
 }
 
-LayoutFrameSet::LayoutFrameSet(HTMLFrameSetElement* frame_set)
-    : LayoutBox(frame_set) {
+LayoutFrameSet::LayoutFrameSet(Element* element) : LayoutBox(element) {
+  DCHECK(IsA<HTMLFrameSetElement>(element));
   SetInline(false);
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_frame_set.h b/third_party/blink/renderer/core/layout/layout_frame_set.h
index 59663753..76b6803 100644
--- a/third_party/blink/renderer/core/layout/layout_frame_set.h
+++ b/third_party/blink/renderer/core/layout/layout_frame_set.h
@@ -33,7 +33,7 @@
 
 class LayoutFrameSet final : public LayoutBox {
  public:
-  LayoutFrameSet(HTMLFrameSetElement*);
+  explicit LayoutFrameSet(Element*);
   ~LayoutFrameSet() override;
   void Trace(Visitor*) const override;
 
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 2187c39c..a41cee7f 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -849,6 +849,14 @@
     NOT_DESTROYED();
     return IsOfType(kLayoutObjectFrameSet);
   }
+  bool IsLayoutNGFrameSet() const {
+    NOT_DESTROYED();
+    return IsOfType(kLayoutObjectNGFrameSet);
+  }
+  bool IsFrameSetIncludingNG() const {
+    NOT_DESTROYED();
+    return IsFrameSet() || IsLayoutNGFrameSet();
+  }
   bool IsInsideListMarkerForCustomContent() const {
     NOT_DESTROYED();
     return IsOfType(kLayoutObjectInsideListMarker);
@@ -3608,6 +3616,7 @@
     kLayoutObjectNGCustom,
     kLayoutObjectNGFieldset,
     kLayoutObjectNGFlexibleBox,
+    kLayoutObjectNGFrameSet,
     kLayoutObjectNGGrid,
     kLayoutObjectNGInsideListMarker,
     kLayoutObjectNGListItem,
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.cc b/third_party/blink/renderer/core/layout/layout_object_factory.cc
index cd6caa4..5b47a09 100644
--- a/third_party/blink/renderer/core/layout/layout_object_factory.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/html/html_frame_set_element.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
 #include "third_party/blink/renderer/core/layout/layout_button.h"
 #include "third_party/blink/renderer/core/layout/layout_counter.h"
@@ -15,6 +16,7 @@
 #include "third_party/blink/renderer/core/layout/layout_fieldset.h"
 #include "third_party/blink/renderer/core/layout/layout_file_upload_control.h"
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
+#include "third_party/blink/renderer/core/layout/layout_frame_set.h"
 #include "third_party/blink/renderer/core/layout/layout_grid.h"
 #include "third_party/blink/renderer/core/layout/layout_inside_list_marker.h"
 #include "third_party/blink/renderer/core/layout/layout_list_item.h"
@@ -44,6 +46,7 @@
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_button.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_frame_set.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_progress.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_ruby_as_block.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_ruby_text.h"
@@ -296,6 +299,15 @@
                       LayoutFileUploadControl>(node, legacy);
 }
 
+LayoutBox* LayoutObjectFactory::CreateFrameSet(HTMLFrameSetElement& element,
+                                               const ComputedStyle& style,
+                                               LegacyLayout legacy) {
+  const bool disable_ng_for_type =
+      !RuntimeEnabledFeatures::LayoutNGFrameSetEnabled();
+  return CreateObject<LayoutBox, LayoutNGFrameSet, LayoutFrameSet>(
+      element, legacy, disable_ng_for_type);
+}
+
 LayoutObject* LayoutObjectFactory::CreateSliderTrack(Node& node,
                                                      const ComputedStyle& style,
                                                      LegacyLayout legacy) {
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.h b/third_party/blink/renderer/core/layout/layout_object_factory.h
index aac3e40..57d6543 100644
--- a/third_party/blink/renderer/core/layout/layout_object_factory.h
+++ b/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -15,6 +15,7 @@
 class CounterContentData;
 class Document;
 class HTMLElement;
+class HTMLFrameSetElement;
 class LayoutBlock;
 class LayoutBlockFlow;
 class LayoutObject;
@@ -83,6 +84,9 @@
   static LayoutBlockFlow* CreateFileUploadControl(Node& node,
                                                   const ComputedStyle& style,
                                                   LegacyLayout legacy);
+  static LayoutBox* CreateFrameSet(HTMLFrameSetElement& element,
+                                   const ComputedStyle& style,
+                                   LegacyLayout legacy);
   static LayoutObject* CreateSliderTrack(Node& node,
                                          const ComputedStyle& style,
                                          LegacyLayout legacy);
diff --git a/third_party/blink/renderer/core/layout/ng/frame_set_layout_data.h b/third_party/blink/renderer/core/layout/ng/frame_set_layout_data.h
new file mode 100644
index 0000000..52121e4
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/frame_set_layout_data.h
@@ -0,0 +1,31 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_FRAME_SET_LAYOUT_DATA_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_FRAME_SET_LAYOUT_DATA_H_
+
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+// An instance of FrameSetLayoutData is produced by NGFrameSetLayoutAlgorithm,
+// and is owned by NGBoxFragmentBuilder and NGPhysicalBoxFragment. It is used
+// by NGFrameSetPainter and resize handling of HTMLFrameSetElement.
+struct FrameSetLayoutData {
+  // Frame grid sizes.
+  Vector<LayoutUnit> col_sizes;
+  Vector<LayoutUnit> row_sizes;
+
+  // Border existence.
+  Vector<bool> col_allow_border;
+  Vector<bool> row_allow_border;
+
+  int border_thickness;
+  bool has_border_color;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_FRAME_SET_LAYOUT_DATA_H_
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc
index 454c1f2..2ea218e 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.cc
@@ -124,7 +124,7 @@
 //
 // TODO(kschmi): Some of these conditions are non-intuitive, so investigate
 // whether these conditions are correct or if the test expectations are off.
-BaselineType DetermineBaselineType(
+BaselineGroup DetermineBaselineGroup(
     const GridTrackSizingDirection track_direction,
     const WritingMode container_writing_mode,
     const WritingMode child_writing_mode) {
@@ -152,14 +152,13 @@
       is_major = true;
       break;
   }
-  return is_major ? BaselineType::kMajor : BaselineType::kMinor;
+  return is_major ? BaselineGroup::kMajor : BaselineGroup::kMinor;
 }
 
 }  // namespace
 
 GridItemData::GridItemData(const NGBlockNode node,
-                           const ComputedStyle& container_style,
-                           const WritingMode container_writing_mode)
+                           const ComputedStyle& container_style)
     : node(node),
       parent_grid(nullptr),
       is_sizing_dependent_on_block_size(false),
@@ -185,11 +184,12 @@
       container_style, &block_auto_behavior, &is_overflow_safe);
   is_block_axis_overflow_safe = is_overflow_safe;
 
-  const auto item_writing_mode = style.GetWritingDirection().GetWritingMode();
-  column_baseline_type = DetermineBaselineType(
+  const auto container_writing_mode = container_style.GetWritingMode();
+  const auto item_writing_mode = style.GetWritingMode();
+  column_baseline_group = DetermineBaselineGroup(
       kForColumns, container_writing_mode, item_writing_mode);
-  row_baseline_type = DetermineBaselineType(kForRows, container_writing_mode,
-                                            item_writing_mode);
+  row_baseline_group = DetermineBaselineGroup(kForRows, container_writing_mode,
+                                              item_writing_mode);
 }
 
 void GridItemData::SetAlignmentFallback(
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h
index c5f7c97..fa742aef 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_item.h
@@ -15,7 +15,7 @@
 class NGGridPlacement;
 
 enum class AxisEdge { kStart, kCenter, kEnd, kBaseline };
-enum class BaselineType { kMajor, kMinor };
+enum class BaselineGroup { kMajor, kMinor };
 enum class SizingConstraint { kLayout, kMinContent, kMaxContent };
 
 struct GridItemIndices {
@@ -29,9 +29,7 @@
 };
 
 struct CORE_EXPORT GridItemData : public GarbageCollected<GridItemData> {
-  GridItemData(const NGBlockNode node,
-               const ComputedStyle& container_style,
-               const WritingMode container_writing_mode);
+  GridItemData(const NGBlockNode node, const ComputedStyle& container_style);
 
   void SetAlignmentFallback(const GridTrackSizingDirection track_direction,
                             const ComputedStyle& container_style,
@@ -69,6 +67,12 @@
       const NGGridLayoutTrackCollection& track_collection,
       const NGGridPlacement& grid_placement);
 
+  enum BaselineGroup BaselineGroup(
+      const GridTrackSizingDirection track_direction) const {
+    return (track_direction == kForColumns) ? column_baseline_group
+                                            : row_baseline_group;
+  }
+
   const GridItemIndices& SetIndices(
       const GridTrackSizingDirection track_direction) const {
     return (track_direction == kForColumns) ? column_set_indices
@@ -178,8 +182,8 @@
   NGAutoBehavior inline_auto_behavior;
   NGAutoBehavior block_auto_behavior;
 
-  BaselineType column_baseline_type;
-  BaselineType row_baseline_type;
+  enum BaselineGroup column_baseline_group;
+  enum BaselineGroup row_baseline_group;
 
   TrackSpanProperties column_span_properties;
   TrackSpanProperties row_span_properties;
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
index ac097cdf..5ae499b 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -490,12 +490,12 @@
   // https://www.w3.org/TR/css-align-3/#baseline-sharing-group
   if (track_direction == kForColumns) {
     const wtf_size_t set_index = grid_item.column_set_indices.begin;
-    return (grid_item.column_baseline_type == BaselineType::kMajor)
+    return (grid_item.column_baseline_group == BaselineGroup::kMajor)
                ? layout_data.Columns()->MajorBaseline(set_index)
                : layout_data.Columns()->MinorBaseline(set_index);
   } else {
     const wtf_size_t set_index = grid_item.row_set_indices.begin;
-    return (grid_item.row_baseline_type == BaselineType::kMajor)
+    return (grid_item.row_baseline_group == BaselineGroup::kMajor)
                ? layout_data.Rows()->MajorBaseline(set_index)
                : layout_data.Rows()->MinorBaseline(set_index);
   }
@@ -1444,7 +1444,6 @@
   DCHECK(grid_items && track_collection);
 
   const auto track_direction = track_collection->Direction();
-  const bool is_for_columns = track_direction == kForColumns;
 
   track_collection->ResetBaselines();
 
@@ -1455,13 +1454,10 @@
     // alignment context along that axis", so we only need to look at the first
     // index for baseline/first-baseline support.
     // https://www.w3.org/TR/css-align-3/#baseline-sharing-group
-    const auto baseline_type = is_for_columns ? grid_item.column_baseline_type
-                                              : grid_item.row_baseline_type;
-    const wtf_size_t set_index = is_for_columns
-                                     ? grid_item.column_set_indices.begin
-                                     : grid_item.row_set_indices.begin;
+    const auto baseline_group = grid_item.BaselineGroup(track_direction);
+    const wtf_size_t set_index = grid_item.SetIndices(track_direction).begin;
 
-    if (baseline_type == BaselineType::kMajor)
+    if (baseline_group == BaselineGroup::kMajor)
       track_collection->SetMajorBaseline(set_index, candidate_baseline);
     else
       track_collection->SetMinorBaseline(set_index, candidate_baseline);
@@ -3518,8 +3514,7 @@
       continue;
 
     absl::optional<LogicalRect> containing_block_rect;
-    GridItemData out_of_flow_item(To<NGBlockNode>(child), container_style,
-                                  ConstraintSpace().GetWritingMode());
+    GridItemData out_of_flow_item(To<NGBlockNode>(child), container_style);
 
     if (out_of_flow_item.IsGridContainingBlock()) {
       containing_block_rect = ComputeOutOfFlowItemContainingRect(
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc
index d9c4ecf2..c3dd18af 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_node.cc
@@ -44,9 +44,8 @@
   const int initial_order = ComputedStyleInitialValues::InitialOrder();
 
   for (auto child = FirstChild(); child; child = child.NextSibling()) {
-    auto* grid_item = MakeGarbageCollected<GridItemData>(
-        To<NGBlockNode>(child), container_style,
-        container_style.GetWritingMode());
+    auto* grid_item = MakeGarbageCollected<GridItemData>(To<NGBlockNode>(child),
+                                                         container_style);
 
     // Order all of our in-flow children by their order property.
     if (!grid_item->IsOutOfFlow()) {
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_frame_set.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_frame_set.cc
new file mode 100644
index 0000000..b761034f
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_frame_set.cc
@@ -0,0 +1,25 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_frame_set.h"
+
+#include "third_party/blink/renderer/core/html/html_frame_set_element.h"
+
+namespace blink {
+
+LayoutNGFrameSet::LayoutNGFrameSet(Element* element) : LayoutNGBlock(element) {
+  DCHECK(IsA<HTMLFrameSetElement>(element));
+}
+
+const char* LayoutNGFrameSet::GetName() const {
+  NOT_DESTROYED();
+  return "LayoutNGFrameSet";
+}
+
+bool LayoutNGFrameSet::IsOfType(LayoutObjectType type) const {
+  NOT_DESTROYED();
+  return type == kLayoutObjectNGFrameSet || LayoutNGBlock::IsOfType(type);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_frame_set.h b/third_party/blink/renderer/core/layout/ng/layout_ng_frame_set.h
new file mode 100644
index 0000000..a11535a
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_frame_set.h
@@ -0,0 +1,30 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FRAME_SET_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FRAME_SET_H_
+
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_block.h"
+
+namespace blink {
+
+class LayoutNGFrameSet final : public LayoutNGBlock {
+ public:
+  explicit LayoutNGFrameSet(Element*);
+
+ private:
+  const char* GetName() const override;
+  bool IsOfType(LayoutObjectType type) const override;
+};
+
+template <>
+struct DowncastTraits<LayoutNGFrameSet> {
+  static bool AllowFrom(const LayoutObject& object) {
+    return object.IsLayoutNGFrameSet();
+  }
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FRAME_SET_H_
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
index ede3990d..ebc9ed3 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
@@ -62,7 +62,7 @@
       return *baseline;
 
     if (baseline_type == kAlphabeticBaseline)
-      return BlockSize();
+      return writing_direction_.IsFlippedLines() ? LayoutUnit() : BlockSize();
 
     return BlockSize() / 2;
   }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index 1c8787b3..e5d6bc3d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/core/layout/geometry/box_sides.h"
 #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
 #include "third_party/blink/renderer/core/layout/ng/flex/ng_flex_data.h"
+#include "third_party/blink/renderer/core/layout/ng/frame_set_layout_data.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_fragment_geometry.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h"
@@ -607,6 +608,9 @@
       std::unique_ptr<DevtoolsFlexInfo> flex_layout_data) {
     flex_layout_data_ = std::move(flex_layout_data);
   }
+  void TransferFrameSetLayoutData(std::unique_ptr<FrameSetLayoutData> data) {
+    frame_set_layout_data_ = std::move(data);
+  }
 
   const NGGridLayoutData& GridLayoutData() const {
     DCHECK(grid_layout_data_);
@@ -776,6 +780,7 @@
   std::unique_ptr<NGGridLayoutData> grid_layout_data_;
 
   std::unique_ptr<DevtoolsFlexInfo> flex_layout_data_;
+  std::unique_ptr<FrameSetLayoutData> frame_set_layout_data_;
 
   LogicalBoxSides sides_to_include_;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index 3a7f84d..b00e30c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -361,9 +361,7 @@
     const auto& grid_style = containing_grid.StyleRef();
     const auto& placement_data = containing_grid.CachedPlacementData();
 
-    GridItemData grid_item(candidate.Node(), grid_style,
-                           grid_style.GetWritingMode());
-
+    GridItemData grid_item(candidate.Node(), grid_style);
     return {grid_style.GetWritingDirection(),
             NGGridLayoutAlgorithm::ComputeOutOfFlowItemContainingRect(
                 NGGridPlacement(grid_style, placement_data), grid_layout_data,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index c401138..548e934c 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -193,7 +193,8 @@
       has_fragment_items = true;
   }
 
-  bool has_rare_data = builder->mathml_paint_info_ ||
+  bool has_rare_data = builder->frame_set_layout_data_ ||
+                       builder->mathml_paint_info_ ||
                        builder->table_grid_rect_ ||
                        !builder->table_column_geometries_.IsEmpty() ||
                        builder->table_collapsed_borders_ ||
@@ -581,7 +582,8 @@
 }
 
 NGPhysicalBoxFragment::RareData::RareData(NGBoxFragmentBuilder* builder)
-    : mathml_paint_info(std::move(builder->mathml_paint_info_)) {
+    : frame_set_layout_data(std::move(builder->frame_set_layout_data_)),
+      mathml_paint_info(std::move(builder->mathml_paint_info_)) {
   if (builder->table_grid_rect_)
     table_grid_rect = *builder->table_grid_rect_;
   if (!builder->table_column_geometries_.IsEmpty())
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index d5a53fe9..fa2f991 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -25,6 +25,7 @@
 
 class NGBoxFragmentBuilder;
 enum class NGOutlineType;
+struct FrameSetLayoutData;
 
 class CORE_EXPORT NGPhysicalBoxFragment final : public NGPhysicalFragment {
  public:
@@ -388,6 +389,10 @@
                                     bool check_same_block_size) const;
 #endif
 
+  const FrameSetLayoutData* GetFrameSetLayoutData() const {
+    return ComputeRareDataAddress()->frame_set_layout_data.get();
+  }
+
   bool HasExtraMathMLPainting() const {
     if (IsMathMLFraction())
       return true;
@@ -487,6 +492,7 @@
     explicit RareData(NGBoxFragmentBuilder*);
     void Trace(Visitor*) const;
 
+    const std::unique_ptr<const FrameSetLayoutData> frame_set_layout_data;
     const std::unique_ptr<const NGMathMLPaintInfo> mathml_paint_info;
 
     // Table rare-data.
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_row_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_row_layout_algorithm.cc
index 510226d..ab80ba19 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_row_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_row_layout_algorithm.cc
@@ -114,8 +114,9 @@
   EBreakBetween row_break_after;
   NGRowBaselineTabulator row_baseline_tabulator;
   HeapVector<ResultWithOffset> results;
-  auto PlaceCells = [&](LayoutUnit row_block_size,
-                        absl::optional<LayoutUnit> row_baseline) {
+  auto PlaceCells =
+      [&](LayoutUnit row_block_size,
+          absl::optional<LayoutUnit> row_baseline) -> NGLayoutResult::EStatus {
     // Reset our state.
     max_cell_block_size = LayoutUnit();
     row_break_before = EBreakBetween::kAuto;
@@ -143,6 +144,17 @@
       const NGLayoutResult* cell_result =
           cell.Layout(cell_space, cell_break_token);
 
+      if (cell_result->Status() == NGLayoutResult::kOutOfFragmentainerSpace) {
+        DCHECK(has_block_fragmentation);
+        // If the cell establishes a multicol container (and we're already
+        // inside another fragmentation context), it may have failed to produce
+        // a fragment, because there wasn't enough space. We now need to
+        // propagate the failure, to make some ancestor algorithm handle the
+        // problem. We need to break before something further up.
+        return NGLayoutResult::kOutOfFragmentainerSpace;
+      }
+      DCHECK_EQ(cell_result->Status(), NGLayoutResult::kSuccess);
+
       const LogicalOffset offset(
           table_data.column_locations[cell_data.start_column].offset -
               table_data.table_border_spacing.inline_size,
@@ -177,6 +189,8 @@
             std::max(max_cell_block_size, fragment.BlockSize());
       }
     }
+
+    return NGLayoutResult::kSuccess;
   };
 
   // Determine the baseline for the table-row if we haven't been provided a
@@ -194,7 +208,10 @@
     }
   }
 
-  PlaceCells(row.block_size, row_baseline);
+  NGLayoutResult::EStatus status = PlaceCells(row.block_size, row_baseline);
+  if (status == NGLayoutResult::kOutOfFragmentainerSpace)
+    return container_builder_.Abort(status);
+  DCHECK_EQ(status, NGLayoutResult::kSuccess);
 
   LayoutUnit previous_consumed_row_block_size;
   if (IsResumingLayout(BreakToken())) {
@@ -213,8 +230,13 @@
 
   if (has_block_fragmentation) {
     // If we've expanded due to fragmentation, relayout with the new block-size.
-    if (row.block_size != row_block_size)
-      PlaceCells(row_block_size, absl::nullopt);
+    if (row.block_size != row_block_size) {
+      NGLayoutResult::EStatus status =
+          PlaceCells(row_block_size, absl::nullopt);
+      if (status == NGLayoutResult::kOutOfFragmentainerSpace)
+        return container_builder_.Abort(status);
+      DCHECK_EQ(status, NGLayoutResult::kSuccess);
+    }
 
     for (auto& result : results)
       container_builder_.AddResult(*result.result, result.offset);
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc
index 6250fb038..4bc28ae 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.cc
+++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -706,11 +706,12 @@
         // used by the next navigation only when they requested the same URL
         // with the same association mapping.
         change_rel_to_prefetch = true;
-        // Prefetch requests for alternate SXG should be made with no-cors,
-        // regardless of the crossorigin attribute of Link:rel=preload header
-        // that triggered the prefetch. See step 19.6.8 of
+        // Prefetch requests for alternate SXG should be made with a
+        // corsAttributeState of Anonymous, regardless of the crossorigin
+        // attribute of Link:rel=preload header that triggered the prefetch. See
+        // step 19.6.8 of
         // https://wicg.github.io/webpackage/loading.html#mp-link-type-prefetch.
-        params.cross_origin = kCrossOriginAttributeNotSet;
+        params.cross_origin = kCrossOriginAttributeAnonymous;
       }
     }
 
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc b/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc
index 8d20985..c18f99d 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc
+++ b/third_party/blink/renderer/core/streams/readable_stream_byob_request.cc
@@ -16,8 +16,7 @@
     NotShared<DOMUint8Array> view)
     : controller_(controller), view_(view) {}
 
-NotShared<DOMArrayBufferView> ReadableStreamBYOBRequest::view(
-    ExceptionState& exception_state) const {
+NotShared<DOMArrayBufferView> ReadableStreamBYOBRequest::view() const {
   // https://streams.spec.whatwg.org/#rs-byob-request-view
   // 1. Return this.[[view]].
   return view_;
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_request.h b/third_party/blink/renderer/core/streams/readable_stream_byob_request.h
index 16304775..db629534 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_byob_request.h
+++ b/third_party/blink/renderer/core/streams/readable_stream_byob_request.h
@@ -23,7 +23,7 @@
                             NotShared<DOMUint8Array> view);
 
   // https://streams.spec.whatwg.org/#rs-byob-request-view
-  NotShared<DOMArrayBufferView> view(ExceptionState&) const;
+  NotShared<DOMArrayBufferView> view() const;
 
   // https://streams.spec.whatwg.org/#rs-byob-request-respond
   void respond(ScriptState*, uint64_t bytes_written, ExceptionState&);
diff --git a/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl b/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl
index 66bd7f0e..419fef4 100644
--- a/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl
+++ b/third_party/blink/renderer/core/streams/readable_stream_byob_request.idl
@@ -6,7 +6,7 @@
 [
     Exposed=(Window,Worker,Worklet)
 ] interface ReadableStreamBYOBRequest {
-    [RaisesException] readonly attribute ArrayBufferView? view;
+    readonly attribute ArrayBufferView? view;
 
     [CallWith=ScriptState, RaisesException] void respond([EnforceRange] unsigned long long bytesWritten);
     [CallWith=ScriptState, RaisesException] void respondWithNewView(ArrayBufferView view);
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 71633d0..bdbffda 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -3738,35 +3738,6 @@
   CustomElement::AddEmbedderCustomElementNameForTesting(name, exception_state);
 }
 
-String Internals::resolveModuleSpecifier(const String& specifier,
-                                         const String& base_url_string,
-                                         Document* document,
-                                         ExceptionState& exception_state) {
-  Modulator* modulator =
-      Modulator::From(ToScriptStateForMainWorld(document->GetFrame()));
-
-  if (!modulator) {
-    V8ThrowException::ThrowTypeError(
-        v8::Isolate::GetCurrent(),
-        "Failed to resolve module specifier " + specifier + ": No modulator");
-    return NullURL();
-  }
-
-  const KURL base_url = document->CompleteURL(base_url_string);
-  String failure_reason = "Failed";
-  const KURL result =
-      modulator->ResolveModuleSpecifier(specifier, base_url, &failure_reason);
-
-  if (!result.IsValid()) {
-    V8ThrowException::ThrowTypeError(v8::Isolate::GetCurrent(),
-                                     "Failed to resolve module specifier " +
-                                         specifier + ": " + failure_reason);
-    return NullURL();
-  }
-
-  return result.GetString();
-}
-
 String Internals::getParsedImportMap(Document* document,
                                      ExceptionState& exception_state) {
   Modulator* modulator =
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h
index 21a8e7a..6779f6c 100644
--- a/third_party/blink/renderer/core/testing/internals.h
+++ b/third_party/blink/renderer/core/testing/internals.h
@@ -338,11 +338,6 @@
   InternalRuntimeFlags* runtimeFlags() const;
   unsigned workerThreadCount() const;
 
-  String resolveModuleSpecifier(const String& specifier,
-                                const String& base_url_string,
-                                Document*,
-                                ExceptionState&);
-
   String getParsedImportMap(Document*, ExceptionState&);
 
   void SetDeviceProximity(Document*,
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl
index 27b799a..302b315 100644
--- a/third_party/blink/renderer/core/testing/internals.idl
+++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -417,15 +417,7 @@
     // element mechanism.
     [RaisesException] void addEmbedderCustomElementName(DOMString name);
 
-    // https://html.spec.whatwg.org/C/#resolve-a-module-specifier
-    // Throws TypeError on error.
-    // Used for testing Import Maps https://github.com/domenic/import-maps
-    [RaisesException] DOMString resolveModuleSpecifier(DOMString specifier, DOMString base_url, Document document);
-
     // Returns the current serialized import map of the Document.
-    // TODO(crbug.com/927181): Currently this returns the "imports" value,
-    // because Blink doesn't support scopes yet. Update this once scopes are
-    // implemented.
     [RaisesException] DOMString getParsedImportMap(Document document);
 
     // Sets the scale for devtools device emulation.
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index 381a9db..e7d6b9c0 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -58,6 +58,7 @@
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_v8_value_converter.h"
 #include "third_party/blink/renderer/bindings/core/v8/callback_promise_adapter.h"
+#include "third_party/blink/renderer/bindings/core/v8/js_based_event_listener.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
@@ -2588,8 +2589,19 @@
   if (!elv) {
     return mojom::blink::ServiceWorkerFetchHandlerType::kNoHandler;
   }
-  // TODO(crbug.com/1347319): implement nop handler detection.
-  return mojom::blink::ServiceWorkerFetchHandlerType::kNotSkippable;
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  v8::HandleScope handle_scope(isolate);
+  // TODO(crbug.com/1349613): revisit the way to implement this.
+  // The following code returns kEmptyFetchHandler if all handlers are nop.
+  for (RegisteredEventListener& e : *elv) {
+    EventTarget* et = EventTarget::Create(ScriptController()->GetScriptState());
+    v8::Local<v8::Value> v =
+        To<JSBasedEventListener>(e.Callback())->GetEffectiveFunction(*et);
+    if (!v.As<v8::Function>()->Experimental_IsNopFunction()) {
+      return mojom::blink::ServiceWorkerFetchHandlerType::kNotSkippable;
+    }
+  }
+  return mojom::blink::ServiceWorkerFetchHandlerType::kEmptyFetchHandler;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc b/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
index 61675c9..ec1313b 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context_autoplay_test.cc
@@ -54,11 +54,9 @@
 class AudioContextAutoplayTestPlatform : public TestingPlatformSupport {
  public:
   std::unique_ptr<WebAudioDevice> CreateAudioDevice(
-      unsigned number_of_input_channels,
-      unsigned number_of_channels,
+      unsigned number_of_output_channels,
       const WebAudioLatencyHint& latency_hint,
-      WebAudioDevice::RenderCallback*,
-      const WebString& device_id) override {
+      WebAudioDevice::RenderCallback*) override {
     return std::make_unique<MockWebAudioDeviceForAutoplayTest>(
         AudioHardwareSampleRate(), AudioHardwareBufferSize());
   }
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context_test.cc b/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
index 3560c7c..78eacf6 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
@@ -48,11 +48,9 @@
 class AudioContextTestPlatform : public TestingPlatformSupport {
  public:
   std::unique_ptr<WebAudioDevice> CreateAudioDevice(
-      unsigned number_of_input_channels,
-      unsigned number_of_channels,
+      unsigned number_of_output_channels,
       const WebAudioLatencyHint& latency_hint,
-      WebAudioDevice::RenderCallback*,
-      const WebString& device_id) override {
+      WebAudioDevice::RenderCallback*) override {
     double buffer_size = 0;
     const double interactive_size = AudioHardwareBufferSize();
     const double balanced_size = AudioHardwareBufferSize() * 2;
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
index db6963c..fe46f7c 100644
--- a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
@@ -395,7 +395,11 @@
     }
   }
 
-  // We've resolved the promise.  Remove it now.
+  // Resolving a promise above can result in uninitializing/clearing of the
+  // context. (e.g. dropping an iframe. See crbug.com/1350086)
+  if (is_cleared_) return;
+
+  // Otherwise the resolver should exist in the set. Check and remove it.
   DCHECK(decode_audio_resolvers_.Contains(resolver));
   decode_audio_resolvers_.erase(resolver);
 }
diff --git a/third_party/blink/renderer/platform/audio/audio_destination.cc b/third_party/blink/renderer/platform/audio/audio_destination.cc
index 642122e..4f542916 100644
--- a/third_party/blink/renderer/platform/audio/audio_destination.cc
+++ b/third_party/blink/renderer/platform/audio/audio_destination.cc
@@ -104,12 +104,9 @@
                                 number_of_output_channels));
   SendLogMessage(
       String::Format("%s => (FIFO size=%u bytes)", __func__, fifo_->length()));
-  // Create WebAudioDevice. blink::WebAudioDevice is designed to support the
-  // local input (e.g. loopback from OS audio system), but Chromium's media
-  // renderer does not support it currently. Thus, we use zero for the number
-  // of input channels.
+
   web_audio_device_ = Platform::Current()->CreateAudioDevice(
-      0, number_of_output_channels, latency_hint, this, String());
+      number_of_output_channels, latency_hint, this);
   DCHECK(web_audio_device_);
 
   callback_buffer_size_ = web_audio_device_->FramesPerBuffer();
diff --git a/third_party/blink/renderer/platform/audio/audio_destination_test.cc b/third_party/blink/renderer/platform/audio/audio_destination_test.cc
index d8d94928..5da5fb3a 100644
--- a/third_party/blink/renderer/platform/audio/audio_destination_test.cc
+++ b/third_party/blink/renderer/platform/audio/audio_destination_test.cc
@@ -37,11 +37,9 @@
 class TestPlatform : public TestingPlatformSupport {
  public:
   std::unique_ptr<WebAudioDevice> CreateAudioDevice(
-      unsigned number_of_input_channels,
-      unsigned number_of_channels,
+      unsigned number_of_output_channels,
       const WebAudioLatencyHint& latency_hint,
-      WebAudioDevice::RenderCallback*,
-      const WebString& device_id) override {
+      WebAudioDevice::RenderCallback*) override {
     return std::make_unique<MockWebAudioDevice>(AudioHardwareSampleRate(),
                                                 AudioHardwareBufferSize());
   }
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
index 957231f..f6d07a7 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.cc
@@ -195,7 +195,21 @@
   struct StateEntry {
     // Remembers the type of paired begin that caused a state to be saved.
     // This is for checking integrity of the algorithm.
-    enum PairedType { kClip, kEffect } type;
+    enum PairedType { kClip, kClipOmitted, kEffect };
+    explicit StateEntry(PairedType type,
+                        const TransformPaintPropertyNode* transform,
+                        const ClipPaintPropertyNode* clip,
+                        const EffectPaintPropertyNode* effect,
+                        const TransformPaintPropertyNode* previous_transform)
+        : transform(transform),
+          clip(clip),
+          effect(effect),
+          previous_transform(previous_transform),
+          type_(type) {}
+
+    bool IsClip() const { return type_ != kEffect; }
+    bool IsEffect() const { return type_ == kEffect; }
+    bool NeedsRestore() const { return type_ != kClipOmitted; }
 
     // These fields are neve nullptr.
     const TransformPaintPropertyNode* transform;
@@ -206,6 +220,9 @@
 #if DCHECK_IS_ON()
     bool has_pre_cap_effect_hierarchy_issue = false;
 #endif
+
+   private:
+    PairedType type_;
   };
   void PushState(StateEntry::PairedType);
   void PopState();
@@ -255,7 +272,7 @@
 ConversionContext::~ConversionContext() {
   // End all states.
   while (state_stack_.size()) {
-    if (state_stack_.back().type == StateEntry::kEffect)
+    if (state_stack_.back().IsEffect())
       EndEffect();
     else
       EndClip();
@@ -290,6 +307,9 @@
 // Returns whether the clip has been combined.
 static bool CombineClip(const ClipPaintPropertyNode& clip,
                         FloatRoundedRect& combined_clip_rect) {
+  if (clip.PixelMovingFilter())
+    return true;
+
   // Don't combine into a clip with clip path.
   DCHECK(clip.Parent());
   if (clip.UnaliasedParent()->ClipPath())
@@ -338,7 +358,7 @@
   const auto* lca_clip =
       &target_clip.LowestCommonAncestor(*current_clip_).Unalias();
   while (current_clip_ != lca_clip) {
-    if (!state_stack_.size() || state_stack_.back().type != StateEntry::kClip) {
+    if (!state_stack_.size() || !state_stack_.back().IsClip()) {
       // TODO(crbug.com/803649): We still have clip hierarchy issues with
       // fragment clips. See crbug.com/1240080 for the test case. Will change
       // the above condition to DCHECK after LayoutNGBlockFragmentation is fully
@@ -374,14 +394,11 @@
     // This should never happen unless the DCHECK in step 1 failed.
     if (!clip)
       break;
-    if (!clip->PixelMovingFilter())
-      pending_clips.push_back(clip);
+    pending_clips.push_back(clip);
   }
 
-  if (pending_clips.IsEmpty())
-    return;
-
   // Step 3: Now apply the list of clips in top-down order.
+  DCHECK(pending_clips.size());
   auto pending_combined_clip_rect = pending_clips.back()->PaintClipRect();
   const auto* lowest_combined_clip_node = pending_clips.back();
   for (auto i = pending_clips.size() - 1; i--;) {
@@ -405,31 +422,35 @@
 void ConversionContext::StartClip(
     const FloatRoundedRect& combined_clip_rect,
     const ClipPaintPropertyNode& lowest_combined_clip_node) {
-  DCHECK_EQ(&lowest_combined_clip_node, &lowest_combined_clip_node);
-  const auto& local_transform =
-      lowest_combined_clip_node.LocalTransformSpace().Unalias();
-  if (&local_transform != current_transform_)
-    EndTransform();
-  cc_list_.StartPaint();
-  cc_list_.push<cc::SaveOp>();
-  ApplyTransform(local_transform);
-  const bool antialias = true;
-  if (combined_clip_rect.IsRounded()) {
-    cc_list_.push<cc::ClipRRectOp>(SkRRect(combined_clip_rect),
-                                   SkClipOp::kIntersect, antialias);
+  if (combined_clip_rect.Rect() == gfx::RectF(LayoutRect::InfiniteIntRect())) {
+    PushState(StateEntry::kClipOmitted);
   } else {
-    cc_list_.push<cc::ClipRectOp>(gfx::RectFToSkRect(combined_clip_rect.Rect()),
-                                  SkClipOp::kIntersect, antialias);
-  }
-  if (const auto& clip_path = lowest_combined_clip_node.ClipPath()) {
-    cc_list_.push<cc::ClipPathOp>(clip_path->GetSkPath(), SkClipOp::kIntersect,
-                                  antialias);
-  }
-  cc_list_.EndPaintOfPairedBegin();
+    const auto& local_transform =
+        lowest_combined_clip_node.LocalTransformSpace().Unalias();
+    if (&local_transform != current_transform_)
+      EndTransform();
+    cc_list_.StartPaint();
+    cc_list_.push<cc::SaveOp>();
+    ApplyTransform(local_transform);
+    const bool antialias = true;
+    if (combined_clip_rect.IsRounded()) {
+      cc_list_.push<cc::ClipRRectOp>(SkRRect(combined_clip_rect),
+                                     SkClipOp::kIntersect, antialias);
+    } else {
+      cc_list_.push<cc::ClipRectOp>(
+          gfx::RectFToSkRect(combined_clip_rect.Rect()), SkClipOp::kIntersect,
+          antialias);
+    }
+    if (const auto& clip_path = lowest_combined_clip_node.ClipPath()) {
+      cc_list_.push<cc::ClipPathOp>(clip_path->GetSkPath(),
+                                    SkClipOp::kIntersect, antialias);
+    }
+    cc_list_.EndPaintOfPairedBegin();
 
-  PushState(StateEntry::kClip);
+    PushState(StateEntry::kClip);
+    current_transform_ = &local_transform;
+  }
   current_clip_ = &lowest_combined_clip_node;
-  current_transform_ = &local_transform;
 }
 
 bool HasRealEffects(const EffectPaintPropertyNode& current,
@@ -609,7 +630,7 @@
 void ConversionContext::EndEffect() {
 #if DCHECK_IS_ON()
   const auto& previous_state = state_stack_.back();
-  DCHECK_EQ(previous_state.type, StateEntry::kEffect);
+  DCHECK(previous_state.IsEffect());
   if (!previous_state.has_pre_cap_effect_hierarchy_issue)
     DCHECK_EQ(current_effect_->UnaliasedParent(), previous_state.effect);
   DCHECK_EQ(current_clip_, previous_state.clip);
@@ -640,20 +661,20 @@
 }
 
 void ConversionContext::EndClips() {
-  while (state_stack_.size() && state_stack_.back().type == StateEntry::kClip)
+  while (state_stack_.size() && state_stack_.back().IsClip())
     EndClip();
 }
 
 void ConversionContext::EndClip() {
-  DCHECK_EQ(state_stack_.back().type, StateEntry::kClip);
+  DCHECK(state_stack_.back().IsClip());
   DCHECK_EQ(state_stack_.back().effect, current_effect_);
   EndTransform();
   PopState();
 }
 
 void ConversionContext::PushState(StateEntry::PairedType type) {
-  state_stack_.emplace_back(StateEntry{type, current_transform_, current_clip_,
-                                       current_effect_, previous_transform_});
+  state_stack_.emplace_back(type, current_transform_, current_clip_,
+                            current_effect_, previous_transform_);
   previous_transform_ = nullptr;
 }
 
@@ -661,7 +682,8 @@
   DCHECK_EQ(nullptr, previous_transform_);
 
   const auto& previous_state = state_stack_.back();
-  AppendRestore();
+  if (previous_state.NeedsRestore())
+    AppendRestore();
   current_transform_ = previous_state.transform;
   previous_transform_ = previous_state.previous_transform;
   current_clip_ = previous_state.clip;
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
index 3ba9947..d599eb1 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer_test.cc
@@ -1308,6 +1308,33 @@
   EXPECT_EFFECT_BOUNDS(7, 15, 93, 85, *output, 2);
 }
 
+TEST_P(PaintChunksToCcLayerTest, FilterClipExpanderUnderClip) {
+  // This tests the situation of crbug.com/1350017.
+  CompositorFilterOperations filter;
+  filter.AppendBlurFilter(10);
+  auto e1 = CreateFilterEffect(e0(), t0(), &c0(), filter);
+  auto c1 = CreateClip(c0(), t0(), FloatRoundedRect(10, 20, 30, 40));
+  auto clip_expander = CreatePixelMovingFilterClipExpander(*c1, *e1);
+  TestChunks chunks;
+  chunks.AddChunk(t0(), *clip_expander, *e1, gfx::Rect(5, 10, 200, 300),
+                  gfx::Rect(10, 15, 20, 30));
+
+  auto cc_list = base::MakeRefCounted<cc::DisplayItemList>(
+      cc::DisplayItemList::kTopLevelDisplayItemList);
+  PaintChunksToCcLayer::ConvertInto(chunks.Build(), PropertyTreeState::Root(),
+                                    gfx::Vector2dF(), *cc_list);
+  ASSERT_EQ(7u, cc_list->TotalOpCount());
+  auto output = cc_list->ReleaseAsRecord();
+  EXPECT_THAT(*output,
+              PaintRecordMatcher::Make(
+                  {cc::PaintOpType::SaveLayer,  // <e1>
+                   cc::PaintOpType::Save,
+                   cc::PaintOpType::ClipRect,    // <c1>
+                   cc::PaintOpType::DrawRecord,  // the DrawingDisplayItem
+                   cc::PaintOpType::Restore,     // </c1>
+                   cc::PaintOpType::Restore}));  // </e1>
+}
+
 TEST_P(PaintChunksToCcLayerTest,
        UpdateLayerPropertiesRegionCaptureDataSetOnLayer) {
   auto layer = cc::Layer::Create();
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index c10bd32..c860c600 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -394,12 +394,6 @@
     {
       name: "CoepReflection",
       status: "test",
-
-      // If a feature is implied by one supporting an origin trial, it must also
-      // support origin trial.
-      implied_by: ["AnonymousIframe"],
-      origin_trial_allows_third_party: true,
-      origin_trial_feature_name: "CoepReflection",
     },
     {
       name: "CompositeBGColorAnimation",
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index 92ceb17..abe1d387 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -407,6 +407,8 @@
 crbug.com/591099 external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/aspect-ratio-intrinsic-size-005.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/baseline-synthesis-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-flexbox/baseline-synthesis-003.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-flexbox/baseline-synthesis-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/dynamic-baseline-change.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox/dynamic-baseline-change-nested.html [ Failure ]
 crbug.com/1132627 external/wpt/css/css-flexbox/flex-minimum-width-flex-items-007.xht [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/baseline-synthesis-003.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/baseline-synthesis-003.html
new file mode 100644
index 0000000..98f0e7c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/baseline-synthesis-003.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#synthesize-baseline">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="display: flex; align-items: baseline; writing-mode: vertical-lr; text-orientation: sideways; background: red;">
+  <div style="height: 50px; width: 100px; background: green;"></div>
+  <div style="height: 50px; width: 100px; background: green; line-height: 0;">
+    <span style="width: 10px; height: 10px; display: inline-block;"></span>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/baseline-synthesis-004.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/baseline-synthesis-004.html
new file mode 100644
index 0000000..36c116c2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/baseline-synthesis-004.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-align-3/#synthesize-baseline">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div style="display: flex; align-items: baseline; writing-mode: vertical-lr; background: red;">
+  <div style="height: 50px; width: 100px; background: green;"></div>
+  <div style="height: 50px; width: 100px; background: green; line-height: 0;">
+    <span style="width: 100px; height: 10px; display: inline-block;"></span>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/nested-with-multicol-table-cell.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/nested-with-multicol-table-cell.html
new file mode 100644
index 0000000..abb99c6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/nested-with-multicol-table-cell.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1347322">
+<div style="columns:2;">
+  <div style="columns:2; margin-top:8px;">
+    text
+    <div style="display:table-cell; columns:2;"></div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/README.md b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/README.md
index 60c415f..abf059e4 100644
--- a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/README.md
+++ b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/README.md
@@ -1,16 +1,14 @@
 # Data-driven import maps tests
 
 In this directory, test inputs and expectations are expressed as JSON files.
-This is in order to share the same JSON files between WPT tests and Jest-based
-tests for the reference JavaScript implementation at [WICG repository](https://github.com/WICG/import-maps/tree/master/reference-implementation).
+This is in order to share the same JSON files between WPT tests and other
+implementations that might not run the full WPT suite, e.g. server-side
+JavaScript runtimes or the [JavaScript reference implementation](https://github.com/WICG/import-maps/tree/master/reference-implementation).
 
 ## Basics
 
 A **test object** describes a set of parameters (import maps and base URLs) and test expectations.
-Test expectations can be:
-
-- Expected resulting URLs for specifiers (resolution tests), or
-- Expected parsed import maps (parsing tests).
+Test expectations consist of the expected resulting URLs for specifiers.
 
 Each JSON file under [resources/](resources/) directory consists of a test object.
 A minimum test object would be:
@@ -38,11 +36,10 @@
     - In WPT tests, this is used for the test name of `promise_test()` together with specifier to be resolved, like `"Main test name: a"`.
 - `importMap` (object or string): the import map to be attached.
 - `importMapBaseURL` (string): the base URL used for [parsing the import map](https://wicg.github.io/import-maps/#parse-an-import-map-string).
-- (resolution tests only) `expectedResults` (object; string to (string or null)): resolution test cases.
+- `expectedResults` (object; string to (string or null)): resolution test cases.
     - The keys are specifiers to be resolved.
     - The values are expected resolved URLs. If `null`, resolution should fail.
-- (resolution tests only) `baseURL` (string): the base URL used in [resolving a specifier](https://wicg.github.io/import-maps/#resolve-a-module-specifier) for each specifiers.
-- (parsing tests only) `expectedParsedImportMap` (object): the expected parsed import map for parsing test cases.
+- `baseURL` (string): the base URL used in [resolving a specifier](https://wicg.github.io/import-maps/#resolve-a-module-specifier) for each specifiers.
 
 Optional fields:
 
@@ -83,3 +80,8 @@
 
 Child test objects inherit fields from their parent test object.
 In the example above, the child test objects specifies `baseURL` fields, while they inherits other fields (e.g. `importMapBaseURL`) from the top-level test object.
+
+## TODO
+
+The `parsing-*.json` files are not currently used by the WPT harness. We should
+convert them to resolution tests.
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/parsing-internal.https.html b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/parsing-internal.https.html
deleted file mode 100644
index 7d45ae8..0000000
--- a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/parsing-internal.https.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE html>
-<meta name="timeout" content="long">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
-<script>
-// All parsing tests requires Chromium's internal methods.
-globalThis.useInternalMethods = true;
-</script>
-<body>
-<script type="module">
-import { runTestsFromJSON, setupGlobalCleanup } from "./resources/test-helper.js";
-
-const promises = [];
-
-for (const json of [
-  'resources/parsing-addresses-absolute.json',
-  'resources/parsing-addresses-invalid.json',
-  'resources/parsing-addresses.json',
-  'resources/parsing-invalid-json.json',
-  'resources/parsing-schema-normalization.json',
-  'resources/parsing-schema-scope.json',
-  'resources/parsing-schema-specifier-map.json',
-  'resources/parsing-schema-toplevel.json',
-  'resources/parsing-scope-keys.json',
-  'resources/parsing-specifier-keys.json',
-  'resources/parsing-trailing-slashes.json',
-]) {
-  promise_test(() => {
-      const promise = runTestsFromJSON(json);
-      promises.push(promise);
-      return promise;
-    },
-    "Test helper: fetching and sanity checking test JSON: " + json);
-}
-
-Promise.all(promises).then(setupGlobalCleanup);
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resolving-internal.https.html b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resolving-internal.https.html
deleted file mode 100644
index d75bebba..0000000
--- a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resolving-internal.https.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<meta name="timeout" content="long">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
-<script>
-// This test file is for resolution tests that require Chromium's internal
-// methods.
-// For tests that don't use Chromium's internal methods, see
-// resolving.https.html.
-globalThis.useInternalMethods = true;
-</script>
-<body>
-<script type="module">
-import { runTestsFromJSON, setupGlobalCleanup } from "./resources/test-helper.js";
-
-const promises = [];
-
-for (const json of [
-  'resources/empty-import-map-internal.json',
-  'resources/url-specifiers-schemes-internal.json'
-]) {
-  promise_test(() => {
-      const promise = runTestsFromJSON(json);
-      promises.push(promise);
-      return promise;
-    },
-    "Test helper: fetching and sanity checking test JSON: " + json);
-}
-
-Promise.all(promises).then(setupGlobalCleanup);
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resolving.html b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resolving.html
new file mode 100644
index 0000000..bcf3d1de
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resolving.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta name="variant" content="?data-url-prefix.json">
+<meta name="variant" content="?empty-import-map.json">
+<meta name="variant" content="?overlapping-entries.json">
+<meta name="variant" content="?packages-via-trailing-slashes.json">
+<meta name="variant" content="?resolving-null.json">
+<meta name="variant" content="?scopes-exact-vs-prefix.json">
+<meta name="variant" content="?scopes.json">
+<meta name="variant" content="?tricky-specifiers.json">
+<meta name="variant" content="?url-specifiers-schemes.json">
+<meta name="variant" content="?url-specifiers.json">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script type="module">
+import { runTestsFromJSON } from "./resources/test-helper.js";
+
+const filename = location.search.substring(1);
+promise_test(
+  () => runTestsFromJSON('resources/' + filename),
+  "Test helper: fetching and sanity checking test JSON: " + filename);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resolving.https.html b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resolving.https.html
deleted file mode 100644
index 40b7ef5..0000000
--- a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resolving.https.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<meta name="timeout" content="long">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
-<body>
-<script type="module">
-import { runTestsFromJSON, setupGlobalCleanup } from "./resources/test-helper.js";
-
-const promises = [];
-
-for (const json of [
-  'resources/scopes.json',
-  'resources/empty-import-map.json',
-  'resources/packages-via-trailing-slashes.json',
-  'resources/tricky-specifiers.json',
-  'resources/url-specifiers.json',
-  'resources/data-base-url.json',
-  'resources/scopes-exact-vs-prefix.json',
-  'resources/overlapping-entries.json',
-  'resources/resolving-null.json',
-]) {
-  promise_test(() => {
-      const promise = runTestsFromJSON(json);
-      promises.push(promise);
-      return promise;
-    },
-    "Test helper: fetching and sanity checking test JSON: " + json);
-}
-
-Promise.all(promises).then(setupGlobalCleanup);
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/data-base-url.json b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/data-url-prefix.json
similarity index 72%
rename from third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/data-base-url.json
rename to third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/data-url-prefix.json
index 81fcf08..980f6e00 100644
--- a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/data-base-url.json
+++ b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/data-url-prefix.json
@@ -6,9 +6,9 @@
   },
   "importMapBaseURL": "https://example.com/app/index.html",
   "baseURL": "https://example.com/js/app.mjs",
-  "name": "data: base URL (?)",
+  "name": "data: URL prefix",
   "tests": {
-    "should favor the most-specific key": {
+    "should not resolve since you can't resolve relative to a data: URL": {
       "expectedResults": {
         "foo/bar": null
       }
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/empty-import-map-internal.json b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/empty-import-map-internal.json
deleted file mode 100644
index 42033a2c..0000000
--- a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/empty-import-map-internal.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "importMap": {},
-  "importMapBaseURL": "https://example.com/app/index.html",
-  "baseURL": "https://example.com/js/app.mjs",
-  "tests": {
-    "non-HTTPS fetch scheme absolute URLs": {
-      "expectedResults": {
-        "about:fetch-scheme": "about:fetch-scheme"
-      }
-    },
-    "non-fetch scheme absolute URLs": {
-      "expectedResults": {
-        "about:fetch-scheme": "about:fetch-scheme",
-        "mailto:non-fetch-scheme": "mailto:non-fetch-scheme",
-        "import:non-fetch-scheme": "import:non-fetch-scheme",
-        "javascript:non-fetch-scheme": "javascript:non-fetch-scheme",
-        "wss:non-fetch-scheme": "wss://non-fetch-scheme/"
-      }
-    }
-  }
-}
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/empty-import-map.json b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/empty-import-map.json
index ff85a6d..f488759 100644
--- a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/empty-import-map.json
+++ b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/empty-import-map.json
@@ -42,6 +42,20 @@
         "https://invalid-url.com:demo": null,
         "http://[invalid-url.com]/": null
       }
+    },
+    "non-HTTPS fetch scheme absolute URLs": {
+      "expectedResults": {
+        "about:fetch-scheme": "about:fetch-scheme"
+      }
+    },
+    "non-fetch scheme absolute URLs": {
+      "expectedResults": {
+        "about:fetch-scheme": "about:fetch-scheme",
+        "mailto:non-fetch-scheme": "mailto:non-fetch-scheme",
+        "import:non-fetch-scheme": "import:non-fetch-scheme",
+        "javascript:non-fetch-scheme": "javascript:non-fetch-scheme",
+        "wss:non-fetch-scheme": "wss://non-fetch-scheme/"
+      }
     }
   }
 }
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/test-helper-iframe.js b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/test-helper-iframe.js
index 597955f..3f38a5f0 100644
--- a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/test-helper-iframe.js
+++ b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/test-helper-iframe.js
@@ -1,5 +1,5 @@
 // Handle errors around fetching, parsing and registering import maps.
-const onScriptError = event => {
+window.onScriptError = event => {
   window.registrationResult = {type: 'FetchError', error: event.error};
   return false;
 };
@@ -14,90 +14,33 @@
 // objects themselves and re-create error objects later, to avoid
 // issues around serializing error objects which is a quite new feature.
 window.addEventListener('message', event => {
-  if (event.data.action === 'prepareResolve') {
-    // To get the result of #resolve-a-module-specifier given a script
-    // (with base URL = |baseURL|) and |specifier|, the service worker
-    // first serves an importer script with response URL = |baseURL|:
-    //     window.importHelper = (specifier) => import(specifier);
-    // This is to use |baseURL| as the referringScript's base URL.
-
-    // Step 1. Signal the service worker to serve
-    // the importer script for the next fetch request.
-    parent.worker.postMessage('serveImporterScript');
-  } else if (event.data.action === 'resolve') {
-    if (event.data.expectedURL === null ||
-        new URL(event.data.expectedURL).protocol === 'https:') {
-      // Testing without internal methods:
-      // If the resolution is expected to fail (null case here),
-      // we can test the failure just by catching the exception.
-      // If the expected URL is HTTPS, we can test the result by
-      // intercepting requests by service workers.
-
-      // Step 3. Evaluate the importer script as a classic script,
-      // in order to prevent |baseURL| from being mapped by import maps.
-      const script = document.createElement('script');
-      script.onload = () => {
-        // Step 4. Trigger dynamic import from |baseURL|.
-        importHelper(event.data.specifier)
-          .then(module => {
-              // Step 5. Service worker responds with a JSON containing
-              // the request URL for the dynamic import
-              // (= the result of #resolve-a-module-specifier).
-              parent.postMessage({type: 'ResolutionSuccess',
-                                  result: module.response.url},
-                                 '*');
-            })
-          .catch(e => {
-              parent.postMessage(
-                  {type: 'Failure', result: e.name, message: e.message},
-                  '*');
-            });
-      };
-      script.src = event.data.baseURL;
-      document.body.appendChild(script);
-    } else {
-      // Testing with internal methods.
-      // For example, the resolution results are data: URLs.
-      if (!event.data.useInternalMethods) {
-        parent.postMessage(
-            {type: 'Failure',
-             result: 'Error',
-             message: 'internals.resolveModuleSpecifier is not available'},
-            '*');
-        return;
-      }
-      try {
-        const result = internals.resolveModuleSpecifier(
-          event.data.specifier,
-          event.data.baseURL,
-          document);
-        parent.postMessage(
-            {type: 'ResolutionSuccess', result: result}, '*');
-      } catch (e) {
-        parent.postMessage(
-            {type: 'Failure', result: e.name, message: e.message}, '*');
-      }
-    }
-  } else if (event.data.action === 'getParsedImportMap') {
-    if (!event.data.useInternalMethods) {
-      parent.postMessage(
-          {type: 'Failure',
-           result: 'Error',
-           message: 'internals.getParsedImportMap is not available'},
-          '*');
-    }
-    try {
-      parent.postMessage({
-          type: 'GetParsedImportMapSuccess',
-          result: internals.getParsedImportMap(document)}, '*');
-    } catch (e) {
-      parent.postMessage(
-          {type: 'Failure', result: e.name, message: e.message}, '*');
-    }
-  } else {
+  if (event.data.action !== 'resolve') {
     parent.postMessage({
         type: 'Failure',
         result: 'Error',
         message: 'Invalid Action: ' + event.data.action}, '*');
+    return;
   }
+
+  // To respond to a resolution request, we:
+  // 1. Save the specifier to resolve into a global.
+  // 2. Update the document's base URL to the requested base URL.
+  // 3. Create a new inline script, parsed with that base URL, which
+  //    resolves the saved specifier using import.meta.resolve(), and
+  //    sents the result to the parent window.
+  window.specifierToResolve = event.data.specifier;
+  document.querySelector('base').href = event.data.baseURL;
+
+  const inlineScript = document.createElement('script');
+  inlineScript.type = 'module';
+  inlineScript.textContent = `
+    try {
+      const result = import.meta.resolve(window.specifierToResolve);
+      parent.postMessage({type: 'ResolutionSuccess', result}, '*');
+    } catch (e) {
+      parent.postMessage(
+          {type: 'Failure', result: e.name, message: e.message}, '*');
+    }
+  `;
+  document.body.append(inlineScript);
 });
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/test-helper.js b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/test-helper.js
index 579fd52..e89b639 100644
--- a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/test-helper.js
+++ b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/test-helper.js
@@ -1,31 +1,8 @@
 setup({allow_uncaught_exception : true});
 
-// Set window.useInternalMethods = true when needed && available.
-
-let registration;
-const scope = './scope/';
-
-// Global setup: this must be the first promise_test.
-promise_test(async (t) => {
-  const script = 'service-worker.js';
-
-  registration =
-      await service_worker_unregister_and_register(t, script, scope);
-  window.worker = registration.installing;
-  await wait_for_state(t, window.worker, 'activated');
-}, 'global setup');
-
-export function setupGlobalCleanup() {
-  // Global cleanup: the final promise_test.
-  promise_test(() => {
-     return registration.unregister();
-  }, 'global cleanup');
-}
-
 // Creates a new Document (via <iframe>) and add an inline import map.
-function parse(importMap, importMapBaseURL) {
+function createTestIframe(importMap, importMapBaseURL) {
   return new Promise(resolve => {
-    const importMapString = JSON.stringify(importMap);
     const iframe = document.createElement('iframe');
 
     window.addEventListener('message', event => {
@@ -36,35 +13,14 @@
       },
       {once: true});
 
-    const testHTML = `
-      <body>
-      <script src="${location.origin}/import-maps/data-driven/resources/test-helper-iframe.js"></script>
-      <script type="importmap" onerror="onScriptError(event)">
-      ${importMapString}
-      </script>
-      <script type="module">
-        if (!window.registrationResult) {
-          window.registrationResult = {type: 'Success'};
-        }
-        window.removeEventListener('error', window.windowErrorHandler);
-        parent.postMessage(window.registrationResult, '*');
-      </script>
-      </body>
-    `;
+    const testHTML = createTestHTML(importMap, importMapBaseURL);
 
     if (new URL(importMapBaseURL).protocol === 'data:') {
-      if (!window.useInternalMethods) {
-        throw new Error(
-            'Import maps with base URL = data: URL requires internal methods');
-      }
       iframe.src = 'data:text/html;base64,' + btoa(testHTML);
     } else {
-      // Set the src to `scope` in order to make requests from `iframe`
-      // intercepted by the service worker.
-      iframe.src = scope;
+      iframe.src = '/common/blank.html';
       iframe.onload = () => {
-        iframe.contentDocument.write(
-            `<base href="${importMapBaseURL}">` + testHTML);
+        iframe.contentDocument.write(testHTML);
         iframe.contentDocument.close();
       };
     }
@@ -72,9 +28,29 @@
   });
 }
 
-// Returns a promise that is resolved with the resulting URL.
-// `expectedURL` is a string, or null if to be thrown.
-function resolve(specifier, parsedImportMap, baseURL, expectedURL) {
+function createTestHTML(importMap, importMapBaseURL) {
+  return `
+    <!DOCTYPE html>
+    <script src="${location.origin}/import-maps/data-driven/resources/test-helper-iframe.js"></script>
+
+    <base href="${importMapBaseURL}">
+    <script type="importmap" onerror="onScriptError(event)">
+    ${JSON.stringify(importMap)}
+    </script>
+
+    <script type="module">
+      if (!window.registrationResult) {
+        window.registrationResult = {type: 'Success'};
+      }
+      window.removeEventListener('error', window.windowErrorHandler);
+      parent.postMessage(window.registrationResult, '*');
+    </script>
+  `;
+}
+
+// Returns a promise that is resolved with the resulting URL, or rejected if
+// the resolution fails.
+function resolve(specifier, baseURL, iframe) {
   return new Promise((resolve, reject) => {
     window.addEventListener('message', event => {
         if (event.data.type === 'ResolutionSuccess') {
@@ -91,35 +67,10 @@
       },
       {once: true});
 
-    parsedImportMap.contentWindow.postMessage({action: 'prepareResolve'}, '*');
-
-    navigator.serviceWorker.addEventListener('message', event => {
-      // Step 2. After postMessage() at Step 1 is processed, the service worker
-      // sends back a message and the parent Window receives the message here
-      // and sends a 'resolve' message to the iframe.
-      parsedImportMap.contentWindow.postMessage(
-          {action: 'resolve',
-           specifier: specifier,
-           baseURL: baseURL,
-           expectedURL: expectedURL,
-           useInternalMethods: window.useInternalMethods},
-          '*');
-    }, {once: true});
-  });
-}
-
-// Returns a promise that is resolved with a serialized string of
-// a parsed import map JSON object.
-function getParsedImportMap(parsedImportMap) {
-  return new Promise((resolve, reject) => {
-    window.addEventListener('message', event => {
-        resolve(event.data.result);
-      },
-      {once: true});
-
-    parsedImportMap.contentWindow.postMessage(
-        {action: 'getParsedImportMap',
-         useInternalMethods: window.useInternalMethods}, '*');
+    iframe.contentWindow.postMessage(
+      {action: 'resolve', specifier, baseURL},
+      '*'
+    );
   });
 }
 
@@ -130,22 +81,6 @@
   }
 }
 
-// Sort keys and then stringify for comparison.
-function stringifyImportMap(importMap) {
-  function getKeys(m) {
-    if (typeof m !== 'object')
-      return [];
-
-    let keys = [];
-    for (const key in m) {
-      keys.push(key);
-      keys = keys.concat(getKeys(m[key]));
-    }
-    return keys;
-  }
-  return JSON.stringify(importMap, getKeys(importMap).sort());
-}
-
 async function runTests(j) {
   const tests = j.tests;
   delete j.tests;
@@ -153,7 +88,7 @@
   if (j.hasOwnProperty('importMap')) {
     assert_own_property(j, 'importMap');
     assert_own_property(j, 'importMapBaseURL');
-    j.parsedImportMap = await parse(j.importMap, j.importMapBaseURL);
+    j.iframe = await createTestIframe(j.importMap, j.importMapBaseURL);
     delete j.importMap;
     delete j.importMapBaseURL;
   }
@@ -161,7 +96,7 @@
   assert_no_extra_properties(
       j,
       ['expectedResults', 'expectedParsedImportMap',
-      'baseURL', 'name', 'parsedImportMap',
+      'baseURL', 'name', 'iframe',
       'importMap', 'importMapBaseURL',
       'link', 'details'],
       j.name);
@@ -174,56 +109,29 @@
         fullTestName = j.name + ': ' + testName;
       }
       tests[testName].name = fullTestName;
-      const k = Object.assign(Object.assign({}, j), tests[testName]);
+      const k = Object.assign({}, j, tests[testName]);
       await runTests(k);
     }
   } else {
     // Leaf node.
-    for (const key of ['parsedImportMap', 'name']) {
+    for (const key of ['iframe', 'name', 'expectedResults']) {
       assert_own_property(j, key, j.name);
     }
-    assert_true(j.hasOwnProperty('expectedResults') ||
-                j.hasOwnProperty('expectedParsedImportMap'),
-                'expectedResults or expectedParsedImportMap should exist');
 
-    // Resolution tests.
-    if (j.hasOwnProperty('expectedResults')) {
-      assert_own_property(j, 'baseURL');
-      assert_equals(
-          j.parsedImportMap.parseImportMapResult,
-          'Success',
-          'Import map registration should be successful for resolution tests');
-      for (const specifier in j.expectedResults) {
-        const expected = j.expectedResults[specifier];
-        promise_test(async t => {
-            if (expected === null) {
-              return promise_rejects_js(t, TypeError,
-                  resolve(specifier, j.parsedImportMap, j.baseURL, null));
-            } else {
-              // Should be resolved to `expected`.
-              const actual = await resolve(
-                  specifier, j.parsedImportMap, j.baseURL, expected);
-              assert_equals(actual, expected);
-            }
-          },
-          j.name + ': ' + specifier);
-      }
-    }
-
-    // Parsing tests.
-    if (j.hasOwnProperty('expectedParsedImportMap')) {
+    assert_equals(
+        j.iframe.parseImportMapResult,
+        'Success',
+        'Import map registration should be successful for resolution tests');
+    for (const [specifier, expected] of Object.entries(j.expectedResults)) {
       promise_test(async t => {
-        if (j.expectedParsedImportMap === null) {
-          assert_equals(j.parsedImportMap.parseImportMapResult, 'ParseError');
+        if (expected === null) {
+          return promise_rejects_js(t, TypeError, resolve(specifier, j.baseURL, j.iframe));
         } else {
-          const actualParsedImportMap =
-              await getParsedImportMap(j.parsedImportMap);
-          assert_equals(stringifyImportMap(JSON.parse(actualParsedImportMap)),
-                        stringifyImportMap(j.expectedParsedImportMap));
+          assert_equals(await resolve(specifier, j.baseURL, j.iframe), expected);
         }
-      }, j.name);
+      },
+      j.name + ': ' + specifier);
     }
-
   }
 }
 
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/url-specifiers-schemes-internal.json b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/url-specifiers-schemes.json
similarity index 100%
rename from third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/url-specifiers-schemes-internal.json
rename to third_party/blink/web_tests/external/wpt/import-maps/data-driven/resources/url-specifiers-schemes.json
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/service-worker.js b/third_party/blink/web_tests/external/wpt/import-maps/data-driven/service-worker.js
deleted file mode 100644
index 68f293b..0000000
--- a/third_party/blink/web_tests/external/wpt/import-maps/data-driven/service-worker.js
+++ /dev/null
@@ -1,28 +0,0 @@
-let serveImporterScript = false;
-
-self.addEventListener('message', event => {
-  serveImporterScript = true;
-  event.source.postMessage('Done');
-});
-
-self.addEventListener('fetch', event => {
-    if (event.request.url.indexOf('test-helper-iframe.js') >= 0) {
-      return;
-    }
-    if (serveImporterScript) {
-      serveImporterScript = false;
-      event.respondWith(
-        new Response(
-          'window.importHelper = (specifier) => import(specifier);',
-          {headers: {'Content-Type': 'text/javascript'}}
-        ));
-    } else {
-      event.respondWith(
-        new Response(
-          'export const response = ' +
-              JSON.stringify({url: event.request.url}) + ';',
-          {headers: {'Access-Control-Allow-Origin': '*',
-                     'Content-Type': 'text/javascript'}}
-        ));
-    }
-});
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/non-http-attributionsrc.js b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/non-http-attributionsrc.js
new file mode 100644
index 0000000..ab203c07
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/attribution-reporting/non-http-attributionsrc.js
@@ -0,0 +1,16 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function(testRunner) {
+  const {page, dp} = await testRunner.startBlank(
+      `Test that using a non-HTTP-family URL as an attributionsrc triggers an issue.`);
+
+  await dp.Audits.enable();
+
+  const issuePromise = dp.Audits.onceIssueAdded();
+  await page.loadHTML(`<img attributionsrc="wss://example.com/">`);
+  const issue = await issuePromise;
+  testRunner.log(issue.params.issue, 'Issue reported: ', ['violatingNodeId']);
+  testRunner.completeTest();
+})
diff --git a/third_party/blink/web_tests/media/track/track-cue-rendering-zero-dimension-crash.html b/third_party/blink/web_tests/media/track/track-cue-rendering-zero-dimension-crash.html
new file mode 100644
index 0000000..5cb9aea8
--- /dev/null
+++ b/third_party/blink/web_tests/media/track/track-cue-rendering-zero-dimension-crash.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<video src="../content/test.ogv" height="0"></video>
+<script>
+function animationFrame() {
+  return new Promise(resolve => { requestAnimationFrame(resolve); });
+}
+
+promise_test(async () => {
+  let v = document.querySelector('video');
+  let track = v.addTextTrack('subtitles', 'label', 'en');
+  track.mode = 'showing';
+  track.addCue(new VTTCue(1, 60, 'First subtitle'));
+  v.currentTime = 3;
+  await new Promise(resolve => { v.addEventListener('seeked', resolve, {once:true}); });
+  await animationFrame();
+  await animationFrame();
+  // Pass if no division-by-zero.
+}, 'crbug.com/1351153: Crash by zero height video');
+</script>
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/attribution-reporting/non-http-attributionsrc-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/attribution-reporting/non-http-attributionsrc-expected.txt
new file mode 100644
index 0000000..f758b75
--- /dev/null
+++ b/third_party/blink/web_tests/platform/generic/http/tests/inspector-protocol/attribution-reporting/non-http-attributionsrc-expected.txt
@@ -0,0 +1,12 @@
+Test that using a non-HTTP-family URL as an attributionsrc triggers an issue.
+Issue reported: {
+    code : AttributionReportingIssue
+    details : {
+        attributionReportingIssueDetails : {
+            invalidParameter : wss://example.com
+            violatingNodeId : <number>
+            violationType : UntrustworthyReportingOrigin
+        }
+    }
+}
+
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/README.md b/third_party/blink/web_tests/wpt_internal/import-maps/README.md
new file mode 100644
index 0000000..96e420ab
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/README.md
@@ -0,0 +1,15 @@
+# Import maps internal tests
+
+These tests are essentially unit tests of the import map parser. The only
+observable effect of an import map is how it impacts module resolution, which is
+tested in `external/wpt`. But it's nice to have these sorts of parsing unit
+tests too.
+
+## Format
+
+The format is similar to the resolution tests format, which is described in
+`external/wpt/import-maps/README.md`. The only differences are that for a given
+test object:
+
+* Instead of `expectedResults`, we have `expectedParsedImportMap`.
+* `baseURL` is not applicable and cannot appear.
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/parsing.html b/third_party/blink/web_tests/wpt_internal/import-maps/parsing.html
new file mode 100644
index 0000000..a8b62e1
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/parsing.html
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+
+<meta name="variant" content="?parsing-addresses-absolute.json">
+<meta name="variant" content="?parsing-addresses-invalid.json">
+<meta name="variant" content="?parsing-addresses.json">
+<meta name="variant" content="?parsing-invalid-json.json">
+<meta name="variant" content="?parsing-schema-normalization.json">
+<meta name="variant" content="?parsing-schema-scope.json">
+<meta name="variant" content="?parsing-schema-specifier-map.json">
+<meta name="variant" content="?parsing-schema-toplevel.json">
+<meta name="variant" content="?parsing-scope-keys.json">
+<meta name="variant" content="?parsing-specifier-keys.json">
+<meta name="variant" content="?parsing-trailing-slashes.json">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+
+const filename = location.search.substring(1);
+promise_test(async () => {
+  const res = await fetch('resources/' + filename);
+  const json = await res.json();
+  const tests = await jsonToTests(json);
+
+  for (const test of tests) {
+    promise_test(async t => {
+      const testHTML = `
+        <!DOCTYPE html>
+        <base href="${test.importMapBaseURL}">
+        <script type="importmap">
+        ${JSON.stringify(test.importMap)}
+        </scri` + `pt>
+        <script>
+        parent.postMessage(internals.getParsedImportMap(document), '*');
+        </scri` + `pt>
+      `;
+
+      const iframe = document.createElement('iframe');
+      if (new URL(test.importMapBaseURL).protocol === 'data:') {
+        iframe.src = 'data:text/html;base64,' + btoa(testHTML);
+      } else {
+        iframe.src = '/common/blank.html';
+        iframe.onload = () => {
+          iframe.contentDocument.write(testHTML);
+          iframe.contentDocument.close();
+        };
+      }
+      document.body.append(iframe);
+
+      let parsedImportMap = JSON.parse(await new Promise(resolve => {
+        window.onmessage = t.step_func(e => {
+          assert_equals(e.source, iframe.contentWindow);
+          resolve(e.data);
+        });
+      }));
+
+      // internals.getParsedImportMap() returns an empty object instead of null for parse failures.
+      // Translate it so the test comparison works as expected.
+      if (Object.keys(parsedImportMap).length === 0) {
+        parsedImportMap = null;
+      }
+
+      assert_equals(
+        stringifyImportMap(parsedImportMap),
+        stringifyImportMap(test.expectedParsedImportMap)
+      );
+    }, test.name);
+  }
+}, 'Data fetching and setup');
+
+function jsonToTests(json, inheritedProps = {}, name = '') {
+  const baseProps = {
+    importMap: orFallback(json, inheritedProps, 'importMap'),
+    importMapBaseURL: orFallback(json, inheritedProps, 'importMapBaseURL'),
+    expectedParsedImportMap: orFallback(json, inheritedProps, 'expectedParsedImportMap')
+  };
+
+  if (json.tests) {
+    // Parent node
+    return Object.entries(json.tests).flatMap(([subName, subJSON]) => {
+      const fullName = [name, json.name, subName].filter(Boolean).join(': ');
+      return jsonToTests(subJSON, baseProps, fullName);
+    });
+  } else {
+    // Leaf (test) node
+    return [{ name, ...baseProps }];
+  }
+}
+
+function orFallback(obj1, obj2, property) {
+  return obj1.hasOwnProperty(property) ? obj1[property] : obj2[property];
+}
+
+// Sort keys and then stringify for comparison.
+function stringifyImportMap(importMap) {
+  function getKeys(m) {
+    if (typeof m !== 'object')
+      return [];
+
+    let keys = [];
+    for (const key in m) {
+      keys.push(key);
+      keys = keys.concat(getKeys(m[key]));
+    }
+    return keys;
+  }
+  return JSON.stringify(importMap, getKeys(importMap).sort());
+}
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-addresses-absolute.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-addresses-absolute.json
new file mode 100644
index 0000000..b400439
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-addresses-absolute.json
@@ -0,0 +1,65 @@
+{
+  "name": "Absolute URL addresses",
+  "tests": {
+    "should only accept absolute URL addresses with fetch schemes": {
+      "importMap": {
+        "imports": {
+          "about": "about:good",
+          "blob": "blob:good",
+          "data": "data:good",
+          "file": "file:///good",
+          "filesystem": "filesystem:http://example.com/good/",
+          "http": "http://good/",
+          "https": "https://good/",
+          "ftp": "ftp://good/",
+          "import": "import:bad",
+          "mailto": "mailto:bad",
+          "javascript": "javascript:bad",
+          "wss": "wss:bad"
+        }
+      },
+      "importMapBaseURL": "https://base.example/path1/path2/path3",
+      "expectedParsedImportMap": {
+        "imports": {
+          "about": "about:good",
+          "blob": "blob:good",
+          "data": "data:good",
+          "file": "file:///good",
+          "filesystem": "filesystem:http://example.com/good/",
+          "http": "http://good/",
+          "https": "https://good/",
+          "ftp": "ftp://good/",
+          "import": "import:bad",
+          "javascript": "javascript:bad",
+          "mailto": "mailto:bad",
+          "wss": "wss://bad/"
+        },
+        "scopes": {}
+      }
+    },
+    "should parse absolute URLs, ignoring unparseable ones": {
+      "importMap": {
+        "imports": {
+          "unparseable2": "https://example.com:demo",
+          "unparseable3": "http://[www.example.com]/",
+          "invalidButParseable1": "https:example.org",
+          "invalidButParseable2": "https://///example.com///",
+          "prettyNormal": "https://example.net",
+          "percentDecoding": "https://ex%41mple.com/"
+        }
+      },
+      "importMapBaseURL": "https://base.example/path1/path2/path3",
+      "expectedParsedImportMap": {
+        "imports": {
+          "unparseable2": null,
+          "unparseable3": null,
+          "invalidButParseable1": "https://example.org/",
+          "invalidButParseable2": "https://example.com///",
+          "prettyNormal": "https://example.net/",
+          "percentDecoding": "https://example.com/"
+        },
+        "scopes": {}
+      }
+    }
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-addresses-invalid.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-addresses-invalid.json
new file mode 100644
index 0000000..4e5f182
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-addresses-invalid.json
@@ -0,0 +1,27 @@
+{
+  "name": "Other invalid addresses",
+  "tests": {
+    "should ignore unprefixed strings that are not absolute URLs": {
+      "importMap": {
+        "imports": {
+          "foo1": "bar",
+          "foo2": "\\bar",
+          "foo3": "~bar",
+          "foo4": "#bar",
+          "foo5": "?bar"
+        }
+      },
+      "importMapBaseURL": "https://base.example/path1/path2/path3",
+      "expectedParsedImportMap": {
+        "imports": {
+          "foo1": null,
+          "foo2": null,
+          "foo3": null,
+          "foo4": null,
+          "foo5": null
+        },
+        "scopes": {}
+      }
+    }
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-addresses.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-addresses.json
new file mode 100644
index 0000000..fe92709
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-addresses.json
@@ -0,0 +1,85 @@
+{
+  "name": "Relative URL-like addresses",
+  "tests": {
+    "should accept strings prefixed with ./, ../, or /": {
+      "importMap": {
+        "imports": {
+          "dotSlash": "./foo",
+          "dotDotSlash": "../foo",
+          "slash": "/foo"
+        }
+      },
+      "importMapBaseURL": "https://base.example/path1/path2/path3",
+      "expectedParsedImportMap": {
+        "imports": {
+          "dotSlash": "https://base.example/path1/path2/foo",
+          "dotDotSlash": "https://base.example/path1/foo",
+          "slash": "https://base.example/foo"
+        },
+        "scopes": {}
+      }
+    },
+    "should not accept strings prefixed with ./, ../, or / for data: base URLs": {
+      "importMap": {
+        "imports": {
+          "dotSlash": "./foo",
+          "dotDotSlash": "../foo",
+          "slash": "/foo"
+        }
+      },
+      "importMapBaseURL": "data:text/html,test",
+      "expectedParsedImportMap": {
+        "imports": {
+          "dotSlash": null,
+          "dotDotSlash": null,
+          "slash": null
+        },
+        "scopes": {}
+      }
+    },
+    "should accept the literal strings ./, ../, or / with no suffix": {
+      "importMap": {
+        "imports": {
+          "dotSlash": "./",
+          "dotDotSlash": "../",
+          "slash": "/"
+        }
+      },
+      "importMapBaseURL": "https://base.example/path1/path2/path3",
+      "expectedParsedImportMap": {
+        "imports": {
+          "dotSlash": "https://base.example/path1/path2/",
+          "dotDotSlash": "https://base.example/path1/",
+          "slash": "https://base.example/"
+        },
+        "scopes": {}
+      }
+    },
+    "should ignore percent-encoded variants of ./, ../, or /": {
+      "importMap": {
+        "imports": {
+          "dotSlash1": "%2E/",
+          "dotDotSlash1": "%2E%2E/",
+          "dotSlash2": ".%2F",
+          "dotDotSlash2": "..%2F",
+          "slash2": "%2F",
+          "dotSlash3": "%2E%2F",
+          "dotDotSlash3": "%2E%2E%2F"
+        }
+      },
+      "importMapBaseURL": "https://base.example/path1/path2/path3",
+      "expectedParsedImportMap": {
+        "imports": {
+          "dotSlash1": null,
+          "dotDotSlash1": null,
+          "dotSlash2": null,
+          "dotDotSlash2": null,
+          "slash2": null,
+          "dotSlash3": null,
+          "dotDotSlash3": null
+        },
+        "scopes": {}
+      }
+    }
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-invalid-json.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-invalid-json.json
new file mode 100644
index 0000000..1bd1c94
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-invalid-json.json
@@ -0,0 +1,6 @@
+{
+  "name": "Invalid JSON",
+  "importMapBaseURL": "https://base.example/",
+  "importMap": "{imports: {}}",
+  "expectedParsedImportMap": null
+}
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-normalization.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-normalization.json
new file mode 100644
index 0000000..a330bb8
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-normalization.json
@@ -0,0 +1,31 @@
+{
+  "name": "Normalization",
+  "importMapBaseURL": "https://base.example/",
+  "tests": {
+    "should normalize empty import maps to have imports and scopes keys": {
+      "importMap": {},
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {}
+      }
+    },
+    "should normalize an import map without imports to have imports": {
+      "importMap": {
+        "scopes": {}
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {}
+      }
+    },
+    "should normalize an import map without scopes to have scopes": {
+      "importMap": {
+        "imports": {}
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {}
+      }
+    }
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-scope.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-scope.json
new file mode 100644
index 0000000..04d0939
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-scope.json
@@ -0,0 +1,46 @@
+{
+  "name": "Mismatching scopes schema",
+  "importMapBaseURL": "https://base.example/",
+  "tests": {
+    "should throw if a scope's value is not an object": {
+      "expectedParsedImportMap": null,
+      "tests": {
+        "null": {
+          "importMap": {
+            "scopes": {
+              "https://example.com/": null
+            }
+          }
+        },
+        "boolean": {
+          "importMap": {
+            "scopes": {
+              "https://example.com/": true
+            }
+          }
+        },
+        "number": {
+          "importMap": {
+            "scopes": {
+              "https://example.com/": 1
+            }
+          }
+        },
+        "string": {
+          "importMap": {
+            "scopes": {
+              "https://example.com/": "foo"
+            }
+          }
+        },
+        "array": {
+          "importMap": {
+            "scopes": {
+              "https://example.com/": []
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-specifier-map.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-specifier-map.json
new file mode 100644
index 0000000..7d7d4be
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-specifier-map.json
@@ -0,0 +1,44 @@
+{
+  "name": "Mismatching the specifier map schema",
+  "importMapBaseURL": "https://base.example/",
+  "tests": {
+    "should ignore entries where the address is not a string": {
+      "importMap": {
+        "imports": {
+          "null": null,
+          "boolean": true,
+          "number": 1,
+          "object": {},
+          "array": [],
+          "array2": [
+            "https://example.com/"
+          ],
+          "string": "https://example.com/"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {
+          "null": null,
+          "boolean": null,
+          "number": null,
+          "object": null,
+          "array": null,
+          "array2": null,
+          "string": "https://example.com/"
+        },
+        "scopes": {}
+      }
+    },
+    "should ignore entries where the specifier key is an empty string": {
+      "importMap": {
+        "imports": {
+          "": "https://example.com/"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {}
+      }
+    }
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-toplevel.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-toplevel.json
new file mode 100644
index 0000000..278cad2
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-schema-toplevel.json
@@ -0,0 +1,97 @@
+{
+  "name": "Mismatching the top-level schema",
+  "importMapBaseURL": "https://base.example/",
+  "tests": {
+    "should throw for top-level non-objects": {
+      "expectedParsedImportMap": null,
+      "tests": {
+        "null": {
+          "importMap": null
+        },
+        "boolean": {
+          "importMap": true
+        },
+        "number": {
+          "importMap": 1
+        },
+        "string": {
+          "importMap": "foo"
+        },
+        "array": {
+          "importMap": []
+        }
+      }
+    },
+    "should throw if imports is a non-object": {
+      "expectedParsedImportMap": null,
+      "tests": {
+        "null": {
+          "importMap": {
+            "imports": null
+          }
+        },
+        "boolean": {
+          "importMap": {
+            "imports": true
+          }
+        },
+        "number": {
+          "importMap": {
+            "imports": 1
+          }
+        },
+        "string": {
+          "importMap": {
+            "imports": "foo"
+          }
+        },
+        "array": {
+          "importMap": {
+            "imports": []
+          }
+        }
+      }
+    },
+    "should throw if scopes is a non-object": {
+      "expectedParsedImportMap": null,
+      "tests": {
+        "null": {
+          "importMap": {
+            "scopes": null
+          }
+        },
+        "boolean": {
+          "importMap": {
+            "scopes": true
+          }
+        },
+        "number": {
+          "importMap": {
+            "scopes": 1
+          }
+        },
+        "string": {
+          "importMap": {
+            "scopes": "foo"
+          }
+        },
+        "array": {
+          "importMap": {
+            "scopes": []
+          }
+        }
+      }
+    },
+    "should ignore unspecified top-level entries": {
+      "importMap": {
+        "imports": {},
+        "new-feature": {},
+        "scops": {}
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {}
+      }
+    }
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-scope-keys.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-scope-keys.json
new file mode 100644
index 0000000..4b2f1eea
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-scope-keys.json
@@ -0,0 +1,191 @@
+{
+  "importMapBaseURL": "https://base.example/path1/path2/path3",
+  "tests": {
+    "Relative URL scope keys should work with no prefix": {
+      "importMap": {
+        "scopes": {
+          "foo": {}
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {
+          "https://base.example/path1/path2/foo": {}
+        }
+      }
+    },
+    "Relative URL scope keys should work with ./, ../, and / prefixes": {
+      "importMap": {
+        "scopes": {
+          "./foo": {},
+          "../foo": {},
+          "/foo": {}
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {
+          "https://base.example/path1/path2/foo": {},
+          "https://base.example/path1/foo": {},
+          "https://base.example/foo": {}
+        }
+      }
+    },
+    "Absolute URL scope keys should ignore relative URL scope keys when the base URL is a data: URL": {
+      "importMap": {
+        "scopes": {
+          "./foo": {},
+          "../foo": {},
+          "/foo": {}
+        }
+      },
+      "importMapBaseURL": "data:text/html,test",
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {}
+      }
+    },
+    "Relative URL scope keys should work with ./, ../, or / with no suffix": {
+      "importMap": {
+        "scopes": {
+          "./": {},
+          "../": {},
+          "/": {}
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {
+          "https://base.example/path1/path2/": {},
+          "https://base.example/path1/": {},
+          "https://base.example/": {}
+        }
+      }
+    },
+    "Relative URL scope keys should work with /s, ?s, and #s": {
+      "importMap": {
+        "scopes": {
+          "foo/bar?baz#qux": {}
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {
+          "https://base.example/path1/path2/foo/bar?baz#qux": {}
+        }
+      }
+    },
+    "Relative URL scope keys should work with an empty string scope key": {
+      "importMap": {
+        "scopes": {
+          "": {}
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {
+          "https://base.example/path1/path2/path3": {}
+        }
+      }
+    },
+    "Relative URL scope keys should work with / suffixes": {
+      "importMap": {
+        "scopes": {
+          "foo/": {},
+          "./foo/": {},
+          "../foo/": {},
+          "/foo/": {},
+          "/foo//": {}
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {
+          "https://base.example/path1/path2/foo/": {},
+          "https://base.example/path1/foo/": {},
+          "https://base.example/foo/": {},
+          "https://base.example/foo//": {}
+        }
+      }
+    },
+    "Relative URL scope keys should deduplicate based on URL parsing rules": {
+      "importMap": {
+        "scopes": {
+          "foo/\\": {
+            "1": "./a"
+          },
+          "foo//": {
+            "2": "./b"
+          },
+          "foo\\\\": {
+            "3": "./c"
+          }
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {
+          "https://base.example/path1/path2/foo//": {
+            "3": "https://base.example/path1/path2/c"
+          }
+        }
+      }
+    },
+    "Absolute URL scope keys should accept all absolute URL scope keys, with or without fetch schemes": {
+      "importMap": {
+        "scopes": {
+          "about:good": {},
+          "blob:good": {},
+          "data:good": {},
+          "file:///good": {},
+          "filesystem:http://example.com/good/": {},
+          "http://good/": {},
+          "https://good/": {},
+          "ftp://good/": {},
+          "import:bad": {},
+          "mailto:bad": {},
+          "javascript:bad": {},
+          "wss:ba": {}
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {
+          "about:good": {},
+          "blob:good": {},
+          "data:good": {},
+          "file:///good": {},
+          "filesystem:http://example.com/good/": {},
+          "http://good/": {},
+          "https://good/": {},
+          "ftp://good/": {},
+          "import:bad": {},
+          "mailto:bad": {},
+          "javascript:bad": {},
+          "wss://ba/": {}
+        }
+      }
+    },
+    "Absolute URL scope keys should parse absolute URL scope keys, ignoring unparseable ones": {
+      "importMap": {
+        "scopes": {
+          "https://example.com:demo": {},
+          "http://[www.example.com]/": {},
+          "https:example.org": {},
+          "https://///example.com///": {},
+          "https://example.net": {},
+          "https://ex%41mple.com/foo/": {}
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {
+          "https://base.example/path1/path2/example.org": {},
+          "https://example.com///": {},
+          "https://example.net/": {},
+          "https://example.com/foo/": {}
+        }
+      }
+    }
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-specifier-keys.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-specifier-keys.json
new file mode 100644
index 0000000..b2d9cf47
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-specifier-keys.json
@@ -0,0 +1,209 @@
+{
+  "importMapBaseURL": "https://base.example/path1/path2/path3",
+  "tests": {
+    "Relative URL specifier keys should absolutize strings prefixed with ./, ../, or / into the corresponding URLs": {
+      "importMap": {
+        "imports": {
+          "./foo": "/dotslash",
+          "../foo": "/dotdotslash",
+          "/foo": "/slash"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {
+          "https://base.example/path1/path2/foo": "https://base.example/dotslash",
+          "https://base.example/path1/foo": "https://base.example/dotdotslash",
+          "https://base.example/foo": "https://base.example/slash"
+        },
+        "scopes": {}
+      }
+    },
+    "Relative URL specifier keys should not absolutize strings prefixed with ./, ../, or / with a data: URL base": {
+      "importMap": {
+        "imports": {
+          "./foo": "https://example.com/dotslash",
+          "../foo": "https://example.com/dotdotslash",
+          "/foo": "https://example.com/slash"
+        }
+      },
+      "importMapBaseURL": "data:text/html,",
+      "expectedParsedImportMap": {
+        "imports": {
+          "./foo": "https://example.com/dotslash",
+          "../foo": "https://example.com/dotdotslash",
+          "/foo": "https://example.com/slash"
+        },
+        "scopes": {}
+      }
+    },
+    "Relative URL specifier keys should absolutize the literal strings ./, ../, or / with no suffix": {
+      "importMap": {
+        "imports": {
+          "./": "/dotslash/",
+          "../": "/dotdotslash/",
+          "/": "/slash/"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {
+          "https://base.example/path1/path2/": "https://base.example/dotslash/",
+          "https://base.example/path1/": "https://base.example/dotdotslash/",
+          "https://base.example/": "https://base.example/slash/"
+        },
+        "scopes": {}
+      }
+    },
+    "Relative URL specifier keys should work with /s, ?s, and #s": {
+      "importMap": {
+        "imports": {
+          "./foo/bar?baz#qux": "/foo"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {
+          "https://base.example/path1/path2/foo/bar?baz#qux": "https://base.example/foo"
+        },
+        "scopes": {}
+      }
+    },
+    "Relative URL specifier keys should ignore an empty string key": {
+      "importMap": {
+        "imports": {
+          "": "/foo"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {},
+        "scopes": {}
+      }
+    },
+    "Relative URL specifier keys should treat percent-encoded variants of ./, ../, or / as bare specifiers": {
+      "importMap": {
+        "imports": {
+          "%2E/": "/dotSlash1/",
+          "%2E%2E/": "/dotDotSlash1/",
+          ".%2F": "/dotSlash2",
+          "..%2F": "/dotDotSlash2",
+          "%2F": "/slash2",
+          "%2E%2F": "/dotSlash3",
+          "%2E%2E%2F": "/dotDotSlash3"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {
+          "%2E/": "https://base.example/dotSlash1/",
+          "%2E%2E/": "https://base.example/dotDotSlash1/",
+          ".%2F": "https://base.example/dotSlash2",
+          "..%2F": "https://base.example/dotDotSlash2",
+          "%2F": "https://base.example/slash2",
+          "%2E%2F": "https://base.example/dotSlash3",
+          "%2E%2E%2F": "https://base.example/dotDotSlash3"
+        },
+        "scopes": {}
+      }
+    },
+    "Relative URL specifier keys should deduplicate based on URL parsing rules": {
+      "importMap": {
+        "imports": {
+          "./foo/\\": "/foo1",
+          "./foo//": "/foo2",
+          "./foo\\\\": "/foo3"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {
+          "https://base.example/path1/path2/foo//": "https://base.example/foo3"
+        },
+        "scopes": {}
+      }
+    },
+    "Absolute URL specifier keys should accept all absolute URL specifier keys, with or without fetch schemes": {
+      "importMap": {
+        "imports": {
+          "about:good": "/about",
+          "blob:good": "/blob",
+          "data:good": "/data",
+          "file:///good": "/file",
+          "filesystem:http://example.com/good/": "/filesystem/",
+          "http://good/": "/http/",
+          "https://good/": "/https/",
+          "ftp://good/": "/ftp/",
+          "import:bad": "/import",
+          "mailto:bad": "/mailto",
+          "javascript:bad": "/javascript",
+          "wss:bad": "/wss"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {
+          "about:good": "https://base.example/about",
+          "blob:good": "https://base.example/blob",
+          "data:good": "https://base.example/data",
+          "file:///good": "https://base.example/file",
+          "filesystem:http://example.com/good/": "https://base.example/filesystem/",
+          "http://good/": "https://base.example/http/",
+          "https://good/": "https://base.example/https/",
+          "ftp://good/": "https://base.example/ftp/",
+          "import:bad": "https://base.example/import",
+          "mailto:bad": "https://base.example/mailto",
+          "javascript:bad": "https://base.example/javascript",
+          "wss://bad/": "https://base.example/wss"
+        },
+        "scopes": {}
+      }
+    },
+    "Absolute URL specifier keys should parse absolute URLs, treating unparseable ones as bare specifiers": {
+      "importMap": {
+        "imports": {
+          "https://example.com:demo": "/unparseable2",
+          "http://[www.example.com]/": "/unparseable3/",
+          "https:example.org": "/invalidButParseable1/",
+          "https://///example.com///": "/invalidButParseable2/",
+          "https://example.net": "/prettyNormal/",
+          "https://ex%41mple.com/": "/percentDecoding/"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {
+          "https://example.com:demo": "https://base.example/unparseable2",
+          "http://[www.example.com]/": "https://base.example/unparseable3/",
+          "https://example.org/": "https://base.example/invalidButParseable1/",
+          "https://example.com///": "https://base.example/invalidButParseable2/",
+          "https://example.net/": "https://base.example/prettyNormal/",
+          "https://example.com/": "https://base.example/percentDecoding/"
+        },
+        "scopes": {}
+      }
+    },
+    "Specifier keys should be sort correctly (issue #181) - Test #1": {
+      "importMap": {
+        "imports": {
+          "https://example.com/aaa": "https://example.com/aaa",
+          "https://example.com/a": "https://example.com/a"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {
+          "https://example.com/aaa": "https://example.com/aaa",
+          "https://example.com/a": "https://example.com/a"
+        },
+        "scopes": {}
+      }
+    },
+    "Specifier keys should be sort correctly (issue #181) - Test #2": {
+      "importMap": {
+        "imports": {
+          "https://example.com/a": "https://example.com/a",
+          "https://example.com/aaa": "https://example.com/aaa"
+        }
+      },
+      "expectedParsedImportMap": {
+        "imports": {
+          "https://example.com/aaa": "https://example.com/aaa",
+          "https://example.com/a": "https://example.com/a"
+        },
+        "scopes": {}
+      }
+    }
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-trailing-slashes.json b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-trailing-slashes.json
new file mode 100644
index 0000000..89c454fc
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/import-maps/resources/parsing-trailing-slashes.json
@@ -0,0 +1,15 @@
+{
+  "name": "Failing addresses: mismatched trailing slashes",
+  "importMap": {
+    "imports": {
+      "trailer/": "/notrailer"
+    }
+  },
+  "importMapBaseURL": "https://base.example/path1/path2/path3",
+  "expectedParsedImportMap": {
+    "imports": {
+      "trailer/": null
+    },
+    "scopes": {}
+  }
+}
diff --git a/third_party/eigen3/README.chromium b/third_party/eigen3/README.chromium
index e319a4f..325de45 100644
--- a/third_party/eigen3/README.chromium
+++ b/third_party/eigen3/README.chromium
@@ -1,8 +1,8 @@
 Name: Eigen
 Short Name: eigen3
 URL: http://eigen.tuxfamily.org/
-Version: 0e187141679fdb91da33249d18cb79a011c0e2ea
-Date: 2022/07/14
+Version: 34780d8bd13d0af0cf17a22789ef286e8512594d
+Date: 2022/08/08
 License: MPL 2
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/ipcz/src/box_test.cc b/third_party/ipcz/src/box_test.cc
index ec814f1..f13203ab 100644
--- a/third_party/ipcz/src/box_test.cc
+++ b/third_party/ipcz/src/box_test.cc
@@ -136,6 +136,7 @@
     EXPECT_EQ(kMessage2, GetBlobContents(blob_handle));
   }
 
+  WaitForDirectRemoteLink(q);
   CloseAll({q, b});
 }
 
@@ -160,6 +161,7 @@
     EXPECT_EQ(IPCZ_RESULT_OK, Put(p, kMessage1, {&box, 1}));
   }
 
+  WaitForDirectRemoteLink(p);
   CloseAll({p, b});
 }
 
diff --git a/third_party/ipcz/src/ipcz/handle_type.h b/third_party/ipcz/src/ipcz/handle_type.h
index a143c5e..df08a27 100644
--- a/third_party/ipcz/src/ipcz/handle_type.h
+++ b/third_party/ipcz/src/ipcz/handle_type.h
@@ -21,7 +21,10 @@
   // DriverObject array and wraps it as a Box object.
   kBox = 1,
 
-  // TODO: Add an enumeration for relayed boxes.
+  // A placeholder for a box handle in a split parcel transmission. This occurs
+  // in the directly transmitted half of the parcel, and it signifies the
+  // existence of a corresponding DriverObject in the relayed half.
+  kRelayedBox = 2,
 };
 
 }  // namespace ipcz
diff --git a/third_party/ipcz/src/ipcz/message.cc b/third_party/ipcz/src/ipcz/message.cc
index 5872d6b..1b686ed 100644
--- a/third_party/ipcz/src/ipcz/message.cc
+++ b/third_party/ipcz/src/ipcz/message.cc
@@ -236,37 +236,12 @@
 
 bool Message::DeserializeUnknownType(const DriverTransport::RawMessage& message,
                                      const DriverTransport& transport) {
-  // Copy the data into a local message object to avoid any TOCTOU issues in
-  // case `data` is in unsafe shared memory.
-  data_.resize(message.data.size());
-  memcpy(data_.data(), message.data.data(), message.data.size());
-
-  // Validate the header. The message must at least be large enough to encode a
-  // v0 MessageHeader, and the encoded header size and version must make sense
-  // (e.g. version 0 size must be sizeof(MessageHeader))
-  if (data_.size() < sizeof(internal::MessageHeaderV0)) {
-    return false;
-  }
-
-  const auto& message_header =
-      *reinterpret_cast<const internal::MessageHeaderV0*>(data_.data());
-  if (message_header.version == 0) {
-    if (message_header.size != sizeof(internal::MessageHeaderV0)) {
-      return false;
-    }
-  } else {
-    if (message_header.size < sizeof(internal::MessageHeaderV0)) {
-      return false;
-    }
-  }
-
-  if (message_header.size > data_.size()) {
+  if (!CopyDataAndValidateHeader(message.data)) {
     return false;
   }
 
   // Validate and deserialize the DriverObject array.
-  const uint32_t driver_object_array_offset =
-      message_header.driver_object_data_array;
+  const uint32_t driver_object_array_offset = header().driver_object_data_array;
   bool all_driver_objects_ok = true;
   if (driver_object_array_offset > 0) {
     if (!IsArrayValid(*this, driver_object_array_offset,
@@ -295,16 +270,44 @@
   return all_driver_objects_ok;
 }
 
-bool Message::DeserializeFromTransport(
-    size_t params_size,
-    uint32_t params_current_version,
-    absl::Span<const internal::ParamMetadata> params_metadata,
-    const DriverTransport::RawMessage& message,
-    const DriverTransport& transport) {
-  if (!DeserializeUnknownType(message, transport)) {
+bool Message::CopyDataAndValidateHeader(absl::Span<const uint8_t> data) {
+  // Copy the data into a local message object to avoid any TOCTOU issues in
+  // case `data` is in unsafe shared memory.
+  data_.resize(data.size());
+  memcpy(data_.data(), data.data(), data.size());
+
+  // The message must at least be large enough to encode a v0 MessageHeader.
+  if (data_.size() < sizeof(internal::MessageHeaderV0)) {
     return false;
   }
 
+  // Version 0 header must match MsesageHeaderV0 size exactly. Newer unknown
+  // versions must not be smaller than that.
+  const auto& header =
+      *reinterpret_cast<const internal::MessageHeaderV0*>(data_.data());
+  if (header.version == 0) {
+    if (header.size != sizeof(internal::MessageHeaderV0)) {
+      return false;
+    }
+  } else {
+    if (header.size < sizeof(internal::MessageHeaderV0)) {
+      return false;
+    }
+  }
+
+  // The header's stated size (and thus the start of the parameter payload)
+  // must not run over the edge of the message.
+  if (header.size > data_.size()) {
+    return false;
+  }
+
+  return true;
+}
+
+bool Message::ValidateParameters(
+    size_t params_size,
+    uint32_t params_current_version,
+    absl::Span<const internal::ParamMetadata> params_metadata) {
   // Validate parameter data. There must be at least enough bytes following the
   // header to encode a StructHeader and to account for all parameter data.
   absl::Span<uint8_t> params_data = params_data_view();
@@ -383,4 +386,35 @@
   return true;
 }
 
+bool Message::DeserializeFromTransport(
+    size_t params_size,
+    uint32_t params_current_version,
+    absl::Span<const internal::ParamMetadata> params_metadata,
+    const DriverTransport::RawMessage& message,
+    const DriverTransport& transport) {
+  if (!DeserializeUnknownType(message, transport)) {
+    return false;
+  }
+
+  return ValidateParameters(params_size, params_current_version,
+                            params_metadata);
+}
+
+bool Message::DeserializeFromRelay(
+    size_t params_size,
+    uint32_t params_current_version,
+    absl::Span<const internal::ParamMetadata> params_metadata,
+    absl::Span<const uint8_t> data,
+    absl::Span<DriverObject> objects) {
+  if (!CopyDataAndValidateHeader(data)) {
+    return false;
+  }
+
+  driver_objects_.resize(objects.size());
+  std::move(objects.begin(), objects.end(), driver_objects_.begin());
+
+  return ValidateParameters(params_size, params_current_version,
+                            params_metadata);
+}
+
 }  // namespace ipcz
diff --git a/third_party/ipcz/src/ipcz/message.h b/third_party/ipcz/src/ipcz/message.h
index 7aa50d2..180f207 100644
--- a/third_party/ipcz/src/ipcz/message.h
+++ b/third_party/ipcz/src/ipcz/message.h
@@ -342,6 +342,19 @@
                                  data_.data());
   }
 
+  // Common helper for vaidation of an incoming message header and basic data
+  // payload size.
+  bool CopyDataAndValidateHeader(absl::Span<const uint8_t> data);
+
+  // Common helper to validate an encoded parameter structure against a specific
+  // message definition. Must only be called on a Message with `data_` already
+  // populated, the header already validated, and DriverObjects already
+  // deserialized into `driver_objects_`.
+  bool ValidateParameters(
+      size_t params_size,
+      uint32_t params_current_version,
+      absl::Span<const internal::ParamMetadata> params_metadata);
+
   // Attempts to deserialize a message from raw `data` and `handles` into `this`
   // message object, given the `params_size`, `params_current_version` and
   // `params_metadata`, which are all generated from message macros at build
@@ -356,6 +369,19 @@
       const DriverTransport::RawMessage& message,
       const DriverTransport& transport);
 
+  // Attempts to deserialize a message from raw `data`, given a set of already
+  // deserialized DriverObjects in `objects`. The objects and data here have
+  // been extracted from a message relayed opaquely through the broker. While
+  // each DriverObject has already been validated and deserialized, the
+  // message-specific parameter data and object-field assignments must be
+  // validated here.
+  bool DeserializeFromRelay(
+      size_t params_size,
+      uint32_t params_current_version,
+      absl::Span<const internal::ParamMetadata> params_metadata,
+      absl::Span<const uint8_t> data,
+      absl::Span<DriverObject> objects);
+
   // Raw serialized data for this message. This always begins with MessageHeader
   // (or potentially some newer or older version thereof), whose actual size
   // is determined by the header's `size` field. After that many bytes, a
diff --git a/third_party/ipcz/src/ipcz/message_macros/message_declaration_macros.h b/third_party/ipcz/src/ipcz/message_macros/message_declaration_macros.h
index 45949835..ecfc724 100644
--- a/third_party/ipcz/src/ipcz/message_macros/message_declaration_macros.h
+++ b/third_party/ipcz/src/ipcz/message_macros/message_declaration_macros.h
@@ -20,6 +20,8 @@
     ~name();                                                     \
     bool Deserialize(const DriverTransport::RawMessage& message, \
                      const DriverTransport& transport);          \
+    bool DeserializeRelayed(absl::Span<const uint8_t> data,      \
+                            absl::Span<DriverObject> objects);   \
                                                                  \
     static constexpr internal::ParamMetadata kMetadata[] = {
 #define IPCZ_MSG_END() \
diff --git a/third_party/ipcz/src/ipcz/message_macros/message_definition_macros.h b/third_party/ipcz/src/ipcz/message_macros/message_definition_macros.h
index 2ac12326..a373ca6 100644
--- a/third_party/ipcz/src/ipcz/message_macros/message_definition_macros.h
+++ b/third_party/ipcz/src/ipcz/message_macros/message_definition_macros.h
@@ -10,15 +10,20 @@
 #define IPCZ_MSG_ID(x)
 #define IPCZ_MSG_VERSION(x)
 
-#define IPCZ_MSG_BEGIN(name, id_decl, version_decl)                     \
-  name::name() = default;                                               \
-  name::~name() = default;                                              \
-  bool name::Deserialize(const DriverTransport::RawMessage& message,    \
-                         const DriverTransport& transport) {            \
-    return DeserializeFromTransport(sizeof(ParamsType), kVersion,       \
-                                    absl::MakeSpan(kMetadata), message, \
-                                    transport);                         \
-  }                                                                     \
+#define IPCZ_MSG_BEGIN(name, id_decl, version_decl)                        \
+  name::name() = default;                                                  \
+  name::~name() = default;                                                 \
+  bool name::Deserialize(const DriverTransport::RawMessage& message,       \
+                         const DriverTransport& transport) {               \
+    return DeserializeFromTransport(sizeof(ParamsType), kVersion,          \
+                                    absl::MakeSpan(kMetadata), message,    \
+                                    transport);                            \
+  }                                                                        \
+  bool name::DeserializeRelayed(absl::Span<const uint8_t> data,            \
+                                absl::Span<DriverObject> objects) {        \
+    return DeserializeFromRelay(sizeof(ParamsType), kVersion,              \
+                                absl::MakeSpan(kMetadata), data, objects); \
+  }                                                                        \
   constexpr internal::ParamMetadata name::kMetadata[];
 
 #define IPCZ_MSG_END()
diff --git a/third_party/ipcz/src/ipcz/node.cc b/third_party/ipcz/src/ipcz/node.cc
index 5c4cf845..258b5a5 100644
--- a/third_party/ipcz/src/ipcz/node.cc
+++ b/third_party/ipcz/src/ipcz/node.cc
@@ -291,6 +291,31 @@
   return true;
 }
 
+bool Node::RelayMessage(const NodeName& from_node, msg::RelayMessage& relay) {
+  ABSL_ASSERT(type_ == Type::kBroker);
+  auto link = GetLink(relay.params().destination);
+  if (!link) {
+    return true;
+  }
+
+  absl::Span<uint8_t> data = relay.GetArrayView<uint8_t>(relay.params().data);
+  msg::AcceptRelayedMessage accept;
+  accept.params().source = from_node;
+  accept.params().data = accept.AllocateArray<uint8_t>(data.size());
+  memcpy(accept.GetArrayData(accept.params().data), data.data(), data.size());
+  accept.params().driver_objects =
+      accept.AppendDriverObjects(relay.driver_objects());
+  link->Transmit(accept);
+  return true;
+}
+
+bool Node::AcceptRelayedMessage(msg::AcceptRelayedMessage& accept) {
+  if (auto link = GetLink(accept.params().source)) {
+    link->DispatchRelayedMessage(accept);
+  }
+  return true;
+}
+
 void Node::DropLink(const NodeName& name) {
   Ref<NodeLink> link;
   bool lost_broker = false;
diff --git a/third_party/ipcz/src/ipcz/node.h b/third_party/ipcz/src/ipcz/node.h
index ded796d3f..5f36a9b 100644
--- a/third_party/ipcz/src/ipcz/node.h
+++ b/third_party/ipcz/src/ipcz/node.h
@@ -11,6 +11,7 @@
 #include "ipcz/driver_memory.h"
 #include "ipcz/ipcz.h"
 #include "ipcz/link_side.h"
+#include "ipcz/node_messages.h"
 #include "ipcz/node_name.h"
 #include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
 #include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
@@ -146,6 +147,13 @@
   // the broker could not satisfy the request.
   bool CancelIntroduction(const NodeName& name);
 
+  // Relays a message to its destination on behalf of `from_node`.
+  bool RelayMessage(const NodeName& from_node, msg::RelayMessage& relay);
+
+  // Attempts to dispatch a relayed message from the broker as if it came from
+  // the relay source directly.
+  bool AcceptRelayedMessage(msg::AcceptRelayedMessage& accept);
+
   // Drops this node's link to the named node, if one exists.
   void DropLink(const NodeName& name);
 
diff --git a/third_party/ipcz/src/ipcz/node_link.cc b/third_party/ipcz/src/ipcz/node_link.cc
index f84033d..1a09862 100644
--- a/third_party/ipcz/src/ipcz/node_link.cc
+++ b/third_party/ipcz/src/ipcz/node_link.cc
@@ -8,6 +8,7 @@
 #include <atomic>
 #include <cstddef>
 #include <cstdint>
+#include <cstring>
 #include <limits>
 #include <utility>
 
@@ -20,6 +21,7 @@
 #include "ipcz/node.h"
 #include "ipcz/node_link_memory.h"
 #include "ipcz/node_messages.h"
+#include "ipcz/parcel.h"
 #include "ipcz/portal.h"
 #include "ipcz/remote_router_link.h"
 #include "ipcz/router.h"
@@ -239,6 +241,55 @@
   Transmit(request);
 }
 
+void NodeLink::RelayMessage(const NodeName& to_node, Message& message) {
+  ABSL_ASSERT(remote_node_type_ == Node::Type::kBroker);
+
+  msg::RelayMessage relay;
+  relay.params().destination = to_node;
+  relay.params().data =
+      relay.AllocateArray<uint8_t>(message.data_view().size());
+  memcpy(relay.GetArrayData(relay.params().data), message.data_view().data(),
+         message.data_view().size());
+  relay.params().driver_objects =
+      relay.AppendDriverObjects(message.driver_objects());
+  Transmit(relay);
+}
+
+bool NodeLink::DispatchRelayedMessage(msg::AcceptRelayedMessage& accept) {
+  // We only allow a limited subset of messages to be relayed through a broker.
+  // Namely, any message which might carry driver objects between two
+  // non-brokers needs to be relayable.
+  //
+  // If an unknown or unsupported message type is relayed it's silently
+  // discarded, rather than being rejected as a validation failure. This leaves
+  // open the possibility for newer versions of a message to introduce driver
+  // objects and support relaying.
+  absl::Span<uint8_t> data = accept.GetArrayView<uint8_t>(accept.params().data);
+  absl::Span<DriverObject> objects = accept.driver_objects();
+  if (data.size() < sizeof(internal::MessageHeaderV0)) {
+    return false;
+  }
+  const uint8_t message_id =
+      reinterpret_cast<internal::MessageHeaderV0*>(data.data())->message_id;
+  switch (message_id) {
+    case msg::AcceptParcelDriverObjects::kId: {
+      msg::AcceptParcelDriverObjects accept_parcel;
+      return accept_parcel.DeserializeRelayed(data, objects) &&
+             OnAcceptParcelDriverObjects(accept_parcel);
+    }
+
+    case msg::AddBlockBuffer::kId: {
+      msg::AddBlockBuffer add;
+      return add.DeserializeRelayed(data, objects) && OnAddBlockBuffer(add);
+    }
+
+    default:
+      DVLOG(4) << "Ignoring relayed message with ID "
+               << static_cast<int>(message_id);
+      return true;
+  }
+}
+
 void NodeLink::Deactivate() {
   {
     absl::MutexLock lock(&mutex_);
@@ -257,9 +308,13 @@
   if (!message.CanTransmitOn(*transport_)) {
     // The driver has indicated that it can't transmit this message through our
     // transport, so the message must instead be relayed through a broker.
-    //
-    // TODO: Broker relaying not yet implemented.
-    ABSL_ASSERT(false);
+    auto broker = node_->GetBrokerLink();
+    if (!broker) {
+      DLOG(ERROR) << "Cannot relay message without a broker link";
+      return;
+    }
+
+    broker->RelayMessage(remote_node_name_, message);
     return;
   }
 
@@ -347,6 +402,7 @@
   // until any deserialized objects are stored in a new Parcel object. This
   // ensures that they're properly cleaned up before we return.
   bool parcel_valid = true;
+  bool is_split_parcel = false;
   std::vector<Ref<APIObject>> objects(handle_types.size());
   for (size_t i = 0; i < handle_types.size(); ++i) {
     switch (handle_types[i]) {
@@ -377,6 +433,11 @@
         break;
       }
 
+      case HandleType::kRelayedBox: {
+        is_split_parcel = true;
+        break;
+      }
+
       default:
         parcel_valid = false;
         break;
@@ -399,25 +460,22 @@
   parcel.SetInlinedData(
       std::vector<uint8_t>(parcel_data.begin(), parcel_data.end()));
 
-  const absl::optional<Sublink> sublink = GetSublink(for_sublink);
-  if (!sublink) {
-    DVLOG(4) << "Dropping " << parcel.Describe() << " at "
-             << local_node_name_.ToString() << ", arriving from "
-             << remote_node_name_.ToString() << " via unknown sublink "
-             << for_sublink;
-    return true;
+  if (is_split_parcel) {
+    return AcceptParcelWithoutDriverObjects(for_sublink, parcel);
   }
-  const LinkType link_type = sublink->router_link->GetType();
-  if (link_type.is_outward()) {
-    DVLOG(4) << "Accepting inbound " << parcel.Describe() << " at "
-             << sublink->router_link->Describe();
-    return sublink->receiver->AcceptInboundParcel(parcel);
-  }
+  return AcceptCompleteParcel(for_sublink, parcel);
+}
 
-  ABSL_ASSERT(link_type.is_peripheral_inward());
-  DVLOG(4) << "Accepting outbound " << parcel.Describe() << " at "
-           << sublink->router_link->Describe();
-  return sublink->receiver->AcceptOutboundParcel(parcel);
+bool NodeLink::OnAcceptParcelDriverObjects(
+    msg::AcceptParcelDriverObjects& accept) {
+  Parcel parcel(accept.params().sequence_number);
+  std::vector<Ref<APIObject>> objects;
+  objects.reserve(accept.driver_objects().size());
+  for (auto& object : accept.driver_objects()) {
+    objects.push_back(MakeRefCounted<Box>(std::move(object)));
+  }
+  parcel.SetObjects(std::move(objects));
+  return AcceptParcelDriverObjects(accept.params().sublink, parcel);
 }
 
 bool NodeLink::OnRouteClosed(msg::RouteClosed& route_closed) {
@@ -578,6 +636,22 @@
   return true;
 }
 
+bool NodeLink::OnRelayMessage(msg::RelayMessage& relay) {
+  if (node_->type() != Node::Type::kBroker) {
+    return false;
+  }
+
+  return node_->RelayMessage(remote_node_name_, relay);
+}
+
+bool NodeLink::OnAcceptRelayedMessage(msg::AcceptRelayedMessage& accept) {
+  if (remote_node_type_ != Node::Type::kBroker) {
+    return false;
+  }
+
+  return node_->AcceptRelayedMessage(accept);
+}
+
 void NodeLink::OnTransportError() {
   SublinkMap sublinks;
   {
@@ -596,6 +670,100 @@
   node_->DropLink(remote_node_name_);
 }
 
+bool NodeLink::AcceptParcelWithoutDriverObjects(SublinkId for_sublink,
+                                                Parcel& parcel) {
+  const auto key = std::make_tuple(for_sublink, parcel.sequence_number());
+  Parcel parcel_with_driver_objects;
+  {
+    absl::MutexLock lock(&mutex_);
+    auto [it, inserted] = partial_parcels_.try_emplace(key, std::move(parcel));
+    if (inserted) {
+      return true;
+    }
+
+    parcel_with_driver_objects = std::move(it->second);
+    partial_parcels_.erase(it);
+  }
+
+  return AcceptSplitParcel(for_sublink, parcel, parcel_with_driver_objects);
+}
+
+bool NodeLink::AcceptParcelDriverObjects(SublinkId for_sublink,
+                                         Parcel& parcel) {
+  const auto key = std::make_tuple(for_sublink, parcel.sequence_number());
+  Parcel parcel_without_driver_objects;
+  {
+    absl::MutexLock lock(&mutex_);
+    auto [it, inserted] = partial_parcels_.try_emplace(key, std::move(parcel));
+    if (inserted) {
+      return true;
+    }
+
+    parcel_without_driver_objects = std::move(it->second);
+    partial_parcels_.erase(it);
+  }
+
+  return AcceptSplitParcel(for_sublink, parcel_without_driver_objects, parcel);
+}
+
+bool NodeLink::AcceptSplitParcel(SublinkId for_sublink,
+                                 Parcel& parcel_without_driver_objects,
+                                 Parcel& parcel_with_driver_objects) {
+  // The parcel with no driver objects should still have an object attachemnt
+  // slot reserved for every relayed driver object.
+  if (parcel_without_driver_objects.num_objects() <
+      parcel_with_driver_objects.num_objects()) {
+    return false;
+  }
+
+  // Fill in all the object gaps in the data-only parcel with the boxed objects
+  // from the driver objects parcel.
+  Parcel& complete_parcel = parcel_without_driver_objects;
+  auto remaining_driver_objects = parcel_with_driver_objects.objects_view();
+  for (auto& object : complete_parcel.objects_view()) {
+    if (object) {
+      continue;
+    }
+
+    if (remaining_driver_objects.empty()) {
+      return false;
+    }
+
+    object = std::move(remaining_driver_objects[0]);
+    remaining_driver_objects.remove_prefix(1);
+  }
+
+  // At least one driver object was unclaimed by the data half of the parcel.
+  // That's not right.
+  if (!remaining_driver_objects.empty()) {
+    return false;
+  }
+
+  return AcceptCompleteParcel(for_sublink, complete_parcel);
+}
+
+bool NodeLink::AcceptCompleteParcel(SublinkId for_sublink, Parcel& parcel) {
+  const absl::optional<Sublink> sublink = GetSublink(for_sublink);
+  if (!sublink) {
+    DVLOG(4) << "Dropping " << parcel.Describe() << " at "
+             << local_node_name_.ToString() << ", arriving from "
+             << remote_node_name_.ToString() << " via unknown sublink "
+             << for_sublink;
+    return true;
+  }
+  const LinkType link_type = sublink->router_link->GetType();
+  if (link_type.is_outward()) {
+    DVLOG(4) << "Accepting inbound " << parcel.Describe() << " at "
+             << sublink->router_link->Describe();
+    return sublink->receiver->AcceptInboundParcel(parcel);
+  }
+
+  ABSL_ASSERT(link_type.is_peripheral_inward());
+  DVLOG(4) << "Accepting outbound " << parcel.Describe() << " at "
+           << sublink->router_link->Describe();
+  return sublink->receiver->AcceptOutboundParcel(parcel);
+}
+
 NodeLink::Sublink::Sublink(Ref<RemoteRouterLink> router_link,
                            Ref<Router> receiver)
     : router_link(std::move(router_link)), receiver(std::move(receiver)) {}
diff --git a/third_party/ipcz/src/ipcz/node_link.h b/third_party/ipcz/src/ipcz/node_link.h
index 76003be..0ba40fa 100644
--- a/third_party/ipcz/src/ipcz/node_link.h
+++ b/third_party/ipcz/src/ipcz/node_link.h
@@ -30,6 +30,7 @@
 namespace ipcz {
 
 class Message;
+class Parcel;
 class RemoteRouterLink;
 class Router;
 
@@ -166,6 +167,17 @@
   using RequestMemoryCallback = std::function<void(DriverMemory)>;
   void RequestMemory(size_t size, RequestMemoryCallback callback);
 
+  // Asks the remote node (which must be a broker) to relay `message` over to
+  // `to_node`. This is used to transmit driver objects between non-broker nodes
+  // whenever direct transmission is unsupported by the driver.
+  void RelayMessage(const NodeName& to_node, Message& message);
+
+  // Simulates receipt of a new message from the remote node on this link. This
+  // is called by the local Node with a message that was relayed to it by its
+  // broker. All relayed messages land on their destination node through this
+  // method.
+  bool DispatchRelayedMessage(msg::AcceptRelayedMessage& relay);
+
   // Permanently deactivates this NodeLink. Once this call returns the NodeLink
   // will no longer receive transport messages. It may still be used to transmit
   // outgoing messages, but it cannot be reactivated. Transmissions over a
@@ -208,6 +220,8 @@
   bool OnRejectIntroduction(msg::RejectIntroduction& reject) override;
   bool OnAddBlockBuffer(msg::AddBlockBuffer& add) override;
   bool OnAcceptParcel(msg::AcceptParcel& accept) override;
+  bool OnAcceptParcelDriverObjects(
+      msg::AcceptParcelDriverObjects& accept) override;
   bool OnRouteClosed(msg::RouteClosed& route_closed) override;
   bool OnRouteDisconnected(msg::RouteDisconnected& route_disconnected) override;
   bool OnBypassPeer(msg::BypassPeer& bypass) override;
@@ -219,8 +233,17 @@
   bool OnFlushRouter(msg::FlushRouter& flush) override;
   bool OnRequestMemory(msg::RequestMemory& request) override;
   bool OnProvideMemory(msg::ProvideMemory& provide) override;
+  bool OnRelayMessage(msg::RelayMessage& relay) override;
+  bool OnAcceptRelayedMessage(msg::AcceptRelayedMessage& accept) override;
   void OnTransportError() override;
 
+  bool AcceptParcelWithoutDriverObjects(SublinkId for_sublink, Parcel& parcel);
+  bool AcceptParcelDriverObjects(SublinkId for_sublink, Parcel& parcel);
+  bool AcceptSplitParcel(SublinkId for_sublink,
+                         Parcel& parcel_without_driver_objects,
+                         Parcel& parcel_with_driver_objects);
+  bool AcceptCompleteParcel(SublinkId for_sublink, Parcel& parcel);
+
   const Ref<Node> node_;
   const LinkSide link_side_;
   const NodeName local_node_name_;
@@ -249,6 +272,12 @@
   using MemoryRequestMap =
       absl::flat_hash_map<uint32_t, std::list<RequestMemoryCallback>>;
   MemoryRequestMap pending_memory_requests_ ABSL_GUARDED_BY(mutex_);
+
+  // Tracks partially received contents of split parcels so they can be
+  // reconstructed for dispatch.
+  using PartialParcelKey = std::tuple<SublinkId, SequenceNumber>;
+  using PartialParcelMap = absl::flat_hash_map<PartialParcelKey, Parcel>;
+  PartialParcelMap partial_parcels_ ABSL_GUARDED_BY(mutex_);
 };
 
 }  // namespace ipcz
diff --git a/third_party/ipcz/src/ipcz/node_messages_generator.h b/third_party/ipcz/src/ipcz/node_messages_generator.h
index afdaa77..36f6d6f 100644
--- a/third_party/ipcz/src/ipcz/node_messages_generator.h
+++ b/third_party/ipcz/src/ipcz/node_messages_generator.h
@@ -140,6 +140,25 @@
   IPCZ_MSG_PARAM_DRIVER_OBJECT_ARRAY(driver_objects)
 IPCZ_MSG_END()
 
+// Conveys partial parcel contents, namely just its attached driver objects.
+// When a parcel with driver objects cannot be transmitted directly to its
+// destination, this message is split off and relayed through the broker while
+// the rest of the parcel contents are sent directly, without the objects
+// attached. The receiving node can reconstitute the full parcel once both
+// messages are received.
+IPCZ_MSG_BEGIN(AcceptParcelDriverObjects, IPCZ_MSG_ID(21), IPCZ_MSG_VERSION(0))
+  // The SublinkId linking the source and destination Routers along the
+  // transmitting NodeLink.
+  IPCZ_MSG_PARAM(SublinkId, sublink)
+
+  // The SequenceNumber of this parcel within the transmitting portal's outbound
+  // parcel sequence (and the receiving portal's inbound parcel sequence.)
+  IPCZ_MSG_PARAM(SequenceNumber, sequence_number)
+
+  // The driver objects to be accepted.
+  IPCZ_MSG_PARAM_DRIVER_OBJECT_ARRAY(driver_objects)
+IPCZ_MSG_END()
+
 // Notifies a node that the route has been closed on one side. This message
 // always pertains to the side of the route opposite of the router receiving it,
 // guaranteed by the fact that the closed side of the route only transmits this
@@ -368,4 +387,31 @@
   IPCZ_MSG_PARAM_DRIVER_OBJECT(buffer)
 IPCZ_MSG_END()
 
+// Sends a message payload to the broker to be relayed to another node. Used to
+// relay messages which carry driver objects through the broker when they cannot
+// be transmitted directly between their source and destination nodes.
+IPCZ_MSG_BEGIN(RelayMessage, IPCZ_MSG_ID(66), IPCZ_MSG_VERSION(0))
+  // The node to which this message's contents should ultimately be relayed.
+  IPCZ_MSG_PARAM(NodeName, destination)
+
+  // The actual serialized message to be relayed, including its own header.
+  IPCZ_MSG_PARAM_ARRAY(uint8_t, data)
+
+  // The set of driver objects to be relayed along with `data`.
+  IPCZ_MSG_PARAM_DRIVER_OBJECT_ARRAY(driver_objects)
+IPCZ_MSG_END()
+
+// Relays a message payload from an intermediate broker to its destination. This
+// is the continuation of RelayMessage above. Must only be accepted on a broker.
+IPCZ_MSG_BEGIN(AcceptRelayedMessage, IPCZ_MSG_ID(67), IPCZ_MSG_VERSION(0))
+  // The node which originally requested that the broker relay this message.
+  IPCZ_MSG_PARAM(NodeName, source)
+
+  // The full serialized data of the relayed message.
+  IPCZ_MSG_PARAM_ARRAY(uint8_t, data)
+
+  // The set of driver objects relayed along with `data`.
+  IPCZ_MSG_PARAM_DRIVER_OBJECT_ARRAY(driver_objects)
+IPCZ_MSG_END()
+
 IPCZ_MSG_END_INTERFACE()
diff --git a/third_party/ipcz/src/ipcz/remote_router_link.cc b/third_party/ipcz/src/ipcz/remote_router_link.cc
index 4602db6..dd1ba21 100644
--- a/third_party/ipcz/src/ipcz/remote_router_link.cc
+++ b/third_party/ipcz/src/ipcz/remote_router_link.cc
@@ -113,6 +113,7 @@
 
   size_t num_portals = 0;
   absl::InlinedVector<DriverObject, 2> driver_objects;
+  bool must_relay_driver_objects = false;
   for (Ref<APIObject>& object : objects) {
     switch (object->object_type()) {
       case APIObject::kPortal:
@@ -122,10 +123,9 @@
       case APIObject::kBox: {
         Box* box = Box::FromObject(object.get());
         ABSL_ASSERT(box);
-
-        // TODO: Support object relay when direct transmission is impossible.
-        ABSL_ASSERT(box->object().CanTransmitOn(*node_link()->transport()));
-
+        if (!box->object().CanTransmitOn(*node_link()->transport())) {
+          must_relay_driver_objects = true;
+        }
         driver_objects.push_back(std::move(box->object()));
         break;
       }
@@ -135,6 +135,20 @@
     }
   }
 
+  // If driver objects will require relaying through the broker, then the parcel
+  // must be split into two separate messages: one for the driver objects (which
+  // will be relayed), and one for the rest of the message (which will transmit
+  // directly).
+  //
+  // This ensures that many side effects of message receipt are well-ordered
+  // with other transmissions on the same link from the same thread. Namely,
+  // since a thread may send a message which introduces a new remote Router on a
+  // new sublink, followed immediately by a message which targets that Router,
+  // it is critical that both messages arrive in the order they were sent. If
+  // one of the messages is relayed while the other is not, ordering could not
+  // be guaranteed.
+  const bool must_split_parcel = must_relay_driver_objects;
+
   // Allocate all the arrays in the message. Note that each allocation may
   // relocate the parcel data in memory, so views into these arrays should not
   // be acquired until all allocations are complete.
@@ -174,7 +188,8 @@
       }
 
       case APIObject::kBox:
-        handle_types[i] = HandleType::kBox;
+        handle_types[i] =
+            must_split_parcel ? HandleType::kRelayedBox : HandleType::kBox;
         break;
 
       default:
@@ -183,8 +198,20 @@
     }
   }
 
-  accept.params().driver_objects =
-      accept.AppendDriverObjects(absl::MakeSpan(driver_objects));
+  if (must_split_parcel) {
+    msg::AcceptParcelDriverObjects accept_objects;
+    accept_objects.params().sublink = sublink_;
+    accept_objects.params().sequence_number = parcel.sequence_number();
+    accept_objects.params().driver_objects =
+        accept_objects.AppendDriverObjects(absl::MakeSpan(driver_objects));
+
+    DVLOG(4) << "Transmitting objects for " << parcel.Describe() << " over "
+             << Describe();
+    node_link()->Transmit(accept_objects);
+  } else {
+    accept.params().driver_objects =
+        accept.AppendDriverObjects(absl::MakeSpan(driver_objects));
+  }
 
   DVLOG(4) << "Transmitting " << parcel.Describe() << " over " << Describe();
 
diff --git a/third_party/ipcz/src/reference_drivers/async_reference_driver.cc b/third_party/ipcz/src/reference_drivers/async_reference_driver.cc
index 647e423..3ebbe8e6 100644
--- a/third_party/ipcz/src/reference_drivers/async_reference_driver.cc
+++ b/third_party/ipcz/src/reference_drivers/async_reference_driver.cc
@@ -30,10 +30,27 @@
 // thread for each transport.
 class AsyncTransport : public ObjectImpl<AsyncTransport, Object::kTransport> {
  public:
+  enum class NodeType {
+    kBroker,
+    kNonBroker,
+  };
+
+  struct TransportType {
+    NodeType local;
+    NodeType remote;
+  };
+
+  explicit AsyncTransport(const TransportType& type) : type_(type) {}
+
+  NodeType local_type() const { return type_.local; }
+  NodeType remote_type() const { return type_.remote; }
+
   using Pair = std::pair<Ref<AsyncTransport>, Ref<AsyncTransport>>;
-  static Pair CreatePair() {
-    Pair pair{MakeRefCounted<AsyncTransport>(),
-              MakeRefCounted<AsyncTransport>()};
+  static Pair CreatePair(NodeType node0_type, NodeType node1_type) {
+    Pair pair{MakeRefCounted<AsyncTransport>(
+                  TransportType{.local = node0_type, .remote = node1_type}),
+              MakeRefCounted<AsyncTransport>(
+                  TransportType{.local = node1_type, .remote = node0_type})};
     std::tie(pair.second->peer_, pair.first->peer_) = pair;
     return pair;
   }
@@ -164,6 +181,8 @@
     }
   }
 
+  const TransportType type_;
+
   Ref<AsyncTransport> peer_;
   IpczHandle transport_ = IPCZ_INVALID_HANDLE;
   IpczTransportActivityHandler handler_;
@@ -176,15 +195,18 @@
       std::make_unique<absl::Notification>();
 };
 
-IpczResult IPCZ_API CreateTransports(IpczDriverHandle,
-                                     IpczDriverHandle,
+IpczResult IPCZ_API CreateTransports(IpczDriverHandle transport0,
+                                     IpczDriverHandle transport1,
                                      uint32_t,
                                      const void*,
-                                     IpczDriverHandle* transport0,
-                                     IpczDriverHandle* transport1) {
-  auto [first, second] = AsyncTransport::CreatePair();
-  *transport0 = Object::ReleaseAsHandle(std::move(first));
-  *transport1 = Object::ReleaseAsHandle(std::move(second));
+                                     IpczDriverHandle* new_transport0,
+                                     IpczDriverHandle* new_transport1) {
+  auto* target0 = AsyncTransport::FromHandle(transport0);
+  auto* target1 = AsyncTransport::FromHandle(transport1);
+  auto [first, second] = AsyncTransport::CreatePair(target0->remote_type(),
+                                                    target1->remote_type());
+  *new_transport0 = Object::ReleaseAsHandle(std::move(first));
+  *new_transport1 = Object::ReleaseAsHandle(std::move(second));
   return IPCZ_RESULT_OK;
 }
 
@@ -216,6 +238,29 @@
   return IPCZ_RESULT_OK;
 }
 
+IpczResult IPCZ_API SerializeWithForcedBrokering(IpczDriverHandle handle,
+                                                 IpczDriverHandle transport,
+                                                 uint32_t flags,
+                                                 const void* options,
+                                                 void* data,
+                                                 size_t* num_bytes,
+                                                 IpczDriverHandle* handles,
+                                                 size_t* num_handles) {
+  auto* target = AsyncTransport::FromHandle(transport);
+  if (!target) {
+    return IPCZ_RESULT_ABORTED;
+  }
+
+  if (target->local_type() == AsyncTransport::NodeType::kNonBroker &&
+      target->remote_type() == AsyncTransport::NodeType::kNonBroker) {
+    // Force ipcz to relay driver objects through a broker.
+    return IPCZ_RESULT_PERMISSION_DENIED;
+  }
+
+  return kSingleProcessReferenceDriverBase.Serialize(
+      handle, transport, flags, options, data, num_bytes, handles, num_handles);
+}
+
 }  // namespace
 
 // Note that this driver inherits most of its implementation from the baseline
@@ -236,4 +281,29 @@
     kSingleProcessReferenceDriverBase.GenerateRandomBytes,
 };
 
+const IpczDriver kAsyncReferenceDriverWithForcedBrokering = {
+    sizeof(kAsyncReferenceDriverWithForcedBrokering),
+    kSingleProcessReferenceDriverBase.Close,
+    SerializeWithForcedBrokering,
+    kSingleProcessReferenceDriverBase.Deserialize,
+    CreateTransports,
+    ActivateTransport,
+    DeactivateTransport,
+    Transmit,
+    kSingleProcessReferenceDriverBase.AllocateSharedMemory,
+    kSingleProcessReferenceDriverBase.GetSharedMemoryInfo,
+    kSingleProcessReferenceDriverBase.DuplicateSharedMemory,
+    kSingleProcessReferenceDriverBase.MapSharedMemory,
+    kSingleProcessReferenceDriverBase.GenerateRandomBytes,
+};
+
+AsyncTransportPair CreateAsyncTransportPair() {
+  AsyncTransport::Pair transports = AsyncTransport::CreatePair(
+      AsyncTransport::NodeType::kBroker, AsyncTransport::NodeType::kNonBroker);
+  return {
+      .broker = Object::ReleaseAsHandle(std::move(transports.first)),
+      .non_broker = Object::ReleaseAsHandle(std::move(transports.second)),
+  };
+}
+
 }  // namespace ipcz::reference_drivers
diff --git a/third_party/ipcz/src/reference_drivers/async_reference_driver.h b/third_party/ipcz/src/reference_drivers/async_reference_driver.h
index e596e60..2371be1 100644
--- a/third_party/ipcz/src/reference_drivers/async_reference_driver.h
+++ b/third_party/ipcz/src/reference_drivers/async_reference_driver.h
@@ -15,6 +15,19 @@
 // production driver, without the complexity of a multiprocess environment.
 extern const IpczDriver kAsyncReferenceDriver;
 
+// Mostly the same as kAsyncReferenceDriver, but rejects direct transmission of
+// driver handles between non-broker nodes. This forces ipcz to relay such
+// messages through the broker.
+extern const IpczDriver kAsyncReferenceDriverWithForcedBrokering;
+
+// Creates a new pair of async transport endpoints, one for a broker and one
+// for a non-broker.
+struct AsyncTransportPair {
+  IpczDriverHandle broker;
+  IpczDriverHandle non_broker;
+};
+AsyncTransportPair CreateAsyncTransportPair();
+
 }  // namespace ipcz::reference_drivers
 
 #endif  // IPCZ_SRC_DRIVERS_ASYNC_REFERENCE_DRIVER_H_
diff --git a/third_party/ipcz/src/test/multinode_test.cc b/third_party/ipcz/src/test/multinode_test.cc
index 9455476e..dd9345c 100644
--- a/third_party/ipcz/src/test/multinode_test.cc
+++ b/third_party/ipcz/src/test/multinode_test.cc
@@ -121,6 +121,12 @@
     case DriverMode::kAsyncDelegatedAlloc:
       return reference_drivers::kAsyncReferenceDriver;
 
+    case DriverMode::kAsyncObjectBrokering:
+      return reference_drivers::kAsyncReferenceDriverWithForcedBrokering;
+
+    case DriverMode::kAsyncObjectBrokeringAndDelegatedAlloc:
+      return reference_drivers::kAsyncReferenceDriverWithForcedBrokering;
+
 #if BUILDFLAG(ENABLE_IPCZ_MULTIPROCESS_TESTS)
     case DriverMode::kMultiprocess:
       return reference_drivers::kMultiprocessReferenceDriver;
@@ -146,7 +152,8 @@
 
 void TestNode::ConnectToBroker(absl::Span<IpczHandle> portals) {
   uint32_t flags = IPCZ_CONNECT_NODE_TO_BROKER;
-  if (driver_mode_ == DriverMode::kAsyncDelegatedAlloc) {
+  if (driver_mode_ == DriverMode::kAsyncDelegatedAlloc ||
+      driver_mode_ == DriverMode::kAsyncObjectBrokeringAndDelegatedAlloc) {
     flags |= IPCZ_CONNECT_NODE_TO_ALLOCATION_DELEGATE;
   }
   IpczDriverHandle transport =
@@ -222,6 +229,18 @@
 }
 
 TestNode::TransportPair TestNode::CreateTransports() {
+  if (driver_mode_ == DriverMode::kAsync ||
+      driver_mode_ == DriverMode::kAsyncDelegatedAlloc ||
+      driver_mode_ == DriverMode::kAsyncObjectBrokering ||
+      driver_mode_ == DriverMode::kAsyncObjectBrokeringAndDelegatedAlloc) {
+    reference_drivers::AsyncTransportPair transports =
+        reference_drivers::CreateAsyncTransportPair();
+    return {
+        .ours = transports.broker,
+        .theirs = transports.non_broker,
+    };
+  }
+
   TransportPair transports;
   const IpczResult result = GetDriver().CreateTransports(
       IPCZ_INVALID_DRIVER_HANDLE, IPCZ_INVALID_DRIVER_HANDLE, IPCZ_NO_FLAGS,
diff --git a/third_party/ipcz/src/test/multinode_test.h b/third_party/ipcz/src/test/multinode_test.h
index 6f08423..75e3f4ef 100644
--- a/third_party/ipcz/src/test/multinode_test.h
+++ b/third_party/ipcz/src/test/multinode_test.h
@@ -303,12 +303,14 @@
 #endif
 
 // TODO: Add other DriverMode enumerators here as support is landed.
-#define INSTANTIATE_MULTINODE_TEST_SUITE_P(suite)                    \
-  INSTANTIATE_TEST_SUITE_P(                                          \
-      , suite,                                                       \
-      ::testing::Values(ipcz::test::DriverMode::kSync,               \
-                        ipcz::test::DriverMode::kAsync,              \
-                        ipcz::test::DriverMode::kAsyncDelegatedAlloc \
-                            IPCZ_EXTRA_DRIVER_MODES))
+#define INSTANTIATE_MULTINODE_TEST_SUITE_P(suite)                        \
+  INSTANTIATE_TEST_SUITE_P(                                              \
+      , suite,                                                           \
+      ::testing::Values(                                                 \
+          ipcz::test::DriverMode::kSync, ipcz::test::DriverMode::kAsync, \
+          ipcz::test::DriverMode::kAsyncDelegatedAlloc,                  \
+          ipcz::test::DriverMode::kAsyncObjectBrokering,                 \
+          ipcz::test::DriverMode::kAsyncObjectBrokeringAndDelegatedAlloc \
+              IPCZ_EXTRA_DRIVER_MODES))
 
 #endif  // IPCZ_SRC_TEST_MULTINODE_TEST_H_
diff --git a/third_party/tflite/README.chromium b/third_party/tflite/README.chromium
index 7c9e3646..ae515c1 100644
--- a/third_party/tflite/README.chromium
+++ b/third_party/tflite/README.chromium
@@ -1,8 +1,8 @@
 Name: TensorFlow Lite
 Short Name: tflite
 URL: https://github.com/tensorflow/tensorflow
-Version: 179fbbab3fc38152be53b519376f0067736fd934
-Date: 2022/08/02
+Version: 20bdb50879599c0e7a62036ee3fd8a644ced97f1
+Date: 2022/08/08
 License: Apache 2.0
 License File: LICENSE
 Security Critical: Yes
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index 6617d636..6c42221 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -105,7 +105,8 @@
     ])
     append_to_env('CXXFLAGS', [
         '-nostdinc++',
-        ' -isystem../../../buildtools/third_party/libc++/trunk/include',
+        '-isystem../../../buildtools/third_party/libc++',
+        '-isystem../../../buildtools/third_party/libc++/trunk/include',
         '-isystem../../../buildtools/third_party/libc++abi/trunk/include'
     ])
 
diff --git a/tools/gn/bootstrap/libc++.ninja b/tools/gn/bootstrap/libc++.ninja
index 72bb082..5760fc0 100644
--- a/tools/gn/bootstrap/libc++.ninja
+++ b/tools/gn/bootstrap/libc++.ninja
@@ -5,15 +5,15 @@
 libcxxabi = third_party/libc++abi/trunk/src
 
 defines = -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D_FILE_OFFSET_BITS=64
-includes = -isystem$buildtools/$libcxx/../include -isystem$buildtools/$libcxx/.. -isystem$buildtools/$libcxxabi/../include
-cflags = $cxxflags $defines $includes -O2 -g0 -pthread -pipe -fno-exceptions -std=c++14 -Wno-c++11-narrowing -nostdinc++ -fPIC
+includes = -isystem$buildtools/$libcxx/../include -isystem$buildtools/$libcxx -isystem$buildtools/$libcxx/.. -isystem$buildtools/$libcxx/../.. -isystem$buildtools/$libcxxabi/../include
+cflags = $cxxflags $defines $includes -O2 -g0 -pthread -pipe -fno-exceptions -std=c++20 -Wno-c++11-narrowing -nostdinc++ -fPIC
 
 rule cxx_libcxx
   command = $cxx $cflags -D_LIBCPP_NO_EXCEPTIONS -D_LIBCPP_BUILDING_LIBRARY -DLIBCXX_BUILDING_LIBCXXABI -c $in -o $out
   description = CXX $out
 
 rule cxx_libcxxabi
-  command = $cxx $cflags -D_LIBCXXABI_NO_EXCEPTIONS -DLIBCXXABI_SILENT_TERMINATE -c $in -o $out
+  command = $cxx $cflags -D_LIBCXXABI_NO_EXCEPTIONS -D_LIBCPP_BUILDING_LIBRARY -DLIBCXXABI_SILENT_TERMINATE -c $in -o $out
   description = CXX $out
 
 rule link
@@ -46,6 +46,9 @@
 build $libcxx/random.o: cxx_libcxx $buildtools/$libcxx/random.cpp
 build $libcxx/random_shuffle.o: cxx_libcxx $buildtools/$libcxx/random_shuffle.cpp
 build $libcxx/regex.o: cxx_libcxx $buildtools/$libcxx/regex.cpp
+build $libcxx/ryu/d2fixed.o: cxx_libcxx $buildtools/$libcxx/ryu/d2fixed.cpp
+build $libcxx/ryu/d2s.o: cxx_libcxx $buildtools/$libcxx/ryu/d2s.cpp
+build $libcxx/ryu/f2s.o: cxx_libcxx $buildtools/$libcxx/ryu/f2s.cpp
 build $libcxx/shared_mutex.o: cxx_libcxx $buildtools/$libcxx/shared_mutex.cpp
 build $libcxx/stdexcept.o: cxx_libcxx $buildtools/$libcxx/stdexcept.cpp
 build $libcxx/string.o: cxx_libcxx $buildtools/$libcxx/string.cpp
@@ -75,4 +78,4 @@
 build $libcxxabi/stdlib_stdexcept.o: cxx_libcxxabi $buildtools/$libcxxabi/stdlib_stdexcept.cpp
 build $libcxxabi/stdlib_typeinfo.o: cxx_libcxxabi $buildtools/$libcxxabi/stdlib_typeinfo.cpp
 
-build ../libc++.gn.so: link $libcxx/algorithm.o $libcxx/any.o $libcxx/atomic.o $libcxx/barrier.o $libcxx/bind.o $libcxx/charconv.o $libcxx/chrono.o $libcxx/condition_variable.o $libcxx/condition_variable_destructor.o $libcxx/debug.o $libcxx/exception.o $libcxx/functional.o $libcxx/future.o $libcxx/hash.o $libcxx/ios.o $libcxx/ios.instantiations.o $libcxx/iostream.o $libcxx/locale.o $libcxx/memory.o $libcxx/mutex.o $libcxx/mutex_destructor.o $libcxx/new.o $libcxx/optional.o $libcxx/random.o $libcxx/random_shuffle.o $libcxx/regex.o $libcxx/shared_mutex.o $libcxx/stdexcept.o $libcxx/string.o $libcxx/strstream.o $libcxx/system_error.o $libcxx/thread.o $libcxx/typeinfo.o $libcxx/utility.o $libcxx/valarray.o $libcxx/variant.o $libcxx/vector.o $libcxxabi/abort_message.o $libcxxabi/cxa_aux_runtime.o $libcxxabi/cxa_default_handlers.o $libcxxabi/cxa_demangle.o $libcxxabi/cxa_exception_storage.o $libcxxabi/cxa_guard.o $libcxxabi/cxa_handlers.o $libcxxabi/cxa_noexception.o $libcxxabi/cxa_thread_atexit.o $libcxxabi/cxa_vector.o $libcxxabi/cxa_virtual.o $libcxxabi/fallback_malloc.o $libcxxabi/private_typeinfo.o $libcxxabi/stdlib_exception.o $libcxxabi/stdlib_stdexcept.o $libcxxabi/stdlib_typeinfo.o
+build ../libc++.gn.so: link $libcxx/algorithm.o $libcxx/any.o $libcxx/atomic.o $libcxx/barrier.o $libcxx/bind.o $libcxx/charconv.o $libcxx/chrono.o $libcxx/condition_variable.o $libcxx/condition_variable_destructor.o $libcxx/debug.o $libcxx/exception.o $libcxx/functional.o $libcxx/future.o $libcxx/hash.o $libcxx/ios.o $libcxx/ios.instantiations.o $libcxx/iostream.o $libcxx/locale.o $libcxx/memory.o $libcxx/mutex.o $libcxx/mutex_destructor.o $libcxx/new.o $libcxx/optional.o $libcxx/random.o $libcxx/random_shuffle.o $libcxx/regex.o $libcxx/ryu/d2fixed.o $libcxx/ryu/d2s.o $libcxx/ryu/f2s.o $libcxx/shared_mutex.o $libcxx/stdexcept.o $libcxx/string.o $libcxx/strstream.o $libcxx/system_error.o $libcxx/thread.o $libcxx/typeinfo.o $libcxx/utility.o $libcxx/valarray.o $libcxx/variant.o $libcxx/vector.o $libcxxabi/abort_message.o $libcxxabi/cxa_aux_runtime.o $libcxxabi/cxa_default_handlers.o $libcxxabi/cxa_demangle.o $libcxxabi/cxa_exception_storage.o $libcxxabi/cxa_guard.o $libcxxabi/cxa_handlers.o $libcxxabi/cxa_noexception.o $libcxxabi/cxa_thread_atexit.o $libcxxabi/cxa_vector.o $libcxxabi/cxa_virtual.o $libcxxabi/fallback_malloc.o $libcxxabi/private_typeinfo.o $libcxxabi/stdlib_exception.o $libcxxabi/stdlib_stdexcept.o $libcxxabi/stdlib_typeinfo.o
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 70a50b6b..b41f748a 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -5823,6 +5823,7 @@
   <int value="29" label="TILE_NAVSUGGEST"/>
   <int value="30" label="OPEN_TAB"/>
   <int value="31" label="HISTORY_CLUSTER"/>
+  <int value="32" label="NULL_RESULT_MESSAGE"/>
 </enum>
 
 <enum name="AutoDSEPermissionRevertTransition">
@@ -55733,6 +55734,7 @@
       label="AutofillEnableFixedPaymentsBubbleLogging:disabled"/>
   <int value="-2026156288"
       label="LookalikeUrlNavigationSuggestionsUI:disabled"/>
+  <int value="-2025971178" label="QsRevamp:disabled"/>
   <int value="-2025367104" label="enable-material-design-ntp"/>
   <int value="-2025360412" label="SyncAndroidPromosWithSingleButton:disabled"/>
   <int value="-2025330968" label="Journeys:disabled"/>
@@ -57825,6 +57827,7 @@
   <int value="-752321357" label="AutofillEnableGoogleIssuedCard:enabled"/>
   <int value="-750175757" label="ClientLoFi:enabled"/>
   <int value="-749550261" label="SeamlessRefreshRateSwitching:enabled"/>
+  <int value="-749306189" label="QsRevamp:enabled"/>
   <int value="-749048160" label="enable-panels"/>
   <int value="-748571227"
       label="AssistantEnableMediaSessionIntegration:enabled"/>
@@ -74132,6 +74135,8 @@
   <int value="22"
       label="Longest input timestamp earlier than first input timestamp"/>
   <int value="23" label="Longest input delay less than first input delay"/>
+  <int value="24" label="Invalid order - parse start / activation start"/>
+  <int value="25" label="Invalid order - activation start / first paint"/>
 </enum>
 
 <enum name="PageLoadTimingUnderStat">
@@ -86859,6 +86864,11 @@
   <int value="3" label="Timeout"/>
 </enum>
 
+<enum name="ServiceWorkerFetchEventResult">
+  <int value="0" label="Should Fallback"/>
+  <int value="1" label="Got Response"/>
+</enum>
+
 <enum name="ServiceWorkerInstalledScriptsManager.FinishedReason">
   <int value="0" label="NOT_FINISHED"/>
   <int value="1" label="SUCCESS"/>
diff --git a/tools/metrics/histograms/metadata/input/histograms.xml b/tools/metrics/histograms/metadata/input/histograms.xml
index 7a3ffe23c..ab7c8067 100644
--- a/tools/metrics/histograms/metadata/input/histograms.xml
+++ b/tools/metrics/histograms/metadata/input/histograms.xml
@@ -371,6 +371,18 @@
   </summary>
 </histogram>
 
+<histogram
+    name="InputMethod.Assistive.UserPref.PhysicalKeyboardDiacriticsOnLongpress"
+    enum="BooleanEnabled" expires_after="2023-08-07">
+  <owner>jhtin@google.com</owner>
+  <owner>essential-inputs-team@google.com</owner>
+  <summary>
+    The user's preference for diacritics. Recorded when the user is logged in
+    and the AssistiveSuggester is initialised. &quot;Enabled&quot; is logged as
+    the default value if the user didn't explicitly set it.
+  </summary>
+</histogram>
+
 <histogram name="InputMethod.AutoCorrectLevel" enum="IMECorrectionLevel"
     expires_after="2022-10-03">
   <owner>shend@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 07e1978..737ee75c 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -3587,16 +3587,6 @@
   <token key="CustomPassphraseStatus" variants="CustomPassphraseStatus"/>
 </histogram>
 
-<histogram name="PasswordProtection.DomFeatureExtractionDuration" units="ms"
-    expires_after="2022-09-11">
-  <owner>drubery@chromium.org</owner>
-  <owner>chrome-counter-abuse-alerts@google.com</owner>
-  <summary>
-    The time it takes to extract the DOM features of a login page before sending
-    a PasswordProtectionRequest. Logged on every password reuse PhishGuard ping.
-  </summary>
-</histogram>
-
 <histogram name="PasswordProtection.InterstitialAction"
     enum="PasswordProtectionWarningAction" expires_after="2022-12-25">
   <owner>xinghuilu@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/security/histograms.xml b/tools/metrics/histograms/metadata/security/histograms.xml
index 961da8ad..bc13c16f 100644
--- a/tools/metrics/histograms/metadata/security/histograms.xml
+++ b/tools/metrics/histograms/metadata/security/histograms.xml
@@ -559,9 +559,9 @@
 </histogram>
 
 <histogram name="Security.SecurityLevel.InsecureMainFrameFormSubmission"
-    enum="SecurityLevel" expires_after="2022-08-14">
+    enum="SecurityLevel" expires_after="2023-08-14">
   <owner>estark@chromium.org</owner>
-  <owner>trusty-transport@chromium.org</owner>
+  <owner>carlosil@chromium.org</owner>
   <summary>
     Records the security level of a page when submitting a form on a top-frame
     navigation with a non-cryptographic scheme. This histogram is recorded
diff --git a/tools/metrics/histograms/metadata/service/histograms.xml b/tools/metrics/histograms/metadata/service/histograms.xml
index c7b1befb..761185f 100644
--- a/tools/metrics/histograms/metadata/service/histograms.xml
+++ b/tools/metrics/histograms/metadata/service/histograms.xml
@@ -45,6 +45,11 @@
   <variant name="UNKNOWN"/>
 </variants>
 
+<variants name="ServiceWorkerFetchEventResult">
+  <variant name="GOT_RESPONSE"/>
+  <variant name="SHOULD_FALLBACK"/>
+</variants>
+
 <histogram name="ServiceWorker.AbortPaymentEvent.Time" units="ms"
     expires_after="2022-11-22">
   <owner>rouslan@chromium.org</owner>
@@ -475,6 +480,24 @@
 </histogram>
 
 <histogram
+    name="ServiceWorker.LoadTiming.MainFrame.MainResource.FetchHandlerStartToFetchHandlerEndByFetchResult_{ServiceWorkerFetchEventResult}"
+    units="ms" expires_after="2023-06-30">
+  <owner>yyanagisawa@chromium.org</owner>
+  <owner>chrome-worker@google.com</owner>
+  <summary>
+    The time taken from (a) a fetch event is dispatched, to (b) respondWith() is
+    settled for the fetch event, or fetch event dispatch is finished without
+    respondWith() being called.
+
+    Recorded for each navigation request (including redirects) where there is a
+    fetch event handler and the fetch event was successfully dispatched to the
+    service worker.
+
+    The records are breakdown by FetchEventResult.
+  </summary>
+</histogram>
+
+<histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.ForwardServiceWorkerToWorkerReady2"
     units="ms" expires_after="2023-06-30">
   <owner>yyanagisawa@chromium.org</owner>
@@ -616,6 +639,17 @@
   </summary>
 </histogram>
 
+<histogram name="ServiceWorker.MainFrame.MainResource.FetchResult"
+    enum="ServiceWorkerFetchEventResult" expires_after="2023-06-30">
+  <owner>yyanagisawa@chromium.org</owner>
+  <owner>chrome-worker@google.com</owner>
+  <summary>
+    Records the fetch result after the fetch handler has been dispatched. This
+    is recorded after dispatching the fetch event handler to a service worker,
+    and it executed the handler without error (i.e. abort or timeout).
+  </summary>
+</histogram>
+
 <histogram name="ServiceWorker.MaybeStartWorker.Purpose"
     enum="ServiceWorkerMetrics.EventType" expires_after="2023-06-30">
   <owner>yyanagisawa@chromium.org</owner>
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py
index 1cd8e30..5962329 100644
--- a/tools/perf/core/bot_platforms.py
+++ b/tools/perf/core/bot_platforms.py
@@ -473,6 +473,12 @@
     'blink_perf.display_locking',
     'v8.runtime_stats.top_25',
 ])
+_FUCHSIA_PERF_ASTRO_BENCHMARK_CONFIGS = PerfSuite([
+    _GetBenchmarkConfig('speedometer2'),
+])
+_FUCHSIA_PERF_SHERLOCK_BENCHMARK_CONFIGS = PerfSuite([
+    _GetBenchmarkConfig('speedometer2'),
+])
 _LINUX_PERF_FYI_BENCHMARK_CONFIGS = PerfSuite([
     _GetBenchmarkConfig('power.desktop'),
     _GetBenchmarkConfig('rendering.desktop'),
@@ -685,6 +691,20 @@
                                8, 'chromeos')
 LACROS_X86_PERF = PerfPlatform('lacros-x86-perf', '', _LACROS_BENCHMARK_CONFIGS,
                                12, 'chromeos')
+# Fuchsia
+FUCHSIA_PERF_ASTRO = PerfPlatform('fuchsia-perf-ast',
+                                  '',
+                                  _FUCHSIA_PERF_ASTRO_BENCHMARK_CONFIGS,
+                                  1,
+                                  'fuchsia',
+                                  executables=FUCHSIA_EXEC_CONFIGS['astro'])
+FUCHSIA_PERF_SHERLOCK = PerfPlatform(
+    'fuchsia-perf-shk',
+    '',
+    _FUCHSIA_PERF_SHERLOCK_BENCHMARK_CONFIGS,
+    1,
+    'fuchsia',
+    executables=FUCHSIA_EXEC_CONFIGS['sherlock'])
 
 # FYI bots
 WIN_10_LOW_END_HP_CANDIDATE = PerfPlatform(
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index c7d35e3..812fa0b7 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -338,9 +338,6 @@
             'chromium_builder_perf', 'base_perftests'
         ],
     },
-    'fuchsia-builder-perf-x64': {
-        'additional_compile_targets': ['chrome_pkg', 'base_perftests'],
-    },
 }
 
 # These configurations are taken from chromium_perf.py in
@@ -571,6 +568,15 @@
         'perf_trigger':
         False,
     },
+    'fuchsia-builder-perf-arm64': {
+        'additional_compile_targets': [
+            'web_engine_shell_pkg', 'cast_runner_pkg', 'web_runner_pkg',
+            'chromium_builder_perf', 'base_perftests'
+        ],
+    },
+    'fuchsia-builder-perf-x64': {
+        'additional_compile_targets': ['chrome_pkg', 'base_perftests'],
+    },
     'linux-builder-perf': {
         'additional_compile_targets': ['chromedriver', 'chromium_builder_perf'],
         'tests': [{
@@ -1176,6 +1182,44 @@
             'synthetic_product_name': 'PowerEdge R230 (Dell Inc.)'
         },
     },
+    'fuchsia-perf-ast': {
+        'tests': [{
+            'isolate':
+            'performance_web_engine_test_suite',
+            'extra_args':
+            ['--output-format=histograms', '--experimental-tbmv3-metrics'] +
+            bot_platforms.FUCHSIA_EXEC_ARGS['astro'],
+            'type':
+            TEST_TYPES.TELEMETRY,
+        }],
+        'platform':
+        'fuchsia-wes',
+        'dimension': {
+            'cpu': None,
+            'device_type': 'Astro',
+            'os': 'Fuchsia',
+            'pool': 'chrome.tests',
+        },
+    },
+    'fuchsia-perf-shk': {
+        'tests': [{
+            'isolate':
+            'performance_web_engine_test_suite',
+            'extra_args':
+            ['--output-format=histograms', '--experimental-tbmv3-metrics'] +
+            bot_platforms.FUCHSIA_EXEC_ARGS['sherlock'],
+            'type':
+            TEST_TYPES.TELEMETRY,
+        }],
+        'platform':
+        'fuchsia-wes',
+        'dimension': {
+            'cpu': None,
+            'device_type': 'Sherlock',
+            'os': 'Fuchsia',
+            'pool': 'chrome.tests',
+        },
+    },
     'mac-laptop_high_end-perf': {
         'tests': [
             {
@@ -1559,6 +1603,7 @@
     'performance_test_suite_octopus',
     'performance_webview_test_suite',
     'performance_weblayer_test_suite',
+    'performance_web_engine_test_suite',
 ]
 for suffix in android_browser_types.TELEMETRY_ANDROID_BROWSER_TARGET_SUFFIXES:
   PERFORMANCE_TEST_SUITES.append('performance_test_suite' + suffix)
diff --git a/tools/perf/core/perf_json_config_validator.py b/tools/perf/core/perf_json_config_validator.py
index 8baaae67..3dc85dd 100644
--- a/tools/perf/core/perf_json_config_validator.py
+++ b/tools/perf/core/perf_json_config_validator.py
@@ -34,6 +34,8 @@
     'fuchsia-perf-fyi': {'chrome.tests'},
     'fuchsia-perf-atlas-fyi': {'chrome.tests'},
     'fuchsia-perf-sherlock-fyi': {'chrome.tests'},
+    'fuchsia-perf-ast': {'chrome.tests'},
+    'fuchsia-perf-shk': {'chrome.tests'},
     'linux-builder-perf': {'chrome.tests'},
     'mac-arm-builder-perf': {'chrome.tests'},
     'mac-builder-perf': {'chrome.tests'},
diff --git a/tools/perf/core/shard_maps/fuchsia-perf-ast_map.json b/tools/perf/core/shard_maps/fuchsia-perf-ast_map.json
new file mode 100644
index 0000000..56832be7
--- /dev/null
+++ b/tools/perf/core/shard_maps/fuchsia-perf-ast_map.json
@@ -0,0 +1,29 @@
+{
+    "0": {
+        "benchmarks": {
+            "speedometer2": {
+                "abridged": false
+            }
+        },
+        "executables": {
+            "base_perftests": {
+                "arguments": [
+                    "--test-launcher-jobs=1",
+                    "--test-launcher-retry-limit=0",
+                    "-d",
+                    "--os-check=update",
+                    "--system-image-dir=../../third_party/fuchsia-sdk/images-internal/astro-release/smart_display_eng_arrested"
+                ],
+                "path": "bin/run_base_perftests"
+            }
+        }
+    },
+    "extra_infos": {
+        "num_stories": 2,
+        "predicted_min_shard_time": 910.0,
+        "predicted_min_shard_index": 0,
+        "predicted_max_shard_time": 910.0,
+        "predicted_max_shard_index": 0,
+        "shard #0": 910.0
+    }
+}
\ No newline at end of file
diff --git a/tools/perf/core/shard_maps/fuchsia-perf-fyi_map.json b/tools/perf/core/shard_maps/fuchsia-perf-fyi_map.json
index 04d9f8f..f2905f88 100644
--- a/tools/perf/core/shard_maps/fuchsia-perf-fyi_map.json
+++ b/tools/perf/core/shard_maps/fuchsia-perf-fyi_map.json
@@ -3,13 +3,6 @@
         "benchmarks": {
             "jetstream2": {
                 "abridged": false
-            },
-            "media.mobile": {
-                "abridged": false
-            },
-            "rendering.mobile": {
-                "end": 17,
-                "abridged": false
             }
         },
         "executables": {
@@ -27,9 +20,11 @@
     },
     "1": {
         "benchmarks": {
+            "media.mobile": {
+                "abridged": false
+            },
             "rendering.mobile": {
-                "begin": 17,
-                "end": 67,
+                "end": 53,
                 "abridged": false
             }
         }
@@ -37,8 +32,8 @@
     "2": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 67,
-                "end": 113,
+                "begin": 53,
+                "end": 111,
                 "abridged": false
             }
         }
@@ -46,8 +41,8 @@
     "3": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 113,
-                "end": 198,
+                "begin": 111,
+                "end": 190,
                 "abridged": false
             }
         }
@@ -55,8 +50,8 @@
     "4": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 198,
-                "end": 299,
+                "begin": 190,
+                "end": 301,
                 "abridged": false
             }
         }
@@ -64,8 +59,8 @@
     "5": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 299,
-                "end": 358,
+                "begin": 301,
+                "end": 356,
                 "abridged": false
             }
         }
@@ -73,8 +68,8 @@
     "6": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 358,
-                "end": 406,
+                "begin": 356,
+                "end": 413,
                 "abridged": false
             }
         }
@@ -82,7 +77,7 @@
     "7": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 406,
+                "begin": 413,
                 "abridged": false
             },
             "speedometer": {
@@ -92,7 +87,7 @@
                 "abridged": false
             },
             "system_health.memory_desktop": {
-                "end": 27,
+                "end": 22,
                 "abridged": false
             }
         }
@@ -100,8 +95,8 @@
     "8": {
         "benchmarks": {
             "system_health.memory_desktop": {
-                "begin": 27,
-                "end": 50,
+                "begin": 22,
+                "end": 48,
                 "abridged": false
             }
         }
@@ -109,26 +104,26 @@
     "9": {
         "benchmarks": {
             "system_health.memory_desktop": {
-                "begin": 50,
+                "begin": 48,
                 "abridged": false
             }
         }
     },
     "extra_infos": {
         "num_stories": 522,
-        "predicted_min_shard_time": 1662.0,
-        "predicted_min_shard_index": 9,
-        "predicted_max_shard_time": 1707.0,
-        "predicted_max_shard_index": 7,
-        "shard #0": 1688.0,
-        "shard #1": 1700.0,
-        "shard #2": 1694.0,
-        "shard #3": 1702.0,
-        "shard #4": 1690.0,
-        "shard #5": 1697.0,
-        "shard #6": 1670.0,
-        "shard #7": 1707.0,
-        "shard #8": 1689.0,
-        "shard #9": 1662.0
+        "predicted_min_shard_time": 1581.0,
+        "predicted_min_shard_index": 8,
+        "predicted_max_shard_time": 2068.0,
+        "predicted_max_shard_index": 0,
+        "shard #0": 2068.0,
+        "shard #1": 1597.0,
+        "shard #2": 1592.0,
+        "shard #3": 1597.0,
+        "shard #4": 1618.0,
+        "shard #5": 1583.0,
+        "shard #6": 1617.0,
+        "shard #7": 1596.0,
+        "shard #8": 1581.0,
+        "shard #9": 1587.0
     }
 }
\ No newline at end of file
diff --git a/tools/perf/core/shard_maps/fuchsia-perf-sherlock-fyi_map.json b/tools/perf/core/shard_maps/fuchsia-perf-sherlock-fyi_map.json
index db8a7d7..d68558b35 100644
--- a/tools/perf/core/shard_maps/fuchsia-perf-sherlock-fyi_map.json
+++ b/tools/perf/core/shard_maps/fuchsia-perf-sherlock-fyi_map.json
@@ -8,7 +8,7 @@
                 "abridged": false
             },
             "rendering.mobile": {
-                "end": 37,
+                "end": 20,
                 "abridged": false
             }
         },
@@ -28,8 +28,8 @@
     "1": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 37,
-                "end": 121,
+                "begin": 20,
+                "end": 119,
                 "abridged": false
             }
         }
@@ -37,8 +37,8 @@
     "2": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 121,
-                "end": 250,
+                "begin": 119,
+                "end": 267,
                 "abridged": false
             }
         }
@@ -46,8 +46,8 @@
     "3": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 250,
-                "end": 346,
+                "begin": 267,
+                "end": 369,
                 "abridged": false
             }
         }
@@ -55,16 +55,7 @@
     "4": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 346,
-                "end": 420,
-                "abridged": false
-            }
-        }
-    },
-    "5": {
-        "benchmarks": {
-            "rendering.mobile": {
-                "begin": 420,
+                "begin": 369,
                 "abridged": false
             },
             "speedometer": {
@@ -74,21 +65,30 @@
                 "abridged": false
             },
             "system_health.memory_desktop": {
+                "end": 24,
+                "abridged": false
+            }
+        }
+    },
+    "5": {
+        "benchmarks": {
+            "system_health.memory_desktop": {
+                "begin": 24,
                 "abridged": false
             }
         }
     },
     "extra_infos": {
         "num_stories": 522,
-        "predicted_min_shard_time": 1945.0,
-        "predicted_min_shard_index": 3,
-        "predicted_max_shard_time": 1977.0,
-        "predicted_max_shard_index": 5,
-        "shard #0": 1965.0,
-        "shard #1": 1964.0,
-        "shard #2": 1959.0,
-        "shard #3": 1945.0,
-        "shard #4": 1964.0,
-        "shard #5": 1977.0
+        "predicted_min_shard_time": 2647.0,
+        "predicted_min_shard_index": 5,
+        "predicted_max_shard_time": 2697.0,
+        "predicted_max_shard_index": 4,
+        "shard #0": 2660.0,
+        "shard #1": 2656.0,
+        "shard #2": 2666.0,
+        "shard #3": 2666.0,
+        "shard #4": 2697.0,
+        "shard #5": 2647.0
     }
 }
\ No newline at end of file
diff --git a/tools/perf/core/shard_maps/fuchsia-perf-shk_map.json b/tools/perf/core/shard_maps/fuchsia-perf-shk_map.json
new file mode 100644
index 0000000..beb58a1
--- /dev/null
+++ b/tools/perf/core/shard_maps/fuchsia-perf-shk_map.json
@@ -0,0 +1,29 @@
+{
+    "0": {
+        "benchmarks": {
+            "speedometer2": {
+                "abridged": false
+            }
+        },
+        "executables": {
+            "base_perftests": {
+                "arguments": [
+                    "--test-launcher-jobs=1",
+                    "--test-launcher-retry-limit=0",
+                    "-d",
+                    "--os-check=update",
+                    "--system-image-dir=../../third_party/fuchsia-sdk/images-internal/sherlock-release/smart_display_max_eng_arrested"
+                ],
+                "path": "bin/run_base_perftests"
+            }
+        }
+    },
+    "extra_infos": {
+        "num_stories": 2,
+        "predicted_min_shard_time": 910.0,
+        "predicted_min_shard_index": 0,
+        "predicted_max_shard_time": 910.0,
+        "predicted_max_shard_index": 0,
+        "shard #0": 910.0
+    }
+}
\ No newline at end of file
diff --git a/tools/perf/core/shard_maps/timing_data/fuchsia-perf-ast_timing.json b/tools/perf/core/shard_maps/timing_data/fuchsia-perf-ast_timing.json
new file mode 100644
index 0000000..4ecf637
--- /dev/null
+++ b/tools/perf/core/shard_maps/timing_data/fuchsia-perf-ast_timing.json
@@ -0,0 +1,6 @@
+[
+    {
+        "duration": "900.0",
+        "name": "base_perftests/_gtest_"
+    }
+]
\ No newline at end of file
diff --git a/tools/perf/core/shard_maps/timing_data/fuchsia-perf-fyi_timing.json b/tools/perf/core/shard_maps/timing_data/fuchsia-perf-fyi_timing.json
index b9bbdef..6634f7a 100644
--- a/tools/perf/core/shard_maps/timing_data/fuchsia-perf-fyi_timing.json
+++ b/tools/perf/core/shard_maps/timing_data/fuchsia-perf-fyi_timing.json
@@ -1,42 +1,46 @@
 [
     {
-        "duration": "10.0",
-        "name": "media.mobile/mse.html?media=aac_audio.mp4"
+        "duration": "1168.0",
+        "name": "jetstream2/JetStream2"
     },
     {
         "duration": "12.0",
+        "name": "media.mobile/mse.html?media=aac_audio.mp4"
+    },
+    {
+        "duration": "13.0",
         "name": "media.mobile/mse.html?media=aac_audio.mp4,h264_video.mp4"
     },
     {
-        "duration": "11.0",
+        "duration": "12.0",
         "name": "media.mobile/mse.html?media=h264_video.mp4"
     },
     {
-        "duration": "14.0",
+        "duration": "15.0",
         "name": "media.mobile/mse.html?media=tulip2.vp9.webm"
     },
     {
-        "duration": "3.0",
+        "duration": "4.0",
         "name": "media.mobile/video.html?src=boat_1080p60fps_vp9.webm"
     },
     {
-        "duration": "3.0",
+        "duration": "4.0",
         "name": "media.mobile/video.html?src=foodmarket_720p30fps.mp4"
     },
     {
-        "duration": "23.0",
+        "duration": "24.0",
         "name": "media.mobile/video.html?src=tulip2.m4a&type=audio"
     },
     {
-        "duration": "23.0",
+        "duration": "24.0",
         "name": "media.mobile/video.html?src=tulip2.mp3&type=audio"
     },
     {
-        "duration": "7.0",
+        "duration": "8.0",
         "name": "media.mobile/video.html?src=tulip2.mp3&type=audio&seek"
     },
     {
-        "duration": "27.0",
+        "duration": "26.0",
         "name": "media.mobile/video.html?src=tulip2.mp4"
     },
     {
@@ -44,19 +48,19 @@
         "name": "media.mobile/video.html?src=tulip2.mp4&busyjs"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "media.mobile/video.html?src=tulip2.ogg&type=audio"
     },
     {
-        "duration": "7.0",
+        "duration": "8.0",
         "name": "media.mobile/video.html?src=tulip2.ogg&type=audio&seek"
     },
     {
-        "duration": "26.0",
+        "duration": "27.0",
         "name": "media.mobile/video.html?src=tulip2.vp9.webm"
     },
     {
-        "duration": "3.0",
+        "duration": "4.0",
         "name": "media.mobile/video.html?src=tulip2.vp9.webm&background"
     },
     {
@@ -64,559 +68,559 @@
         "name": "media.mobile/video.html?src=tulip2.vp9.webm_WiFi"
     },
     {
-        "duration": "41.0",
+        "duration": "35.0",
         "name": "rendering.mobile/accu_weather_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "7.0",
         "name": "rendering.mobile/accu_weather_mobile_pinch_2018"
     },
     {
-        "duration": "31.0",
+        "duration": "29.0",
         "name": "rendering.mobile/amazon_2018"
     },
     {
-        "duration": "32.0",
+        "duration": "31.0",
         "name": "rendering.mobile/amazon_mobile_2018"
     },
     {
-        "duration": "23.0",
+        "duration": "20.0",
         "name": "rendering.mobile/analog_clock_svg"
     },
     {
-        "duration": "49.0",
+        "duration": "32.0",
         "name": "rendering.mobile/androidpolice_mobile_2018"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "rendering.mobile/animometer_webgl"
     },
     {
-        "duration": "26.0",
+        "duration": "23.0",
         "name": "rendering.mobile/animometer_webgl_attrib_arrays"
     },
     {
-        "duration": "34.0",
+        "duration": "23.0",
         "name": "rendering.mobile/animometer_webgl_multi_draw"
     },
     {
-        "duration": "41.0",
+        "duration": "29.0",
         "name": "rendering.mobile/aquarium"
     },
     {
-        "duration": "18.0",
+        "duration": "7.0",
         "name": "rendering.mobile/aquarium_20k"
     },
     {
-        "duration": "38.0",
+        "duration": "22.0",
         "name": "rendering.mobile/background_color_animation"
     },
     {
-        "duration": "31.0",
+        "duration": "20.0",
         "name": "rendering.mobile/background_color_animation_with_gradient"
     },
     {
-        "duration": "34.0",
+        "duration": "18.0",
         "name": "rendering.mobile/baidu_mobile_2018"
     },
     {
-        "duration": "38.0",
+        "duration": "29.0",
         "name": "rendering.mobile/balls_css_key_frame_animations"
     },
     {
-        "duration": "43.0",
+        "duration": "34.0",
         "name": "rendering.mobile/balls_css_key_frame_animations_composited_transform"
     },
     {
-        "duration": "32.0",
+        "duration": "37.0",
         "name": "rendering.mobile/balls_css_transition_2_properties"
     },
     {
-        "duration": "32.0",
+        "duration": "29.0",
         "name": "rendering.mobile/balls_css_transition_40_properties"
     },
     {
-        "duration": "32.0",
+        "duration": "31.0",
         "name": "rendering.mobile/balls_css_transition_all_properties"
     },
     {
-        "duration": "32.0",
+        "duration": "24.0",
         "name": "rendering.mobile/balls_javascript_canvas"
     },
     {
-        "duration": "34.0",
+        "duration": "25.0",
         "name": "rendering.mobile/balls_javascript_css"
     },
     {
-        "duration": "18.0",
+        "duration": "8.0",
         "name": "rendering.mobile/balls_svg_animations"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/basic_stream"
     },
     {
-        "duration": "31.0",
+        "duration": "26.0",
         "name": "rendering.mobile/bing_mobile_2018"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/blob"
     },
     {
-        "duration": "18.0",
+        "duration": "8.0",
         "name": "rendering.mobile/blogspot_2018"
     },
     {
-        "duration": "32.0",
+        "duration": "21.0",
         "name": "rendering.mobile/blogspot_mobile_2018"
     },
     {
-        "duration": "27.0",
+        "duration": "18.0",
         "name": "rendering.mobile/blur_rotating_background"
     },
     {
-        "duration": "45.0",
+        "duration": "42.0",
         "name": "rendering.mobile/boingboing_mobile_2018"
     },
     {
-        "duration": "44.0",
+        "duration": "34.0",
         "name": "rendering.mobile/booking.com_2018"
     },
     {
-        "duration": "38.0",
+        "duration": "29.0",
         "name": "rendering.mobile/booking.com_mobile_2018"
     },
     {
-        "duration": "32.0",
+        "duration": "22.0",
         "name": "rendering.mobile/bouncing_balls_15"
     },
     {
-        "duration": "46.0",
+        "duration": "41.0",
         "name": "rendering.mobile/bouncing_balls_shadow"
     },
     {
-        "duration": "33.0",
+        "duration": "26.0",
         "name": "rendering.mobile/bouncing_clipped_rectangles"
     },
     {
-        "duration": "32.0",
+        "duration": "22.0",
         "name": "rendering.mobile/bouncing_gradient_circles"
     },
     {
-        "duration": "32.0",
+        "duration": "25.0",
         "name": "rendering.mobile/bouncing_png_images"
     },
     {
-        "duration": "38.0",
+        "duration": "29.0",
         "name": "rendering.mobile/bouncing_svg_images"
     },
     {
-        "duration": "33.0",
+        "duration": "30.0",
         "name": "rendering.mobile/camera_to_webgl"
     },
     {
-        "duration": "32.0",
+        "duration": "24.0",
         "name": "rendering.mobile/canvas2d_to_texture.html"
     },
     {
-        "duration": "38.0",
+        "duration": "39.0",
         "name": "rendering.mobile/canvas_05000_pixels_per_second"
     },
     {
-        "duration": "44.0",
+        "duration": "45.0",
         "name": "rendering.mobile/canvas_10000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "34.0",
         "name": "rendering.mobile/canvas_20000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "34.0",
         "name": "rendering.mobile/canvas_40000_pixels_per_second"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.mobile/canvas_60000_pixels_per_second"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.mobile/canvas_75000_pixels_per_second"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.mobile/canvas_90000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "25.0",
         "name": "rendering.mobile/canvas_animation_no_clear"
     },
     {
-        "duration": "32.0",
+        "duration": "23.0",
         "name": "rendering.mobile/canvas_arcs"
     },
     {
-        "duration": "34.0",
+        "duration": "28.0",
         "name": "rendering.mobile/canvas_font_cycler"
     },
     {
-        "duration": "32.0",
+        "duration": "23.0",
         "name": "rendering.mobile/canvas_lines"
     },
     {
-        "duration": "33.0",
+        "duration": "24.0",
         "name": "rendering.mobile/canvas_to_blob"
     },
     {
-        "duration": "31.0",
+        "duration": "24.0",
         "name": "rendering.mobile/canvas_to_canvas_draw"
     },
     {
-        "duration": "44.0",
+        "duration": "35.0",
         "name": "rendering.mobile/capitolvolkswagen_mobile_2018"
     },
     {
-        "duration": "17.0",
+        "duration": "13.0",
         "name": "rendering.mobile/card_expansion"
     },
     {
-        "duration": "18.0",
+        "duration": "14.0",
         "name": "rendering.mobile/card_expansion_animated"
     },
     {
-        "duration": "18.0",
+        "duration": "17.0",
         "name": "rendering.mobile/card_expansion_images_text"
     },
     {
-        "duration": "17.0",
+        "duration": "19.0",
         "name": "rendering.mobile/card_flying"
     },
     {
-        "duration": "35.0",
+        "duration": "28.0",
         "name": "rendering.mobile/cc_poster_circle"
     },
     {
-        "duration": "32.0",
+        "duration": "24.0",
         "name": "rendering.mobile/cc_scroll_text_only"
     },
     {
-        "duration": "35.0",
+        "duration": "30.0",
         "name": "rendering.mobile/chip_tune"
     },
     {
-        "duration": "64.0",
+        "duration": "47.0",
         "name": "rendering.mobile/cnn_2018"
     },
     {
-        "duration": "18.0",
+        "duration": "8.0",
         "name": "rendering.mobile/cnn_article_mobile_2018"
     },
     {
-        "duration": "60.0",
+        "duration": "45.0",
         "name": "rendering.mobile/cnn_mobile_2018"
     },
     {
-        "duration": "18.0",
+        "duration": "8.0",
         "name": "rendering.mobile/cnn_mobile_pinch_2018"
     },
     {
-        "duration": "55.0",
+        "duration": "45.0",
         "name": "rendering.mobile/cnn_pathological_2018"
     },
     {
-        "duration": "32.0",
+        "duration": "22.0",
         "name": "rendering.mobile/compositor_heavy_animation"
     },
     {
-        "duration": "19.0",
+        "duration": "24.0",
         "name": "rendering.mobile/coordinated_animation"
     },
     {
-        "duration": "32.0",
+        "duration": "23.0",
         "name": "rendering.mobile/crafty_mind"
     },
     {
-        "duration": "39.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_animations_many_keyframes"
     },
     {
-        "duration": "43.0",
+        "duration": "25.0",
         "name": "rendering.mobile/css_animations_simultaneous_inline_style"
     },
     {
-        "duration": "37.0",
+        "duration": "27.0",
         "name": "rendering.mobile/css_animations_simultaneous_new_element"
     },
     {
-        "duration": "37.0",
+        "duration": "26.0",
         "name": "rendering.mobile/css_animations_simultaneous_style_element"
     },
     {
-        "duration": "37.0",
+        "duration": "27.0",
         "name": "rendering.mobile/css_animations_simultaneous_updating_class"
     },
     {
-        "duration": "37.0",
+        "duration": "35.0",
         "name": "rendering.mobile/css_animations_staggered_infinite_iterations"
     },
     {
-        "duration": "39.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_animations_staggered_inline_style"
     },
     {
-        "duration": "39.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_animations_staggered_new_element"
     },
     {
-        "duration": "40.0",
+        "duration": "32.0",
         "name": "rendering.mobile/css_animations_staggered_style_element"
     },
     {
-        "duration": "39.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_animations_staggered_updating_class"
     },
     {
-        "duration": "39.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_animations_triggered_inline_style"
     },
     {
-        "duration": "39.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_animations_triggered_new_element"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_animations_triggered_style_element"
     },
     {
-        "duration": "39.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_animations_triggered_updating_class"
     },
     {
-        "duration": "34.0",
+        "duration": "26.0",
         "name": "rendering.mobile/css_opacity_plus_n_layers_0"
     },
     {
-        "duration": "35.0",
+        "duration": "25.0",
         "name": "rendering.mobile/css_opacity_plus_n_layers_75"
     },
     {
-        "duration": "37.0",
+        "duration": "27.0",
         "name": "rendering.mobile/css_opacity_plus_n_layers_99"
     },
     {
-        "duration": "37.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_transitions_inline_style"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_new_element"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_staggered_inline_style"
     },
     {
-        "duration": "38.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_staggered_new_element"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_staggered_style_element"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_staggered_updating_class"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_style_element"
     },
     {
-        "duration": "38.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_triggered_inline_style"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_triggered_new_element"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_triggered_style_element"
     },
     {
-        "duration": "38.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_triggered_updating_class"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_updating_class"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_color"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_filter"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_value_type_length"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_length_complex"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_length_simple"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_path"
     },
     {
-        "duration": "35.0",
+        "duration": "27.0",
         "name": "rendering.mobile/css_value_type_shadow"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_value_type_transform_complex"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_value_type_transform_simple"
     },
     {
-        "duration": "42.0",
+        "duration": "34.0",
         "name": "rendering.mobile/deviantart_mobile_2018"
     },
     {
-        "duration": "22.0",
+        "duration": "14.0",
         "name": "rendering.mobile/digg_mobile_2018"
     },
     {
-        "duration": "22.0",
+        "duration": "14.0",
         "name": "rendering.mobile/docs_paper.html"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/docs_resume.html"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/docs_table.html"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/draw_image"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/draw_image_not_pixel_aligned"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/dynamic_canvas_to_hw_accelerated_canvas.html"
     },
     {
-        "duration": "41.0",
+        "duration": "33.0",
         "name": "rendering.mobile/dynamic_cube_map"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/dynamic_webgl_to_hw_accelerated_canvas.html"
     },
     {
-        "duration": "39.0",
+        "duration": "31.0",
         "name": "rendering.mobile/earth"
     },
     {
-        "duration": "43.0",
+        "duration": "34.0",
         "name": "rendering.mobile/ebay_2018"
     },
     {
-        "duration": "34.0",
+        "duration": "26.0",
         "name": "rendering.mobile/ebay_mobile_2018"
     },
     {
-        "duration": "22.0",
+        "duration": "14.0",
         "name": "rendering.mobile/ebay_mobile_pinch_2018"
     },
     {
-        "duration": "30.0",
+        "duration": "31.0",
         "name": "rendering.mobile/ebay_scroll_2018"
     },
     {
-        "duration": "40.0",
+        "duration": "26.0",
         "name": "rendering.mobile/effect_games"
     },
     {
-        "duration": "22.0",
+        "duration": "14.0",
         "name": "rendering.mobile/espn_2018"
     },
     {
-        "duration": "65.0",
+        "duration": "52.0",
         "name": "rendering.mobile/espn_mobile_2018"
     },
     {
-        "duration": "40.0",
+        "duration": "26.0",
         "name": "rendering.mobile/espn_pathological_2018"
     },
     {
-        "duration": "37.0",
+        "duration": "30.0",
         "name": "rendering.mobile/extra_large_texture_uploads"
     },
     {
-        "duration": "22.0",
+        "duration": "6.0",
         "name": "rendering.mobile/facebook_2018"
     },
     {
-        "duration": "22.0",
+        "duration": "6.0",
         "name": "rendering.mobile/facebook_mobile_2018"
     },
     {
-        "duration": "36.0",
+        "duration": "22.0",
         "name": "rendering.mobile/falling_particle_simulation_cpu.html"
     },
     {
-        "duration": "36.0",
+        "duration": "21.0",
         "name": "rendering.mobile/falling_particle_simulation_gpu.html"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/famo_us_twitter_demo"
     },
     {
-        "duration": "36.0",
+        "duration": "24.0",
         "name": "rendering.mobile/fill_clear_rect.html"
     },
     {
-        "duration": "36.0",
+        "duration": "22.0",
         "name": "rendering.mobile/fill_shapes"
     },
     {
-        "duration": "18.0",
+        "duration": "20.0",
         "name": "rendering.mobile/filter_terrain_svg"
     },
     {
-        "duration": "30.0",
+        "duration": "31.0",
         "name": "rendering.mobile/flickr_scroll_2018"
     },
     {
-        "duration": "19.0",
+        "duration": "23.0",
         "name": "rendering.mobile/font_wipe"
     },
     {
-        "duration": "19.0",
+        "duration": "24.0",
         "name": "rendering.mobile/forecast.io_mobile_2018"
     },
     {
-        "duration": "19.0",
+        "duration": "21.0",
         "name": "rendering.mobile/get_image_data_cpu.html"
     },
     {
-        "duration": "19.0",
+        "duration": "21.0",
         "name": "rendering.mobile/get_image_data_gpu.html"
     },
     {
@@ -632,19 +636,19 @@
         "name": "rendering.mobile/google_docs_2018"
     },
     {
-        "duration": "21.0",
+        "duration": "25.0",
         "name": "rendering.mobile/google_image_search_2018"
     },
     {
-        "duration": "17.0",
+        "duration": "21.0",
         "name": "rendering.mobile/google_image_search_mobile_2018"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/google_news_ios"
     },
     {
-        "duration": "22.0",
+        "duration": "26.0",
         "name": "rendering.mobile/google_news_mobile_2018"
     },
     {
@@ -652,7 +656,7 @@
         "name": "rendering.mobile/google_plus_2018"
     },
     {
-        "duration": "12.0",
+        "duration": "15.0",
         "name": "rendering.mobile/google_plus_mobile_2018"
     },
     {
@@ -664,23 +668,23 @@
         "name": "rendering.mobile/google_web_search_2018"
     },
     {
-        "duration": "15.0",
+        "duration": "17.0",
         "name": "rendering.mobile/google_web_search_mobile_2018"
     },
     {
-        "duration": "23.0",
+        "duration": "32.0",
         "name": "rendering.mobile/gpu_bound_shader.html"
     },
     {
-        "duration": "30.0",
+        "duration": "29.0",
         "name": "rendering.mobile/gsp.ro_mobile_2018"
     },
     {
-        "duration": "18.0",
+        "duration": "29.0",
         "name": "rendering.mobile/guardian_pathological_2018"
     },
     {
-        "duration": "20.0",
+        "duration": "21.0",
         "name": "rendering.mobile/guimark_vector_chart"
     },
     {
@@ -696,151 +700,151 @@
         "name": "rendering.mobile/hakim"
     },
     {
-        "duration": "18.0",
+        "duration": "14.0",
         "name": "rendering.mobile/horizontal_vertical_expansion"
     },
     {
-        "duration": "20.0",
+        "duration": "22.0",
         "name": "rendering.mobile/hw_accelerated_canvas_to_sw_canvas.html"
     },
     {
-        "duration": "10.0",
+        "duration": "7.0",
         "name": "rendering.mobile/idle_power_animated_gif"
     },
     {
-        "duration": "18.0",
+        "duration": "8.0",
         "name": "rendering.mobile/idle_power_blank"
     },
     {
-        "duration": "18.0",
+        "duration": "8.0",
         "name": "rendering.mobile/idle_power_css_animation"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/idle_power_request_animation_frame"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "rendering.mobile/idle_power_set_timeout_long"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "rendering.mobile/idle_power_set_timetout"
     },
     {
-        "duration": "18.0",
+        "duration": "8.0",
         "name": "rendering.mobile/ie_chalkboard"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/ie_pirate_mark"
     },
     {
-        "duration": "21.0",
+        "duration": "25.0",
         "name": "rendering.mobile/infinite_scroll_element_n_layers_0"
     },
     {
-        "duration": "22.0",
+        "duration": "23.0",
         "name": "rendering.mobile/infinite_scroll_element_n_layers_75"
     },
     {
-        "duration": "23.0",
+        "duration": "25.0",
         "name": "rendering.mobile/infinite_scroll_element_n_layers_99"
     },
     {
-        "duration": "21.0",
+        "duration": "26.0",
         "name": "rendering.mobile/infinite_scroll_root_fixed_n_layers_0"
     },
     {
-        "duration": "22.0",
+        "duration": "24.0",
         "name": "rendering.mobile/infinite_scroll_root_fixed_n_layers_75"
     },
     {
-        "duration": "23.0",
+        "duration": "24.0",
         "name": "rendering.mobile/infinite_scroll_root_fixed_n_layers_99"
     },
     {
-        "duration": "21.0",
+        "duration": "26.0",
         "name": "rendering.mobile/infinite_scroll_root_n_layers_0"
     },
     {
-        "duration": "22.0",
+        "duration": "23.0",
         "name": "rendering.mobile/infinite_scroll_root_n_layers_75"
     },
     {
-        "duration": "23.0",
+        "duration": "24.0",
         "name": "rendering.mobile/infinite_scroll_root_n_layers_99"
     },
     {
-        "duration": "23.0",
+        "duration": "18.0",
         "name": "rendering.mobile/infinite_scrolling"
     },
     {
-        "duration": "21.0",
+        "duration": "23.0",
         "name": "rendering.mobile/jarro_doverson"
     },
     {
-        "duration": "13.0",
+        "duration": "19.0",
         "name": "rendering.mobile/jpeg_decoding_rgb_and_gpu_rasterization"
     },
     {
-        "duration": "13.0",
+        "duration": "15.0",
         "name": "rendering.mobile/jpeg_decoding_yuv_and_gpu_rasterization"
     },
     {
-        "duration": "25.0",
+        "duration": "28.0",
         "name": "rendering.mobile/js_full_screen_invalidation"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/js_opacity_plus_n_layers_0"
     },
     {
-        "duration": "24.0",
+        "duration": "27.0",
         "name": "rendering.mobile/js_opacity_plus_n_layers_75"
     },
     {
-        "duration": "26.0",
+        "duration": "31.0",
         "name": "rendering.mobile/js_opacity_plus_n_layers_99"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/js_paint_plus_n_layers_0"
     },
     {
-        "duration": "24.0",
+        "duration": "27.0",
         "name": "rendering.mobile/js_paint_plus_n_layers_75"
     },
     {
-        "duration": "26.0",
+        "duration": "30.0",
         "name": "rendering.mobile/js_paint_plus_n_layers_99"
     },
     {
-        "duration": "24.0",
+        "duration": "26.0",
         "name": "rendering.mobile/js_poster_circle"
     },
     {
-        "duration": "22.0",
+        "duration": "26.0",
         "name": "rendering.mobile/js_scroll_text_only"
     },
     {
-        "duration": "22.0",
+        "duration": "23.0",
         "name": "rendering.mobile/kevs_3d"
     },
     {
-        "duration": "19.0",
+        "duration": "23.0",
         "name": "rendering.mobile/keyframed_animations"
     },
     {
-        "duration": "19.0",
+        "duration": "20.0",
         "name": "rendering.mobile/large_texture_uploads"
     },
     {
-        "duration": "32.0",
+        "duration": "31.0",
         "name": "rendering.mobile/latimes_pathological_2018"
     },
     {
-        "duration": "14.0",
+        "duration": "16.0",
         "name": "rendering.mobile/linkedin_2018"
     },
     {
@@ -856,31 +860,31 @@
         "name": "rendering.mobile/linkedin_pathological_2018"
     },
     {
-        "duration": "16.0",
+        "duration": "12.0",
         "name": "rendering.mobile/list_animation_simple"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/list_recycle_transform"
     },
     {
-        "duration": "19.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_0fps_impl_60fps"
     },
     {
-        "duration": "19.0",
+        "duration": "20.0",
         "name": "rendering.mobile/main_0fps_impl_60fps_no_update"
     },
     {
-        "duration": "19.0",
+        "duration": "20.0",
         "name": "rendering.mobile/main_0fps_impl_60fps_no_update_jank"
     },
     {
-        "duration": "18.0",
+        "duration": "20.0",
         "name": "rendering.mobile/main_0fps_with_jank_impl_0fps"
     },
     {
-        "duration": "19.0",
+        "duration": "20.0",
         "name": "rendering.mobile/main_15fps_impl_0fps"
     },
     {
@@ -888,15 +892,15 @@
         "name": "rendering.mobile/main_15fps_with_jank_impl_0fps"
     },
     {
-        "duration": "19.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_30fps_impl_0fps"
     },
     {
-        "duration": "19.0",
+        "duration": "22.0",
         "name": "rendering.mobile/main_30fps_impl_60fps"
     },
     {
-        "duration": "19.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_60fps_impl_0fps"
     },
     {
@@ -904,7 +908,7 @@
         "name": "rendering.mobile/main_60fps_impl_60fps"
     },
     {
-        "duration": "19.0",
+        "duration": "20.0",
         "name": "rendering.mobile/main_60fps_impl_60fps_no_update"
     },
     {
@@ -928,11 +932,11 @@
         "name": "rendering.mobile/main_animations_half_presented"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/man_in_blue"
     },
     {
-        "duration": "36.0",
+        "duration": "28.0",
         "name": "rendering.mobile/many_images"
     },
     {
@@ -940,247 +944,247 @@
         "name": "rendering.mobile/many_planets_deep"
     },
     {
-        "duration": "31.0",
+        "duration": "29.0",
         "name": "rendering.mobile/maps_perf_test"
     },
     {
-        "duration": "18.0",
+        "duration": "14.0",
         "name": "rendering.mobile/mask_transition_animation"
     },
     {
-        "duration": "21.0",
+        "duration": "28.0",
         "name": "rendering.mobile/masonry"
     },
     {
-        "duration": "23.0",
+        "duration": "19.0",
         "name": "rendering.mobile/medium_texture_uploads"
     },
     {
-        "duration": "24.0",
+        "duration": "20.0",
         "name": "rendering.mobile/megi_dish"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/microgame_fps"
     },
     {
-        "duration": "22.0",
+        "duration": "17.0",
         "name": "rendering.mobile/microsoft_asteroid_belt"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/microsoft_fireflies"
     },
     {
-        "duration": "22.0",
+        "duration": "18.0",
         "name": "rendering.mobile/microsoft_fish_ie_tank"
     },
     {
-        "duration": "22.0",
+        "duration": "18.0",
         "name": "rendering.mobile/microsoft_performance"
     },
     {
-        "duration": "22.0",
+        "duration": "18.0",
         "name": "rendering.mobile/microsoft_snow"
     },
     {
-        "duration": "22.0",
+        "duration": "18.0",
         "name": "rendering.mobile/microsoft_speed_reading"
     },
     {
-        "duration": "22.0",
+        "duration": "18.0",
         "name": "rendering.mobile/microsoft_tweet_map"
     },
     {
-        "duration": "22.0",
+        "duration": "18.0",
         "name": "rendering.mobile/microsoft_video_city"
     },
     {
-        "duration": "22.0",
+        "duration": "18.0",
         "name": "rendering.mobile/microsoft_worker_fountains"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/mix_10k"
     },
     {
-        "duration": "23.0",
+        "duration": "19.0",
         "name": "rendering.mobile/mix_blend_mode_animation_difference"
     },
     {
-        "duration": "23.0",
+        "duration": "21.0",
         "name": "rendering.mobile/mix_blend_mode_animation_hue"
     },
     {
-        "duration": "23.0",
+        "duration": "20.0",
         "name": "rendering.mobile/mix_blend_mode_animation_propagating_isolation"
     },
     {
-        "duration": "23.0",
+        "duration": "18.0",
         "name": "rendering.mobile/mix_blend_mode_animation_screen"
     },
     {
-        "duration": "51.0",
+        "duration": "62.0",
         "name": "rendering.mobile/mlb_mobile_2018"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/mobile_news_sandbox"
     },
     {
-        "duration": "24.0",
+        "duration": "23.0",
         "name": "rendering.mobile/motion_mark_canvas_fill_shapes"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/motion_mark_canvas_stroke_shapes"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_anim_design_15"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_anim_focus_25"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_anim_images_50"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_anim_leaves_250"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_anim_multiply_175"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_anim_suits_125"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_composited_transforms_125"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_blend_circles_25"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_circles_250"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_clipped_rects_100"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_filter_circles_15"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_gradient_circles_250"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_svg_images_50"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_tagged_images_225"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_dom_particles_svg_masks_25"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_focus_20_15"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_html_leaves_20_50"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_ramp_canvas_arcs"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_ramp_canvas_lines"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_ramp_design"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_ramp_images"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_ramp_leaves"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_ramp_multiply"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_ramp_paths"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_ramp_suits"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_svg_bouncing_circles_250"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_svg_bouncing_clipped_rects_100"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_svg_bouncing_gradient_circles_200"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_svg_bouncing_png_images_200"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/motionmark_svg_bouncing_svg_images_50"
     },
     {
-        "duration": "27.0",
+        "duration": "23.0",
         "name": "rendering.mobile/new_tilings"
     },
     {
-        "duration": "21.0",
+        "duration": "20.0",
         "name": "rendering.mobile/no_op_raf"
     },
     {
-        "duration": "20.0",
+        "duration": "23.0",
         "name": "rendering.mobile/no_op_scroll"
     },
     {
-        "duration": "19.0",
+        "duration": "14.0",
         "name": "rendering.mobile/no_op_settimeout"
     },
     {
-        "duration": "20.0",
+        "duration": "16.0",
         "name": "rendering.mobile/no_op_touch_handler"
     },
     {
-        "duration": "23.0",
+        "duration": "20.0",
         "name": "rendering.mobile/no_update_compositor_animation_with_janky_main_animation"
     },
     {
-        "duration": "35.0",
+        "duration": "33.0",
         "name": "rendering.mobile/non_opaque_background_compositor_thread_scrolling_00050_pixels_per_second"
     },
     {
@@ -1188,143 +1192,143 @@
         "name": "rendering.mobile/non_opaque_background_main_thread_scrolling_00050_pixels_per_second"
     },
     {
-        "duration": "25.0",
+        "duration": "24.0",
         "name": "rendering.mobile/nvidia_vertex_buffer_object"
     },
     {
-        "duration": "30.0",
+        "duration": "31.0",
         "name": "rendering.mobile/nyc_gov_scroll_2018"
     },
     {
-        "duration": "54.0",
+        "duration": "45.0",
         "name": "rendering.mobile/nytimes_mobile_2018"
     },
     {
-        "duration": "47.0",
+        "duration": "51.0",
         "name": "rendering.mobile/nytimes_scroll_2018"
     },
     {
-        "duration": "22.0",
+        "duration": "19.0",
         "name": "rendering.mobile/off_screen_main_60fps"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/off_screen_main_60fps_jank"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/offscreen_animation_no_damage"
     },
     {
-        "duration": "23.0",
+        "duration": "20.0",
         "name": "rendering.mobile/overlay_background_color_css_transitions_page"
     },
     {
-        "duration": "23.0",
+        "duration": "19.0",
         "name": "rendering.mobile/paint_worklet"
     },
     {
-        "duration": "18.0",
+        "duration": "23.0",
         "name": "rendering.mobile/parallax_effect"
     },
     {
-        "duration": "26.0",
+        "duration": "22.0",
         "name": "rendering.mobile/particles"
     },
     {
-        "duration": "32.0",
+        "duration": "27.0",
         "name": "rendering.mobile/pbs_pathological_2018"
     },
     {
-        "duration": "16.0",
+        "duration": "21.0",
         "name": "rendering.mobile/physical_simulation"
     },
     {
-        "duration": "24.0",
+        "duration": "27.0",
         "name": "rendering.mobile/pinterest_2018"
     },
     {
-        "duration": "16.0",
+        "duration": "18.0",
         "name": "rendering.mobile/pinterest_mobile_2018"
     },
     {
-        "duration": "26.0",
+        "duration": "29.0",
         "name": "rendering.mobile/put_and_create_imagebitmap_from_imagedata"
     },
     {
-        "duration": "24.0",
+        "duration": "20.0",
         "name": "rendering.mobile/put_get_image_data"
     },
     {
-        "duration": "24.0",
+        "duration": "26.0",
         "name": "rendering.mobile/put_image_data.html"
     },
     {
-        "duration": "21.0",
+        "duration": "22.0",
         "name": "rendering.mobile/raf"
     },
     {
-        "duration": "20.0",
+        "duration": "26.0",
         "name": "rendering.mobile/raf_animation"
     },
     {
-        "duration": "21.0",
+        "duration": "23.0",
         "name": "rendering.mobile/raf_canvas"
     },
     {
-        "duration": "20.0",
+        "duration": "21.0",
         "name": "rendering.mobile/raf_touch_animation"
     },
     {
-        "duration": "40.0",
+        "duration": "32.0",
         "name": "rendering.mobile/recode_pathological_2018"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/reddit_mobile_2018"
     },
     {
-        "duration": "25.0",
+        "duration": "26.0",
         "name": "rendering.mobile/runway_2019"
     },
     {
-        "duration": "28.0",
+        "duration": "30.0",
         "name": "rendering.mobile/san_angeles"
     },
     {
-        "duration": "14.0",
+        "duration": "15.0",
         "name": "rendering.mobile/second_batch_js_heavy"
     },
     {
-        "duration": "14.0",
+        "duration": "15.0",
         "name": "rendering.mobile/second_batch_js_light"
     },
     {
-        "duration": "14.0",
+        "duration": "16.0",
         "name": "rendering.mobile/second_batch_js_medium"
     },
     {
-        "duration": "62.0",
+        "duration": "63.0",
         "name": "rendering.mobile/sfgate_mobile_2018"
     },
     {
-        "duration": "23.0",
+        "duration": "25.0",
         "name": "rendering.mobile/sheets_render.html"
     },
     {
-        "duration": "25.0",
+        "duration": "26.0",
         "name": "rendering.mobile/silk_finance"
     },
     {
-        "duration": "20.0",
+        "duration": "21.0",
         "name": "rendering.mobile/simple_text_page"
     },
     {
-        "duration": "26.0",
+        "duration": "16.0",
         "name": "rendering.mobile/simple_touch_drag"
     },
     {
-        "duration": "62.0",
+        "duration": "64.0",
         "name": "rendering.mobile/skelebuddies_wasm_2020"
     },
     {
@@ -1332,127 +1336,127 @@
         "name": "rendering.mobile/slashdot_mobile_2018"
     },
     {
-        "duration": "23.0",
+        "duration": "24.0",
         "name": "rendering.mobile/small_texture_uploads"
     },
     {
-        "duration": "28.0",
+        "duration": "29.0",
         "name": "rendering.mobile/smash_cat"
     },
     {
-        "duration": "24.0",
+        "duration": "25.0",
         "name": "rendering.mobile/spielzeugz"
     },
     {
-        "duration": "23.0",
+        "duration": "25.0",
         "name": "rendering.mobile/static_canvas_to_hw_accelerated_canvas.html"
     },
     {
-        "duration": "23.0",
+        "duration": "25.0",
         "name": "rendering.mobile/static_webgl_to_hw_accelerated_canvas.html"
     },
     {
-        "duration": "9.0",
+        "duration": "3.0",
         "name": "rendering.mobile/sticky_using_webkit"
     },
     {
-        "duration": "24.0",
+        "duration": "26.0",
         "name": "rendering.mobile/stroke_shapes"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "rendering.mobile/svg_icon_raster"
     },
     {
-        "duration": "17.0",
+        "duration": "20.0",
         "name": "rendering.mobile/swipe_to_dismiss"
     },
     {
-        "duration": "35.0",
+        "duration": "21.0",
         "name": "rendering.mobile/sync_scroll_offset"
     },
     {
-        "duration": "58.0",
+        "duration": "52.0",
         "name": "rendering.mobile/techcrunch_2018"
     },
     {
-        "duration": "58.0",
+        "duration": "50.0",
         "name": "rendering.mobile/techcrunch_mobile_2018"
     },
     {
-        "duration": "37.0",
+        "duration": "38.0",
         "name": "rendering.mobile/text_05000_pixels_per_second"
     },
     {
-        "duration": "37.0",
+        "duration": "38.0",
         "name": "rendering.mobile/text_10000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_20000_pixels_per_second"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.mobile/text_40000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_60000_pixels_per_second"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.mobile/text_75000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_90000_pixels_per_second"
     },
     {
-        "duration": "32.0",
+        "duration": "34.0",
         "name": "rendering.mobile/text_constant_full_page_raster_05000_pixels_per_second"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.mobile/text_constant_full_page_raster_10000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "35.0",
         "name": "rendering.mobile/text_constant_full_page_raster_20000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_constant_full_page_raster_40000_pixels_per_second"
     },
     {
-        "duration": "32.0",
+        "duration": "34.0",
         "name": "rendering.mobile/text_constant_full_page_raster_60000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "33.0",
         "name": "rendering.mobile/text_constant_full_page_raster_75000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "33.0",
         "name": "rendering.mobile/text_constant_full_page_raster_90000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_fling_05000_pixels_per_second"
     },
     {
-        "duration": "26.0",
+        "duration": "28.0",
         "name": "rendering.mobile/text_fling_10000_pixels_per_second"
     },
     {
-        "duration": "28.0",
+        "duration": "33.0",
         "name": "rendering.mobile/text_fling_20000_pixels_per_second"
     },
     {
-        "duration": "37.0",
+        "duration": "38.0",
         "name": "rendering.mobile/text_hover_05000_pixels_per_second"
     },
     {
-        "duration": "37.0",
+        "duration": "38.0",
         "name": "rendering.mobile/text_hover_10000_pixels_per_second"
     },
     {
@@ -1460,294 +1464,302 @@
         "name": "rendering.mobile/text_hover_20000_pixels_per_second"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.mobile/text_hover_40000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_hover_60000_pixels_per_second"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "rendering.mobile/text_hover_75000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_hover_90000_pixels_per_second"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "rendering.mobile/text_scrollbar_100_pixels_per_second"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "rendering.mobile/text_scrollbar_1200_pixels_per_second"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "rendering.mobile/text_scrollbar_200_pixels_per_second"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "rendering.mobile/text_scrollbar_2300_pixels_per_second"
     },
     {
-        "duration": "9.0",
+        "duration": "10.0",
         "name": "rendering.mobile/text_scrollbar_700_pixels_per_second"
     },
     {
-        "duration": "47.0",
+        "duration": "39.0",
         "name": "rendering.mobile/theverge_article_mobile_2018"
     },
     {
-        "duration": "52.0",
+        "duration": "35.0",
         "name": "rendering.mobile/theverge_mobile_2018"
     },
     {
-        "duration": "38.0",
+        "duration": "34.0",
         "name": "rendering.mobile/throughput_scrolling_active_handler"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.mobile/throughput_scrolling_composited"
     },
     {
-        "duration": "38.0",
+        "duration": "30.0",
         "name": "rendering.mobile/throughput_scrolling_passive_handler"
     },
     {
-        "duration": "39.0",
+        "duration": "31.0",
         "name": "rendering.mobile/throughput_scrolling_uncomposited"
     },
     {
-        "duration": "72.0",
+        "duration": "63.0",
         "name": "rendering.mobile/tiny_racing_v3_wasm_2020"
     },
     {
-        "duration": "34.0",
+        "duration": "23.0",
         "name": "rendering.mobile/toBlob_duration.html"
     },
     {
-        "duration": "34.0",
+        "duration": "26.0",
         "name": "rendering.mobile/toBlob_duration_jpeg.html"
     },
     {
-        "duration": "36.0",
+        "duration": "30.0",
         "name": "rendering.mobile/toBlob_small_canvas_in_worker.html"
     },
     {
-        "duration": "30.0",
+        "duration": "21.0",
         "name": "rendering.mobile/touch_handler_scrolling"
     },
     {
-        "duration": "33.0",
+        "duration": "23.0",
         "name": "rendering.mobile/transfer_from_imageBitmap.html"
     },
     {
-        "duration": "33.0",
+        "duration": "23.0",
         "name": "rendering.mobile/transform_transitions"
     },
     {
-        "duration": "33.0",
+        "duration": "23.0",
         "name": "rendering.mobile/transform_transitions_js_block"
     },
     {
-        "duration": "20.0",
+        "duration": "9.0",
         "name": "rendering.mobile/twitch_2018"
     },
     {
-        "duration": "20.0",
+        "duration": "9.0",
         "name": "rendering.mobile/twitch_mobile_pinch_2018"
     },
     {
-        "duration": "20.0",
+        "duration": "9.0",
         "name": "rendering.mobile/twitter_2018"
     },
     {
-        "duration": "37.0",
+        "duration": "29.0",
         "name": "rendering.mobile/twitter_mobile_2018"
     },
     {
-        "duration": "30.0",
+        "duration": "21.0",
         "name": "rendering.mobile/update_history_state"
     },
     {
-        "duration": "50.0",
+        "duration": "47.0",
         "name": "rendering.mobile/usatoday_mobile_2018"
     },
     {
-        "duration": "18.0",
+        "duration": "15.0",
         "name": "rendering.mobile/vertical_expansion"
     },
     {
-        "duration": "35.0",
+        "duration": "25.0",
         "name": "rendering.mobile/video_to_hw_accelerated_canvas"
     },
     {
-        "duration": "20.0",
+        "duration": "9.0",
         "name": "rendering.mobile/video_to_sub_texture"
     },
     {
-        "duration": "20.0",
+        "duration": "9.0",
         "name": "rendering.mobile/video_to_sub_texture_flip_and_premultiply"
     },
     {
-        "duration": "20.0",
+        "duration": "9.0",
         "name": "rendering.mobile/video_to_sub_texture_flip_y"
     },
     {
-        "duration": "20.0",
+        "duration": "9.0",
         "name": "rendering.mobile/video_to_sub_texture_premultiply"
     },
     {
-        "duration": "20.0",
+        "duration": "9.0",
         "name": "rendering.mobile/video_to_texture"
     },
     {
-        "duration": "33.0",
+        "duration": "26.0",
         "name": "rendering.mobile/web_animation_value_type_color"
     },
     {
-        "duration": "35.0",
+        "duration": "25.0",
         "name": "rendering.mobile/web_animation_value_type_length_3d"
     },
     {
-        "duration": "33.0",
+        "duration": "25.0",
         "name": "rendering.mobile/web_animation_value_type_length_complex"
     },
     {
-        "duration": "33.0",
+        "duration": "23.0",
         "name": "rendering.mobile/web_animation_value_type_length_simple"
     },
     {
-        "duration": "33.0",
+        "duration": "25.0",
         "name": "rendering.mobile/web_animation_value_type_path"
     },
     {
-        "duration": "33.0",
+        "duration": "24.0",
         "name": "rendering.mobile/web_animation_value_type_shadow"
     },
     {
-        "duration": "35.0",
+        "duration": "25.0",
         "name": "rendering.mobile/web_animation_value_type_transform_complex"
     },
     {
-        "duration": "35.0",
+        "duration": "28.0",
         "name": "rendering.mobile/web_animation_value_type_transform_simple"
     },
     {
-        "duration": "20.0",
+        "duration": "9.0",
         "name": "rendering.mobile/web_animations_many_keyframes"
     },
     {
-        "duration": "35.0",
+        "duration": "29.0",
         "name": "rendering.mobile/web_animations_set_current_time"
     },
     {
-        "duration": "35.0",
+        "duration": "26.0",
         "name": "rendering.mobile/web_animations_simultaneous"
     },
     {
-        "duration": "36.0",
+        "duration": "30.0",
         "name": "rendering.mobile/web_animations_staggered_chaining"
     },
     {
-        "duration": "35.0",
+        "duration": "27.0",
         "name": "rendering.mobile/web_animations_staggered_infinite_iterations"
     },
     {
-        "duration": "37.0",
+        "duration": "27.0",
         "name": "rendering.mobile/web_animations_staggered_triggering_page"
     },
     {
-        "duration": "34.0",
+        "duration": "26.0",
         "name": "rendering.mobile/webgl_to_texture"
     },
     {
-        "duration": "27.0",
+        "duration": "21.0",
         "name": "rendering.mobile/webp_decoding_rgb_and_gpu_rasterization"
     },
     {
-        "duration": "27.0",
+        "duration": "17.0",
         "name": "rendering.mobile/webp_decoding_yuv_and_gpu_rasterization"
     },
     {
-        "duration": "40.0",
+        "duration": "38.0",
         "name": "rendering.mobile/wikipedia_2018"
     },
     {
-        "duration": "40.0",
+        "duration": "32.0",
         "name": "rendering.mobile/wikipedia_delayed_scroll_start_2018"
     },
     {
-        "duration": "36.0",
+        "duration": "34.0",
         "name": "rendering.mobile/wikipedia_mobile_2018"
     },
     {
-        "duration": "20.0",
+        "duration": "10.0",
         "name": "rendering.mobile/wordpress_2018"
     },
     {
-        "duration": "40.0",
+        "duration": "31.0",
         "name": "rendering.mobile/wordpress_mobile_2018"
     },
     {
-        "duration": "48.0",
+        "duration": "58.0",
         "name": "rendering.mobile/worldjournal_mobile_2018"
     },
     {
-        "duration": "49.0",
+        "duration": "51.0",
         "name": "rendering.mobile/wow_wiki_pathological_2018"
     },
     {
-        "duration": "74.0",
+        "duration": "76.0",
         "name": "rendering.mobile/wowwiki_mobile_2018"
     },
     {
-        "duration": "81.0",
+        "duration": "64.0",
         "name": "rendering.mobile/wsj_mobile_2018"
     },
     {
-        "duration": "47.0",
+        "duration": "46.0",
         "name": "rendering.mobile/yahoo_answers_2018"
     },
     {
-        "duration": "11.0",
+        "duration": "10.0",
         "name": "rendering.mobile/yahoo_answers_mobile_2018"
     },
     {
-        "duration": "34.0",
+        "duration": "32.0",
         "name": "rendering.mobile/yahoo_news_2018"
     },
     {
-        "duration": "33.0",
+        "duration": "30.0",
         "name": "rendering.mobile/yahoo_news_mobile_2018"
     },
     {
-        "duration": "40.0",
+        "duration": "39.0",
         "name": "rendering.mobile/yahoo_sports_2018"
     },
     {
-        "duration": "40.0",
+        "duration": "39.0",
         "name": "rendering.mobile/yahoo_sports_pathological_2018"
     },
     {
-        "duration": "11.0",
+        "duration": "10.0",
         "name": "rendering.mobile/youtube_2018"
     },
     {
-        "duration": "11.0",
+        "duration": "10.0",
         "name": "rendering.mobile/youtube_mobile_2018"
     },
     {
-        "duration": "41.0",
+        "duration": "34.0",
         "name": "rendering.mobile/zdnet_pathological_2018"
     },
     {
-        "duration": "17.0",
+        "duration": "13.0",
         "name": "rendering.mobile/zoom_in_animation"
     },
     {
+        "duration": "257.0",
+        "name": "speedometer/http://browserbench.org/Speedometer/"
+    },
+    {
+        "duration": "435.0",
+        "name": "speedometer2/Speedometer2"
+    },
+    {
         "duration": "1.0",
         "name": "system_health.memory_desktop/browse:media:googleplaystore:2021"
     },
@@ -1756,11 +1768,11 @@
         "name": "system_health.memory_desktop/browse:media:imgur"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:media:pinterest:2018"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:media:tumblr:2018"
     },
     {
@@ -1768,11 +1780,11 @@
         "name": "system_health.memory_desktop/browse:media:youtube:2019"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:media:youtubetv:2019"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:media:youtubetv_watch:2020"
     },
     {
@@ -1784,15 +1796,15 @@
         "name": "system_health.memory_desktop/browse:news:flipboard:2020"
     },
     {
-        "duration": "69.0",
+        "duration": "56.0",
         "name": "system_health.memory_desktop/browse:news:hackernews:2020"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:news:nytimes:2020"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:news:reddit:2020"
     },
     {
@@ -1808,15 +1820,15 @@
         "name": "system_health.memory_desktop/browse:social:facebook_infinite_scroll:2018"
     },
     {
-        "duration": "68.0",
+        "duration": "64.0",
         "name": "system_health.memory_desktop/browse:social:tumblr_infinite_scroll:2018"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:social:twitter:2018"
     },
     {
-        "duration": "5.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:social:twitter_infinite_scroll:2018"
     },
     {
@@ -1828,7 +1840,7 @@
         "name": "system_health.memory_desktop/browse:tools:autocad:2021"
     },
     {
-        "duration": "39.0",
+        "duration": "38.0",
         "name": "system_health.memory_desktop/browse:tools:docs_scrolling"
     },
     {
@@ -1852,11 +1864,11 @@
         "name": "system_health.memory_desktop/browse:tools:maps:2019"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:tools:photoshop:2021"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:tools:photoshop_warm:2021"
     },
     {
@@ -1864,19 +1876,15 @@
         "name": "system_health.memory_desktop/browse:tools:sheets:2019"
     },
     {
-        "duration": "36.0",
-        "name": "system_health.memory_desktop/browse_accessibility:media:youtube"
-    },
-    {
         "duration": "1.0",
         "name": "system_health.memory_desktop/browse_accessibility:tech:codesearch:2018"
     },
     {
-        "duration": "13.0",
+        "duration": "12.0",
         "name": "system_health.memory_desktop/load:chrome:blank"
     },
     {
-        "duration": "19.0",
+        "duration": "18.0",
         "name": "system_health.memory_desktop/load:games:alphabetty:2018"
     },
     {
@@ -1884,131 +1892,131 @@
         "name": "system_health.memory_desktop/load:games:bubbles:2020"
     },
     {
-        "duration": "22.0",
+        "duration": "24.0",
         "name": "system_health.memory_desktop/load:games:lazors"
     },
     {
-        "duration": "30.0",
+        "duration": "18.0",
         "name": "system_health.memory_desktop/load:games:miniclip:2018"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/load:games:spychase:2018"
     },
     {
-        "duration": "28.0",
+        "duration": "23.0",
         "name": "system_health.memory_desktop/load:media:9gag"
     },
     {
-        "duration": "30.0",
+        "duration": "26.0",
         "name": "system_health.memory_desktop/load:media:dailymotion:2019"
     },
     {
-        "duration": "7.0",
+        "duration": "2.0",
         "name": "system_health.memory_desktop/load:media:facebook_feed:desktop:2020"
     },
     {
-        "duration": "20.0",
+        "duration": "19.0",
         "name": "system_health.memory_desktop/load:media:facebook_photos:2018"
     },
     {
-        "duration": "7.0",
+        "duration": "2.0",
         "name": "system_health.memory_desktop/load:media:facebook_photos:desktop:2020"
     },
     {
-        "duration": "28.0",
+        "duration": "29.0",
         "name": "system_health.memory_desktop/load:media:flickr:2018"
     },
     {
-        "duration": "22.0",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:media:google_images:2018"
     },
     {
-        "duration": "63.0",
+        "duration": "37.0",
         "name": "system_health.memory_desktop/load:media:imgur:2018"
     },
     {
-        "duration": "29.0",
+        "duration": "25.0",
         "name": "system_health.memory_desktop/load:media:soundcloud:2018"
     },
     {
-        "duration": "30.0",
+        "duration": "28.0",
         "name": "system_health.memory_desktop/load:media:youtube:2018"
     },
     {
-        "duration": "19.0",
+        "duration": "16.0",
         "name": "system_health.memory_desktop/load:media:youtubelivingroom:2020"
     },
     {
-        "duration": "24.0",
+        "duration": "28.0",
         "name": "system_health.memory_desktop/load:news:bbc:2018"
     },
     {
-        "duration": "7.0",
+        "duration": "2.0",
         "name": "system_health.memory_desktop/load:news:cnn:2020"
     },
     {
-        "duration": "25.0",
+        "duration": "23.0",
         "name": "system_health.memory_desktop/load:news:flipboard"
     },
     {
-        "duration": "18.0",
+        "duration": "19.0",
         "name": "system_health.memory_desktop/load:news:hackernews:2018"
     },
     {
-        "duration": "45.0",
+        "duration": "48.0",
         "name": "system_health.memory_desktop/load:news:nytimes:2018"
     },
     {
-        "duration": "27.0",
+        "duration": "23.0",
         "name": "system_health.memory_desktop/load:news:qq:2018"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/load:news:reddit:2018"
     },
     {
-        "duration": "20.0",
+        "duration": "17.0",
         "name": "system_health.memory_desktop/load:news:wikipedia:2018"
     },
     {
-        "duration": "23.0",
+        "duration": "22.0",
         "name": "system_health.memory_desktop/load:search:amazon:2018"
     },
     {
-        "duration": "30.0",
+        "duration": "24.0",
         "name": "system_health.memory_desktop/load:search:baidu:2018"
     },
     {
-        "duration": "32.0",
+        "duration": "31.0",
         "name": "system_health.memory_desktop/load:search:ebay:2018"
     },
     {
-        "duration": "39.0",
+        "duration": "36.0",
         "name": "system_health.memory_desktop/load:search:flipkart:2018"
     },
     {
-        "duration": "21.0",
+        "duration": "22.0",
         "name": "system_health.memory_desktop/load:search:google:2018"
     },
     {
-        "duration": "24.0",
+        "duration": "20.0",
         "name": "system_health.memory_desktop/load:search:taobao:2018"
     },
     {
-        "duration": "18.0",
+        "duration": "15.0",
         "name": "system_health.memory_desktop/load:search:yahoo:2018"
     },
     {
-        "duration": "19.0",
+        "duration": "17.0",
         "name": "system_health.memory_desktop/load:search:yandex:2018"
     },
     {
-        "duration": "20.0",
+        "duration": "19.0",
         "name": "system_health.memory_desktop/load:social:instagram:2018"
     },
     {
-        "duration": "16.0",
+        "duration": "13.0",
         "name": "system_health.memory_desktop/load:social:pinterest:2019"
     },
     {
@@ -2016,27 +2024,27 @@
         "name": "system_health.memory_desktop/load:social:vk:2018"
     },
     {
-        "duration": "7.0",
+        "duration": "2.0",
         "name": "system_health.memory_desktop/load:tools:chat:2020"
     },
     {
-        "duration": "47.0",
+        "duration": "52.0",
         "name": "system_health.memory_desktop/load:tools:docs:2019"
     },
     {
-        "duration": "22.0",
+        "duration": "24.0",
         "name": "system_health.memory_desktop/load:tools:drive:2019"
     },
     {
-        "duration": "7.0",
+        "duration": "2.0",
         "name": "system_health.memory_desktop/load:tools:gmail:2019"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "system_health.memory_desktop/load:tools:stackoverflow:2018"
     },
     {
-        "duration": "30.0",
+        "duration": "25.0",
         "name": "system_health.memory_desktop/load:tools:weather:2019"
     },
     {
@@ -2044,23 +2052,23 @@
         "name": "system_health.memory_desktop/load_accessibility:media:wikipedia:2018"
     },
     {
-        "duration": "37.0",
+        "duration": "35.0",
         "name": "system_health.memory_desktop/load_accessibility:shopping:amazon:2018"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/long_running:tools:gmail-background"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/long_running:tools:gmail-foreground"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/multitab:misc:typical24"
     },
     {
-        "duration": "4.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/multitab:misc:typical24:2018"
     },
     {
@@ -2068,7 +2076,7 @@
         "name": "system_health.memory_desktop/play:media:google_play_music"
     },
     {
-        "duration": "50.0",
+        "duration": "48.0",
         "name": "system_health.memory_desktop/play:media:soundcloud:2018"
     },
     {
diff --git a/tools/perf/core/shard_maps/timing_data/fuchsia-perf-sherlock-fyi_timing.json b/tools/perf/core/shard_maps/timing_data/fuchsia-perf-sherlock-fyi_timing.json
index 13968f7..39ff6de 100644
--- a/tools/perf/core/shard_maps/timing_data/fuchsia-perf-sherlock-fyi_timing.json
+++ b/tools/perf/core/shard_maps/timing_data/fuchsia-perf-sherlock-fyi_timing.json
@@ -1,5 +1,9 @@
 [
     {
+        "duration": "1075.0",
+        "name": "jetstream2/JetStream2"
+    },
+    {
         "duration": "10.0",
         "name": "media.mobile/mse.html?media=aac_audio.mp4"
     },
@@ -44,15 +48,15 @@
         "name": "media.mobile/video.html?src=tulip2.mp4&busyjs"
     },
     {
-        "duration": "26.0",
+        "duration": "25.0",
         "name": "media.mobile/video.html?src=tulip2.ogg&type=audio"
     },
     {
-        "duration": "7.0",
+        "duration": "8.0",
         "name": "media.mobile/video.html?src=tulip2.ogg&type=audio&seek"
     },
     {
-        "duration": "24.0",
+        "duration": "25.0",
         "name": "media.mobile/video.html?src=tulip2.vp9.webm"
     },
     {
@@ -68,7 +72,7 @@
         "name": "rendering.mobile/accu_weather_2018"
     },
     {
-        "duration": "8.0",
+        "duration": "6.0",
         "name": "rendering.mobile/accu_weather_mobile_pinch_2018"
     },
     {
@@ -76,27 +80,27 @@
         "name": "rendering.mobile/amazon_2018"
     },
     {
-        "duration": "29.0",
+        "duration": "30.0",
         "name": "rendering.mobile/amazon_mobile_2018"
     },
     {
-        "duration": "21.0",
+        "duration": "19.0",
         "name": "rendering.mobile/analog_clock_svg"
     },
     {
-        "duration": "37.0",
+        "duration": "28.0",
         "name": "rendering.mobile/androidpolice_mobile_2018"
     },
     {
-        "duration": "27.0",
+        "duration": "25.0",
         "name": "rendering.mobile/animometer_webgl"
     },
     {
-        "duration": "24.0",
+        "duration": "23.0",
         "name": "rendering.mobile/animometer_webgl_attrib_arrays"
     },
     {
-        "duration": "24.0",
+        "duration": "23.0",
         "name": "rendering.mobile/animometer_webgl_multi_draw"
     },
     {
@@ -104,23 +108,23 @@
         "name": "rendering.mobile/aquarium"
     },
     {
-        "duration": "8.0",
+        "duration": "6.0",
         "name": "rendering.mobile/aquarium_20k"
     },
     {
-        "duration": "23.0",
+        "duration": "22.0",
         "name": "rendering.mobile/background_color_animation"
     },
     {
-        "duration": "21.0",
+        "duration": "20.0",
         "name": "rendering.mobile/background_color_animation_with_gradient"
     },
     {
-        "duration": "18.0",
+        "duration": "16.0",
         "name": "rendering.mobile/baidu_mobile_2018"
     },
     {
-        "duration": "27.0",
+        "duration": "26.0",
         "name": "rendering.mobile/balls_css_key_frame_animations"
     },
     {
@@ -128,119 +132,119 @@
         "name": "rendering.mobile/balls_css_key_frame_animations_composited_transform"
     },
     {
-        "duration": "22.0",
+        "duration": "27.0",
         "name": "rendering.mobile/balls_css_transition_2_properties"
     },
     {
-        "duration": "22.0",
+        "duration": "27.0",
         "name": "rendering.mobile/balls_css_transition_40_properties"
     },
     {
-        "duration": "22.0",
+        "duration": "27.0",
         "name": "rendering.mobile/balls_css_transition_all_properties"
     },
     {
-        "duration": "22.0",
+        "duration": "20.0",
         "name": "rendering.mobile/balls_javascript_canvas"
     },
     {
-        "duration": "24.0",
+        "duration": "22.0",
         "name": "rendering.mobile/balls_javascript_css"
     },
     {
-        "duration": "8.0",
+        "duration": "6.0",
         "name": "rendering.mobile/balls_svg_animations"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/basic_stream"
     },
     {
-        "duration": "19.0",
+        "duration": "18.0",
         "name": "rendering.mobile/bing_mobile_2018"
     },
     {
-        "duration": "25.0",
+        "duration": "23.0",
         "name": "rendering.mobile/blob"
     },
     {
-        "duration": "8.0",
+        "duration": "6.0",
         "name": "rendering.mobile/blogspot_2018"
     },
     {
-        "duration": "19.0",
+        "duration": "17.0",
         "name": "rendering.mobile/blogspot_mobile_2018"
     },
     {
-        "duration": "16.0",
+        "duration": "14.0",
         "name": "rendering.mobile/blur_rotating_background"
     },
     {
-        "duration": "36.0",
+        "duration": "33.0",
         "name": "rendering.mobile/boingboing_mobile_2018"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "rendering.mobile/booking.com_2018"
     },
     {
-        "duration": "26.0",
+        "duration": "23.0",
         "name": "rendering.mobile/booking.com_mobile_2018"
     },
     {
-        "duration": "21.0",
+        "duration": "20.0",
         "name": "rendering.mobile/bouncing_balls_15"
     },
     {
-        "duration": "34.0",
+        "duration": "33.0",
         "name": "rendering.mobile/bouncing_balls_shadow"
     },
     {
-        "duration": "23.0",
+        "duration": "21.0",
         "name": "rendering.mobile/bouncing_clipped_rectangles"
     },
     {
-        "duration": "22.0",
+        "duration": "20.0",
         "name": "rendering.mobile/bouncing_gradient_circles"
     },
     {
-        "duration": "21.0",
+        "duration": "20.0",
         "name": "rendering.mobile/bouncing_png_images"
     },
     {
-        "duration": "27.0",
+        "duration": "36.0",
         "name": "rendering.mobile/bouncing_svg_images"
     },
     {
-        "duration": "25.0",
+        "duration": "33.0",
         "name": "rendering.mobile/camera_to_webgl"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/canvas2d_to_texture.html"
     },
     {
-        "duration": "33.0",
+        "duration": "39.0",
         "name": "rendering.mobile/canvas_05000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "38.0",
         "name": "rendering.mobile/canvas_10000_pixels_per_second"
     },
     {
-        "duration": "28.0",
+        "duration": "34.0",
         "name": "rendering.mobile/canvas_20000_pixels_per_second"
     },
     {
-        "duration": "27.0",
+        "duration": "34.0",
         "name": "rendering.mobile/canvas_40000_pixels_per_second"
     },
     {
-        "duration": "27.0",
+        "duration": "33.0",
         "name": "rendering.mobile/canvas_60000_pixels_per_second"
     },
     {
-        "duration": "36.0",
+        "duration": "33.0",
         "name": "rendering.mobile/canvas_75000_pixels_per_second"
     },
     {
@@ -248,299 +252,299 @@
         "name": "rendering.mobile/canvas_90000_pixels_per_second"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/canvas_animation_no_clear"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/canvas_arcs"
     },
     {
-        "duration": "28.0",
+        "duration": "33.0",
         "name": "rendering.mobile/canvas_font_cycler"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/canvas_lines"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/canvas_to_blob"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/canvas_to_canvas_draw"
     },
     {
-        "duration": "37.0",
+        "duration": "41.0",
         "name": "rendering.mobile/capitolvolkswagen_mobile_2018"
     },
     {
-        "duration": "12.0",
+        "duration": "19.0",
         "name": "rendering.mobile/card_expansion"
     },
     {
-        "duration": "13.0",
+        "duration": "20.0",
         "name": "rendering.mobile/card_expansion_animated"
     },
     {
-        "duration": "13.0",
+        "duration": "20.0",
         "name": "rendering.mobile/card_expansion_images_text"
     },
     {
-        "duration": "12.0",
+        "duration": "19.0",
         "name": "rendering.mobile/card_flying"
     },
     {
-        "duration": "25.0",
+        "duration": "32.0",
         "name": "rendering.mobile/cc_poster_circle"
     },
     {
-        "duration": "19.0",
+        "duration": "26.0",
         "name": "rendering.mobile/cc_scroll_text_only"
     },
     {
-        "duration": "27.0",
+        "duration": "34.0",
         "name": "rendering.mobile/chip_tune"
     },
     {
-        "duration": "42.0",
+        "duration": "51.0",
         "name": "rendering.mobile/cnn_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/cnn_article_mobile_2018"
     },
     {
-        "duration": "42.0",
+        "duration": "46.0",
         "name": "rendering.mobile/cnn_mobile_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/cnn_mobile_pinch_2018"
     },
     {
-        "duration": "40.0",
+        "duration": "44.0",
         "name": "rendering.mobile/cnn_pathological_2018"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/compositor_heavy_animation"
     },
     {
-        "duration": "14.0",
+        "duration": "21.0",
         "name": "rendering.mobile/coordinated_animation"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/crafty_mind"
     },
     {
-        "duration": "30.0",
+        "duration": "35.0",
         "name": "rendering.mobile/css_animations_many_keyframes"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_animations_simultaneous_inline_style"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_animations_simultaneous_new_element"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_animations_simultaneous_style_element"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_animations_simultaneous_updating_class"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_animations_staggered_infinite_iterations"
     },
     {
-        "duration": "26.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_animations_staggered_inline_style"
     },
     {
-        "duration": "26.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_animations_staggered_new_element"
     },
     {
-        "duration": "26.0",
+        "duration": "32.0",
         "name": "rendering.mobile/css_animations_staggered_style_element"
     },
     {
-        "duration": "26.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_animations_staggered_updating_class"
     },
     {
-        "duration": "26.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_animations_triggered_inline_style"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/css_animations_triggered_new_element"
     },
     {
-        "duration": "25.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_animations_triggered_style_element"
     },
     {
-        "duration": "26.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_animations_triggered_updating_class"
     },
     {
-        "duration": "24.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_opacity_plus_n_layers_0"
     },
     {
-        "duration": "24.0",
+        "duration": "31.0",
         "name": "rendering.mobile/css_opacity_plus_n_layers_75"
     },
     {
-        "duration": "30.0",
+        "duration": "33.0",
         "name": "rendering.mobile/css_opacity_plus_n_layers_99"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_inline_style"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_new_element"
     },
     {
-        "duration": "25.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_staggered_inline_style"
     },
     {
-        "duration": "25.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_staggered_new_element"
     },
     {
-        "duration": "25.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_staggered_style_element"
     },
     {
-        "duration": "25.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_staggered_updating_class"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_style_element"
     },
     {
-        "duration": "25.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_triggered_inline_style"
     },
     {
-        "duration": "25.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_triggered_new_element"
     },
     {
-        "duration": "25.0",
+        "duration": "30.0",
         "name": "rendering.mobile/css_transitions_triggered_style_element"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/css_transitions_triggered_updating_class"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_transitions_updating_class"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_color"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_filter"
     },
     {
-        "duration": "25.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_value_type_length"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_length_complex"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_length_simple"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_path"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/css_value_type_shadow"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_value_type_transform_complex"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/css_value_type_transform_simple"
     },
     {
-        "duration": "23.0",
+        "duration": "29.0",
         "name": "rendering.mobile/deviantart_mobile_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/digg_mobile_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/docs_paper.html"
     },
     {
-        "duration": "23.0",
+        "duration": "29.0",
         "name": "rendering.mobile/docs_resume.html"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/docs_table.html"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/draw_image"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/draw_image_not_pixel_aligned"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/dynamic_canvas_to_hw_accelerated_canvas.html"
     },
     {
-        "duration": "27.0",
+        "duration": "33.0",
         "name": "rendering.mobile/dynamic_cube_map"
     },
     {
-        "duration": "24.0",
+        "duration": "28.0",
         "name": "rendering.mobile/dynamic_webgl_to_hw_accelerated_canvas.html"
     },
     {
-        "duration": "26.0",
+        "duration": "31.0",
         "name": "rendering.mobile/earth"
     },
     {
-        "duration": "27.0",
+        "duration": "28.0",
         "name": "rendering.mobile/ebay_2018"
     },
     {
-        "duration": "20.0",
+        "duration": "25.0",
         "name": "rendering.mobile/ebay_mobile_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/ebay_mobile_pinch_2018"
     },
     {
@@ -548,147 +552,147 @@
         "name": "rendering.mobile/ebay_scroll_2018"
     },
     {
-        "duration": "25.0",
+        "duration": "30.0",
         "name": "rendering.mobile/effect_games"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/espn_2018"
     },
     {
-        "duration": "46.0",
+        "duration": "49.0",
         "name": "rendering.mobile/espn_mobile_2018"
     },
     {
-        "duration": "26.0",
+        "duration": "31.0",
         "name": "rendering.mobile/espn_pathological_2018"
     },
     {
-        "duration": "24.0",
+        "duration": "29.0",
         "name": "rendering.mobile/extra_large_texture_uploads"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/facebook_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/facebook_mobile_2018"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/falling_particle_simulation_cpu.html"
     },
     {
-        "duration": "23.0",
+        "duration": "28.0",
         "name": "rendering.mobile/falling_particle_simulation_gpu.html"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/famo_us_twitter_demo"
     },
     {
-        "duration": "23.0",
+        "duration": "29.0",
         "name": "rendering.mobile/fill_clear_rect.html"
     },
     {
-        "duration": "24.0",
+        "duration": "25.0",
         "name": "rendering.mobile/fill_shapes"
     },
     {
-        "duration": "22.0",
+        "duration": "20.0",
         "name": "rendering.mobile/filter_terrain_svg"
     },
     {
-        "duration": "30.0",
+        "duration": "31.0",
         "name": "rendering.mobile/flickr_scroll_2018"
     },
     {
-        "duration": "14.0",
+        "duration": "21.0",
         "name": "rendering.mobile/font_wipe"
     },
     {
-        "duration": "17.0",
+        "duration": "21.0",
         "name": "rendering.mobile/forecast.io_mobile_2018"
     },
     {
-        "duration": "23.0",
+        "duration": "21.0",
         "name": "rendering.mobile/get_image_data_cpu.html"
     },
     {
-        "duration": "23.0",
+        "duration": "21.0",
         "name": "rendering.mobile/get_image_data_gpu.html"
     },
     {
-        "duration": "10.0",
+        "duration": "8.0",
         "name": "rendering.mobile/gmail_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "8.0",
         "name": "rendering.mobile/google_calendar_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "8.0",
         "name": "rendering.mobile/google_docs_2018"
     },
     {
-        "duration": "20.0",
+        "duration": "23.0",
         "name": "rendering.mobile/google_image_search_2018"
     },
     {
-        "duration": "20.0",
+        "duration": "18.0",
         "name": "rendering.mobile/google_image_search_mobile_2018"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/google_news_ios"
     },
     {
-        "duration": "23.0",
+        "duration": "22.0",
         "name": "rendering.mobile/google_news_mobile_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "8.0",
         "name": "rendering.mobile/google_plus_2018"
     },
     {
-        "duration": "15.0",
+        "duration": "14.0",
         "name": "rendering.mobile/google_plus_mobile_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "8.0",
         "name": "rendering.mobile/google_search_mobile_pinch_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "8.0",
         "name": "rendering.mobile/google_web_search_2018"
     },
     {
-        "duration": "18.0",
+        "duration": "16.0",
         "name": "rendering.mobile/google_web_search_mobile_2018"
     },
     {
-        "duration": "30.0",
+        "duration": "26.0",
         "name": "rendering.mobile/gpu_bound_shader.html"
     },
     {
-        "duration": "30.0",
+        "duration": "29.0",
         "name": "rendering.mobile/gsp.ro_mobile_2018"
     },
     {
-        "duration": "19.0",
+        "duration": "25.0",
         "name": "rendering.mobile/guardian_pathological_2018"
     },
     {
-        "duration": "24.0",
+        "duration": "22.0",
         "name": "rendering.mobile/guimark_vector_chart"
     },
     {
-        "duration": "10.0",
+        "duration": "8.0",
         "name": "rendering.mobile/gws_boogie_expansion"
     },
     {
-        "duration": "10.0",
+        "duration": "8.0",
         "name": "rendering.mobile/gws_google_expansion"
     },
     {
@@ -696,63 +700,63 @@
         "name": "rendering.mobile/hakim"
     },
     {
-        "duration": "13.0",
+        "duration": "20.0",
         "name": "rendering.mobile/horizontal_vertical_expansion"
     },
     {
-        "duration": "23.0",
+        "duration": "22.0",
         "name": "rendering.mobile/hw_accelerated_canvas_to_sw_canvas.html"
     },
     {
-        "duration": "8.0",
+        "duration": "6.0",
         "name": "rendering.mobile/idle_power_animated_gif"
     },
     {
-        "duration": "8.0",
+        "duration": "6.0",
         "name": "rendering.mobile/idle_power_blank"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/idle_power_css_animation"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/idle_power_request_animation_frame"
     },
     {
-        "duration": "12.0",
+        "duration": "11.0",
         "name": "rendering.mobile/idle_power_set_timeout_long"
     },
     {
-        "duration": "12.0",
+        "duration": "11.0",
         "name": "rendering.mobile/idle_power_set_timetout"
     },
     {
-        "duration": "10.0",
+        "duration": "14.0",
         "name": "rendering.mobile/ie_chalkboard"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/ie_pirate_mark"
     },
     {
-        "duration": "25.0",
+        "duration": "23.0",
         "name": "rendering.mobile/infinite_scroll_element_n_layers_0"
     },
     {
-        "duration": "26.0",
+        "duration": "24.0",
         "name": "rendering.mobile/infinite_scroll_element_n_layers_75"
     },
     {
-        "duration": "27.0",
+        "duration": "25.0",
         "name": "rendering.mobile/infinite_scroll_element_n_layers_99"
     },
     {
-        "duration": "25.0",
+        "duration": "23.0",
         "name": "rendering.mobile/infinite_scroll_root_fixed_n_layers_0"
     },
     {
-        "duration": "26.0",
+        "duration": "24.0",
         "name": "rendering.mobile/infinite_scroll_root_fixed_n_layers_75"
     },
     {
@@ -760,443 +764,443 @@
         "name": "rendering.mobile/infinite_scroll_root_fixed_n_layers_99"
     },
     {
-        "duration": "20.0",
+        "duration": "23.0",
         "name": "rendering.mobile/infinite_scroll_root_n_layers_0"
     },
     {
-        "duration": "20.0",
+        "duration": "24.0",
         "name": "rendering.mobile/infinite_scroll_root_n_layers_75"
     },
     {
-        "duration": "22.0",
+        "duration": "25.0",
         "name": "rendering.mobile/infinite_scroll_root_n_layers_99"
     },
     {
-        "duration": "17.0",
+        "duration": "24.0",
         "name": "rendering.mobile/infinite_scrolling"
     },
     {
-        "duration": "21.0",
+        "duration": "23.0",
         "name": "rendering.mobile/jarro_doverson"
     },
     {
-        "duration": "12.0",
+        "duration": "16.0",
         "name": "rendering.mobile/jpeg_decoding_rgb_and_gpu_rasterization"
     },
     {
-        "duration": "12.0",
+        "duration": "15.0",
         "name": "rendering.mobile/jpeg_decoding_yuv_and_gpu_rasterization"
     },
     {
-        "duration": "23.0",
+        "duration": "26.0",
         "name": "rendering.mobile/js_full_screen_invalidation"
     },
     {
-        "duration": "21.0",
+        "duration": "25.0",
         "name": "rendering.mobile/js_opacity_plus_n_layers_0"
     },
     {
-        "duration": "22.0",
+        "duration": "25.0",
         "name": "rendering.mobile/js_opacity_plus_n_layers_75"
     },
     {
-        "duration": "24.0",
+        "duration": "28.0",
         "name": "rendering.mobile/js_opacity_plus_n_layers_99"
     },
     {
-        "duration": "22.0",
+        "duration": "25.0",
         "name": "rendering.mobile/js_paint_plus_n_layers_0"
     },
     {
-        "duration": "22.0",
+        "duration": "25.0",
         "name": "rendering.mobile/js_paint_plus_n_layers_75"
     },
     {
-        "duration": "24.0",
+        "duration": "28.0",
         "name": "rendering.mobile/js_paint_plus_n_layers_99"
     },
     {
-        "duration": "23.0",
+        "duration": "26.0",
         "name": "rendering.mobile/js_poster_circle"
     },
     {
-        "duration": "21.0",
+        "duration": "24.0",
         "name": "rendering.mobile/js_scroll_text_only"
     },
     {
-        "duration": "20.0",
+        "duration": "23.0",
         "name": "rendering.mobile/kevs_3d"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/keyframed_animations"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/large_texture_uploads"
     },
     {
-        "duration": "28.0",
+        "duration": "32.0",
         "name": "rendering.mobile/latimes_pathological_2018"
     },
     {
-        "duration": "13.0",
+        "duration": "16.0",
         "name": "rendering.mobile/linkedin_2018"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/linkedin_mobile_2018"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/linkedin_mobile_pinch_2018"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/linkedin_pathological_2018"
     },
     {
-        "duration": "12.0",
+        "duration": "18.0",
         "name": "rendering.mobile/list_animation_simple"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/list_recycle_transform"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_0fps_impl_60fps"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_0fps_impl_60fps_no_update"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_0fps_impl_60fps_no_update_jank"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_0fps_with_jank_impl_0fps"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_15fps_impl_0fps"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/main_15fps_with_jank_impl_0fps"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_30fps_impl_0fps"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_30fps_impl_60fps"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_60fps_impl_0fps"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/main_60fps_impl_60fps"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/main_60fps_impl_60fps_no_update"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/main_60fps_impl_60fps_no_update_jank"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/main_60fps_with_extreme_jank_impl_0fps"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/main_60fps_with_jank_and_delay_impl_60fps"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/main_60fps_with_jank_impl_0fps"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/main_animations_half_presented"
     },
     {
-        "duration": "21.0",
+        "duration": "27.0",
         "name": "rendering.mobile/man_in_blue"
     },
     {
-        "duration": "23.0",
+        "duration": "27.0",
         "name": "rendering.mobile/many_images"
     },
     {
-        "duration": "22.0",
+        "duration": "25.0",
         "name": "rendering.mobile/many_planets_deep"
     },
     {
-        "duration": "24.0",
+        "duration": "27.0",
         "name": "rendering.mobile/maps_perf_test"
     },
     {
-        "duration": "13.0",
+        "duration": "20.0",
         "name": "rendering.mobile/mask_transition_animation"
     },
     {
-        "duration": "16.0",
+        "duration": "20.0",
         "name": "rendering.mobile/masonry"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/medium_texture_uploads"
     },
     {
-        "duration": "17.0",
+        "duration": "21.0",
         "name": "rendering.mobile/megi_dish"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/microgame_fps"
     },
     {
-        "duration": "17.0",
+        "duration": "20.0",
         "name": "rendering.mobile/microsoft_asteroid_belt"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/microsoft_fireflies"
     },
     {
-        "duration": "17.0",
+        "duration": "20.0",
         "name": "rendering.mobile/microsoft_fish_ie_tank"
     },
     {
-        "duration": "17.0",
+        "duration": "21.0",
         "name": "rendering.mobile/microsoft_performance"
     },
     {
-        "duration": "17.0",
+        "duration": "20.0",
         "name": "rendering.mobile/microsoft_snow"
     },
     {
-        "duration": "17.0",
+        "duration": "20.0",
         "name": "rendering.mobile/microsoft_speed_reading"
     },
     {
-        "duration": "17.0",
+        "duration": "20.0",
         "name": "rendering.mobile/microsoft_tweet_map"
     },
     {
-        "duration": "17.0",
+        "duration": "20.0",
         "name": "rendering.mobile/microsoft_video_city"
     },
     {
-        "duration": "17.0",
+        "duration": "20.0",
         "name": "rendering.mobile/microsoft_worker_fountains"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/mix_10k"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/mix_blend_mode_animation_difference"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/mix_blend_mode_animation_hue"
     },
     {
-        "duration": "18.0",
+        "duration": "22.0",
         "name": "rendering.mobile/mix_blend_mode_animation_propagating_isolation"
     },
     {
-        "duration": "18.0",
+        "duration": "21.0",
         "name": "rendering.mobile/mix_blend_mode_animation_screen"
     },
     {
-        "duration": "51.0",
+        "duration": "58.0",
         "name": "rendering.mobile/mlb_mobile_2018"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/mobile_news_sandbox"
     },
     {
-        "duration": "19.0",
+        "duration": "22.0",
         "name": "rendering.mobile/motion_mark_canvas_fill_shapes"
     },
     {
-        "duration": "19.0",
+        "duration": "22.0",
         "name": "rendering.mobile/motion_mark_canvas_stroke_shapes"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_anim_design_15"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_anim_focus_25"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_anim_images_50"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_anim_leaves_250"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_anim_multiply_175"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_anim_suits_125"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_composited_transforms_125"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_blend_circles_25"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_circles_250"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_clipped_rects_100"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_filter_circles_15"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_gradient_circles_250"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_svg_images_50"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_css_bouncing_tagged_images_225"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_dom_particles_svg_masks_25"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_focus_20_15"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_html_leaves_20_50"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_ramp_canvas_arcs"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_ramp_canvas_lines"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_ramp_design"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_ramp_images"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_ramp_leaves"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_ramp_multiply"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_ramp_paths"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_ramp_suits"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_svg_bouncing_circles_250"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_svg_bouncing_clipped_rects_100"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_svg_bouncing_gradient_circles_200"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_svg_bouncing_png_images_200"
     },
     {
-        "duration": "5.0",
+        "duration": "8.0",
         "name": "rendering.mobile/motionmark_svg_bouncing_svg_images_50"
     },
     {
-        "duration": "23.0",
+        "duration": "26.0",
         "name": "rendering.mobile/new_tilings"
     },
     {
-        "duration": "16.0",
+        "duration": "26.0",
         "name": "rendering.mobile/no_op_raf"
     },
     {
-        "duration": "15.0",
+        "duration": "21.0",
         "name": "rendering.mobile/no_op_scroll"
     },
     {
-        "duration": "14.0",
+        "duration": "21.0",
         "name": "rendering.mobile/no_op_settimeout"
     },
     {
-        "duration": "15.0",
+        "duration": "22.0",
         "name": "rendering.mobile/no_op_touch_handler"
     },
     {
-        "duration": "18.0",
+        "duration": "24.0",
         "name": "rendering.mobile/no_update_compositor_animation_with_janky_main_animation"
     },
     {
-        "duration": "30.0",
+        "duration": "37.0",
         "name": "rendering.mobile/non_opaque_background_compositor_thread_scrolling_00050_pixels_per_second"
     },
     {
-        "duration": "30.0",
+        "duration": "37.0",
         "name": "rendering.mobile/non_opaque_background_main_thread_scrolling_00050_pixels_per_second"
     },
     {
-        "duration": "20.0",
+        "duration": "29.0",
         "name": "rendering.mobile/nvidia_vertex_buffer_object"
     },
     {
-        "duration": "30.0",
+        "duration": "31.0",
         "name": "rendering.mobile/nyc_gov_scroll_2018"
     },
     {
-        "duration": "33.0",
+        "duration": "38.0",
         "name": "rendering.mobile/nytimes_mobile_2018"
     },
     {
@@ -1204,91 +1208,91 @@
         "name": "rendering.mobile/nytimes_scroll_2018"
     },
     {
-        "duration": "17.0",
+        "duration": "24.0",
         "name": "rendering.mobile/off_screen_main_60fps"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/off_screen_main_60fps_jank"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/offscreen_animation_no_damage"
     },
     {
-        "duration": "18.0",
+        "duration": "26.0",
         "name": "rendering.mobile/overlay_background_color_css_transitions_page"
     },
     {
-        "duration": "18.0",
+        "duration": "25.0",
         "name": "rendering.mobile/paint_worklet"
     },
     {
-        "duration": "13.0",
+        "duration": "20.0",
         "name": "rendering.mobile/parallax_effect"
     },
     {
-        "duration": "21.0",
+        "duration": "28.0",
         "name": "rendering.mobile/particles"
     },
     {
-        "duration": "23.0",
+        "duration": "31.0",
         "name": "rendering.mobile/pbs_pathological_2018"
     },
     {
-        "duration": "11.0",
+        "duration": "18.0",
         "name": "rendering.mobile/physical_simulation"
     },
     {
-        "duration": "19.0",
+        "duration": "26.0",
         "name": "rendering.mobile/pinterest_2018"
     },
     {
-        "duration": "14.0",
+        "duration": "24.0",
         "name": "rendering.mobile/pinterest_mobile_2018"
     },
     {
-        "duration": "21.0",
+        "duration": "27.0",
         "name": "rendering.mobile/put_and_create_imagebitmap_from_imagedata"
     },
     {
-        "duration": "19.0",
+        "duration": "26.0",
         "name": "rendering.mobile/put_get_image_data"
     },
     {
-        "duration": "19.0",
+        "duration": "25.0",
         "name": "rendering.mobile/put_image_data.html"
     },
     {
-        "duration": "15.0",
+        "duration": "22.0",
         "name": "rendering.mobile/raf"
     },
     {
-        "duration": "16.0",
+        "duration": "22.0",
         "name": "rendering.mobile/raf_animation"
     },
     {
-        "duration": "15.0",
+        "duration": "22.0",
         "name": "rendering.mobile/raf_canvas"
     },
     {
-        "duration": "15.0",
+        "duration": "22.0",
         "name": "rendering.mobile/raf_touch_animation"
     },
     {
-        "duration": "26.0",
+        "duration": "31.0",
         "name": "rendering.mobile/recode_pathological_2018"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/reddit_mobile_2018"
     },
     {
-        "duration": "19.0",
+        "duration": "26.0",
         "name": "rendering.mobile/runway_2019"
     },
     {
-        "duration": "22.0",
+        "duration": "28.0",
         "name": "rendering.mobile/san_angeles"
     },
     {
@@ -1296,7 +1300,7 @@
         "name": "rendering.mobile/second_batch_js_heavy"
     },
     {
-        "duration": "16.0",
+        "duration": "15.0",
         "name": "rendering.mobile/second_batch_js_light"
     },
     {
@@ -1304,11 +1308,11 @@
         "name": "rendering.mobile/second_batch_js_medium"
     },
     {
-        "duration": "43.0",
+        "duration": "49.0",
         "name": "rendering.mobile/sfgate_mobile_2018"
     },
     {
-        "duration": "25.0",
+        "duration": "24.0",
         "name": "rendering.mobile/sheets_render.html"
     },
     {
@@ -1320,55 +1324,55 @@
         "name": "rendering.mobile/simple_text_page"
     },
     {
-        "duration": "17.0",
+        "duration": "15.0",
         "name": "rendering.mobile/simple_touch_drag"
     },
     {
-        "duration": "64.0",
+        "duration": "62.0",
         "name": "rendering.mobile/skelebuddies_wasm_2020"
     },
     {
-        "duration": "33.0",
+        "duration": "31.0",
         "name": "rendering.mobile/slashdot_mobile_2018"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/small_texture_uploads"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "rendering.mobile/smash_cat"
     },
     {
-        "duration": "26.0",
+        "duration": "23.0",
         "name": "rendering.mobile/spielzeugz"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/static_canvas_to_hw_accelerated_canvas.html"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/static_webgl_to_hw_accelerated_canvas.html"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/sticky_using_webkit"
     },
     {
-        "duration": "26.0",
+        "duration": "23.0",
         "name": "rendering.mobile/stroke_shapes"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/svg_icon_raster"
     },
     {
-        "duration": "12.0",
+        "duration": "19.0",
         "name": "rendering.mobile/swipe_to_dismiss"
     },
     {
-        "duration": "21.0",
+        "duration": "18.0",
         "name": "rendering.mobile/sync_scroll_offset"
     },
     {
@@ -1384,15 +1388,15 @@
         "name": "rendering.mobile/text_05000_pixels_per_second"
     },
     {
-        "duration": "37.0",
+        "duration": "36.0",
         "name": "rendering.mobile/text_10000_pixels_per_second"
     },
     {
-        "duration": "34.0",
+        "duration": "33.0",
         "name": "rendering.mobile/text_20000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_40000_pixels_per_second"
     },
     {
@@ -1400,11 +1404,11 @@
         "name": "rendering.mobile/text_60000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_75000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_90000_pixels_per_second"
     },
     {
@@ -1412,7 +1416,7 @@
         "name": "rendering.mobile/text_constant_full_page_raster_05000_pixels_per_second"
     },
     {
-        "duration": "37.0",
+        "duration": "35.0",
         "name": "rendering.mobile/text_constant_full_page_raster_10000_pixels_per_second"
     },
     {
@@ -1420,11 +1424,11 @@
         "name": "rendering.mobile/text_constant_full_page_raster_20000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "34.0",
         "name": "rendering.mobile/text_constant_full_page_raster_40000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_constant_full_page_raster_60000_pixels_per_second"
     },
     {
@@ -1436,15 +1440,15 @@
         "name": "rendering.mobile/text_constant_full_page_raster_90000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "29.0",
         "name": "rendering.mobile/text_fling_05000_pixels_per_second"
     },
     {
-        "duration": "30.0",
+        "duration": "28.0",
         "name": "rendering.mobile/text_fling_10000_pixels_per_second"
     },
     {
-        "duration": "31.0",
+        "duration": "29.0",
         "name": "rendering.mobile/text_fling_20000_pixels_per_second"
     },
     {
@@ -1460,7 +1464,7 @@
         "name": "rendering.mobile/text_hover_20000_pixels_per_second"
     },
     {
-        "duration": "33.0",
+        "duration": "32.0",
         "name": "rendering.mobile/text_hover_40000_pixels_per_second"
     },
     {
@@ -1476,207 +1480,207 @@
         "name": "rendering.mobile/text_hover_90000_pixels_per_second"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/text_scrollbar_100_pixels_per_second"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/text_scrollbar_1200_pixels_per_second"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/text_scrollbar_200_pixels_per_second"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/text_scrollbar_2300_pixels_per_second"
     },
     {
-        "duration": "5.0",
+        "duration": "11.0",
         "name": "rendering.mobile/text_scrollbar_700_pixels_per_second"
     },
     {
-        "duration": "35.0",
+        "duration": "32.0",
         "name": "rendering.mobile/theverge_article_mobile_2018"
     },
     {
-        "duration": "36.0",
+        "duration": "32.0",
         "name": "rendering.mobile/theverge_mobile_2018"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "rendering.mobile/throughput_scrolling_active_handler"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "rendering.mobile/throughput_scrolling_composited"
     },
     {
-        "duration": "29.0",
+        "duration": "26.0",
         "name": "rendering.mobile/throughput_scrolling_passive_handler"
     },
     {
-        "duration": "30.0",
+        "duration": "27.0",
         "name": "rendering.mobile/throughput_scrolling_uncomposited"
     },
     {
-        "duration": "61.0",
+        "duration": "59.0",
         "name": "rendering.mobile/tiny_racing_v3_wasm_2020"
     },
     {
-        "duration": "25.0",
+        "duration": "23.0",
         "name": "rendering.mobile/toBlob_duration.html"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/toBlob_duration_jpeg.html"
     },
     {
-        "duration": "27.0",
+        "duration": "25.0",
         "name": "rendering.mobile/toBlob_small_canvas_in_worker.html"
     },
     {
-        "duration": "22.0",
+        "duration": "19.0",
         "name": "rendering.mobile/touch_handler_scrolling"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/transfer_from_imageBitmap.html"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/transform_transitions"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/transform_transitions_js_block"
     },
     {
-        "duration": "12.0",
+        "duration": "9.0",
         "name": "rendering.mobile/twitch_2018"
     },
     {
-        "duration": "12.0",
+        "duration": "9.0",
         "name": "rendering.mobile/twitch_mobile_pinch_2018"
     },
     {
-        "duration": "12.0",
+        "duration": "9.0",
         "name": "rendering.mobile/twitter_2018"
     },
     {
-        "duration": "24.0",
+        "duration": "21.0",
         "name": "rendering.mobile/twitter_mobile_2018"
     },
     {
-        "duration": "22.0",
+        "duration": "19.0",
         "name": "rendering.mobile/update_history_state"
     },
     {
-        "duration": "36.0",
+        "duration": "37.0",
         "name": "rendering.mobile/usatoday_mobile_2018"
     },
     {
-        "duration": "14.0",
+        "duration": "20.0",
         "name": "rendering.mobile/vertical_expansion"
     },
     {
-        "duration": "25.0",
+        "duration": "23.0",
         "name": "rendering.mobile/video_to_hw_accelerated_canvas"
     },
     {
-        "duration": "12.0",
+        "duration": "9.0",
         "name": "rendering.mobile/video_to_sub_texture"
     },
     {
-        "duration": "12.0",
+        "duration": "9.0",
         "name": "rendering.mobile/video_to_sub_texture_flip_and_premultiply"
     },
     {
-        "duration": "12.0",
+        "duration": "9.0",
         "name": "rendering.mobile/video_to_sub_texture_flip_y"
     },
     {
-        "duration": "12.0",
+        "duration": "9.0",
         "name": "rendering.mobile/video_to_sub_texture_premultiply"
     },
     {
-        "duration": "12.0",
+        "duration": "9.0",
         "name": "rendering.mobile/video_to_texture"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/web_animation_value_type_color"
     },
     {
-        "duration": "27.0",
+        "duration": "23.0",
         "name": "rendering.mobile/web_animation_value_type_length_3d"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/web_animation_value_type_length_complex"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/web_animation_value_type_length_simple"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/web_animation_value_type_path"
     },
     {
-        "duration": "25.0",
+        "duration": "22.0",
         "name": "rendering.mobile/web_animation_value_type_shadow"
     },
     {
-        "duration": "26.0",
+        "duration": "23.0",
         "name": "rendering.mobile/web_animation_value_type_transform_complex"
     },
     {
-        "duration": "26.0",
+        "duration": "23.0",
         "name": "rendering.mobile/web_animation_value_type_transform_simple"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "rendering.mobile/web_animations_many_keyframes"
     },
     {
-        "duration": "27.0",
+        "duration": "23.0",
         "name": "rendering.mobile/web_animations_set_current_time"
     },
     {
-        "duration": "24.0",
+        "duration": "23.0",
         "name": "rendering.mobile/web_animations_simultaneous"
     },
     {
-        "duration": "26.0",
+        "duration": "25.0",
         "name": "rendering.mobile/web_animations_staggered_chaining"
     },
     {
-        "duration": "26.0",
+        "duration": "23.0",
         "name": "rendering.mobile/web_animations_staggered_infinite_iterations"
     },
     {
-        "duration": "26.0",
+        "duration": "25.0",
         "name": "rendering.mobile/web_animations_staggered_triggering_page"
     },
     {
-        "duration": "24.0",
+        "duration": "23.0",
         "name": "rendering.mobile/webgl_to_texture"
     },
     {
-        "duration": "17.0",
+        "duration": "16.0",
         "name": "rendering.mobile/webp_decoding_rgb_and_gpu_rasterization"
     },
     {
-        "duration": "17.0",
+        "duration": "16.0",
         "name": "rendering.mobile/webp_decoding_yuv_and_gpu_rasterization"
     },
     {
-        "duration": "33.0",
+        "duration": "29.0",
         "name": "rendering.mobile/wikipedia_2018"
     },
     {
-        "duration": "33.0",
+        "duration": "28.0",
         "name": "rendering.mobile/wikipedia_delayed_scroll_start_2018"
     },
     {
@@ -1684,43 +1688,43 @@
         "name": "rendering.mobile/wikipedia_mobile_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "rendering.mobile/wordpress_2018"
     },
     {
-        "duration": "28.0",
+        "duration": "27.0",
         "name": "rendering.mobile/wordpress_mobile_2018"
     },
     {
-        "duration": "33.0",
+        "duration": "51.0",
         "name": "rendering.mobile/worldjournal_mobile_2018"
     },
     {
-        "duration": "39.0",
+        "duration": "41.0",
         "name": "rendering.mobile/wow_wiki_pathological_2018"
     },
     {
-        "duration": "59.0",
+        "duration": "65.0",
         "name": "rendering.mobile/wowwiki_mobile_2018"
     },
     {
-        "duration": "59.0",
+        "duration": "52.0",
         "name": "rendering.mobile/wsj_mobile_2018"
     },
     {
-        "duration": "32.0",
+        "duration": "31.0",
         "name": "rendering.mobile/yahoo_answers_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "rendering.mobile/yahoo_answers_mobile_2018"
     },
     {
-        "duration": "26.0",
+        "duration": "25.0",
         "name": "rendering.mobile/yahoo_news_2018"
     },
     {
-        "duration": "26.0",
+        "duration": "25.0",
         "name": "rendering.mobile/yahoo_news_mobile_2018"
     },
     {
@@ -1732,59 +1736,107 @@
         "name": "rendering.mobile/yahoo_sports_pathological_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "rendering.mobile/youtube_2018"
     },
     {
-        "duration": "10.0",
+        "duration": "9.0",
         "name": "rendering.mobile/youtube_mobile_2018"
     },
     {
-        "duration": "32.0",
+        "duration": "66.0",
         "name": "rendering.mobile/zdnet_pathological_2018"
     },
     {
-        "duration": "12.0",
+        "duration": "19.0",
         "name": "rendering.mobile/zoom_in_animation"
     },
     {
-        "duration": "2.0",
+        "duration": "257.0",
+        "name": "speedometer/http://browserbench.org/Speedometer/"
+    },
+    {
+        "duration": "453.0",
+        "name": "speedometer2/Speedometer2"
+    },
+    {
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:media:googleplaystore:2021"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:media:imgur"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/browse:media:pinterest:2018"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/browse:media:tumblr:2018"
+    },
+    {
+        "duration": "80.0",
+        "name": "system_health.memory_desktop/browse:media:youtube:2019"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/browse:media:youtubetv:2019"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/browse:media:youtubetv_watch:2020"
+    },
+    {
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:news:cnn:2021"
     },
     {
-        "duration": "59.0",
+        "duration": "61.0",
         "name": "system_health.memory_desktop/browse:news:flipboard:2020"
     },
     {
-        "duration": "64.0",
+        "duration": "60.0",
         "name": "system_health.memory_desktop/browse:news:hackernews:2020"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/browse:news:nytimes:2020"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/browse:news:reddit:2020"
+    },
+    {
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:search:google:2020"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:search:google_india:2021"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:social:facebook_infinite_scroll:2018"
     },
     {
-        "duration": "2.0",
+        "duration": "60.0",
+        "name": "system_health.memory_desktop/browse:social:tumblr_infinite_scroll:2018"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/browse:social:twitter:2018"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/browse:social:twitter_infinite_scroll:2018"
+    },
+    {
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:tech:discourse_infinite_scroll:2018"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:tools:autocad:2021"
     },
     {
@@ -1792,43 +1844,47 @@
         "name": "system_health.memory_desktop/browse:tools:docs_scrolling"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:tools:gmail-compose:2020"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:tools:gmail-labelclick:2020"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:tools:gmail-openconversation:2020"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:tools:gmail-search:2020"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:tools:maps:2019"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/browse:tools:photoshop:2021"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/browse:tools:photoshop_warm:2021"
+    },
+    {
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse:tools:sheets:2019"
     },
     {
-        "duration": "33.0",
-        "name": "system_health.memory_desktop/browse_accessibility:media:youtube"
-    },
-    {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/browse_accessibility:tech:codesearch:2018"
     },
     {
-        "duration": "13.0",
+        "duration": "12.0",
         "name": "system_health.memory_desktop/load:chrome:blank"
     },
     {
-        "duration": "19.0",
+        "duration": "18.0",
         "name": "system_health.memory_desktop/load:games:alphabetty:2018"
     },
     {
@@ -1836,35 +1892,139 @@
         "name": "system_health.memory_desktop/load:games:bubbles:2020"
     },
     {
-        "duration": "22.0",
+        "duration": "15.0",
+        "name": "system_health.memory_desktop/load:games:lazors"
+    },
+    {
+        "duration": "15.0",
+        "name": "system_health.memory_desktop/load:games:miniclip:2018"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/load:games:spychase:2018"
+    },
+    {
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:media:9gag"
     },
     {
-        "duration": "22.0",
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:media:dailymotion:2019"
     },
     {
-        "duration": "18.0",
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/load:media:facebook_feed:desktop:2020"
+    },
+    {
+        "duration": "15.0",
+        "name": "system_health.memory_desktop/load:media:facebook_photos:2018"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/load:media:facebook_photos:desktop:2020"
+    },
+    {
+        "duration": "23.0",
+        "name": "system_health.memory_desktop/load:media:flickr:2018"
+    },
+    {
+        "duration": "17.0",
+        "name": "system_health.memory_desktop/load:media:google_images:2018"
+    },
+    {
+        "duration": "30.0",
+        "name": "system_health.memory_desktop/load:media:imgur:2018"
+    },
+    {
+        "duration": "23.0",
+        "name": "system_health.memory_desktop/load:media:soundcloud:2018"
+    },
+    {
+        "duration": "27.0",
+        "name": "system_health.memory_desktop/load:media:youtube:2018"
+    },
+    {
+        "duration": "16.0",
+        "name": "system_health.memory_desktop/load:media:youtubelivingroom:2020"
+    },
+    {
+        "duration": "21.0",
         "name": "system_health.memory_desktop/load:news:bbc:2018"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
         "name": "system_health.memory_desktop/load:news:cnn:2020"
     },
     {
+        "duration": "22.0",
+        "name": "system_health.memory_desktop/load:news:flipboard"
+    },
+    {
+        "duration": "13.0",
+        "name": "system_health.memory_desktop/load:news:hackernews:2018"
+    },
+    {
+        "duration": "32.0",
+        "name": "system_health.memory_desktop/load:news:nytimes:2018"
+    },
+    {
+        "duration": "21.0",
+        "name": "system_health.memory_desktop/load:news:qq:2018"
+    },
+    {
+        "duration": "17.0",
+        "name": "system_health.memory_desktop/load:news:wikipedia:2018"
+    },
+    {
         "duration": "21.0",
         "name": "system_health.memory_desktop/load:search:amazon:2018"
     },
     {
-        "duration": "23.0",
+        "duration": "22.0",
         "name": "system_health.memory_desktop/load:search:baidu:2018"
     },
     {
-        "duration": "2.0",
+        "duration": "27.0",
+        "name": "system_health.memory_desktop/load:search:ebay:2018"
+    },
+    {
+        "duration": "27.0",
+        "name": "system_health.memory_desktop/load:search:flipkart:2018"
+    },
+    {
+        "duration": "16.0",
+        "name": "system_health.memory_desktop/load:search:google:2018"
+    },
+    {
+        "duration": "20.0",
+        "name": "system_health.memory_desktop/load:search:taobao:2018"
+    },
+    {
+        "duration": "15.0",
+        "name": "system_health.memory_desktop/load:search:yahoo:2018"
+    },
+    {
+        "duration": "16.0",
+        "name": "system_health.memory_desktop/load:search:yandex:2018"
+    },
+    {
+        "duration": "16.0",
+        "name": "system_health.memory_desktop/load:social:instagram:2018"
+    },
+    {
+        "duration": "13.0",
+        "name": "system_health.memory_desktop/load:social:pinterest:2019"
+    },
+    {
+        "duration": "22.0",
+        "name": "system_health.memory_desktop/load:social:vk:2018"
+    },
+    {
+        "duration": "1.0",
         "name": "system_health.memory_desktop/load:tools:chat:2020"
     },
     {
-        "duration": "37.0",
+        "duration": "39.0",
         "name": "system_health.memory_desktop/load:tools:docs:2019"
     },
     {
@@ -1872,18 +2032,50 @@
         "name": "system_health.memory_desktop/load:tools:drive:2019"
     },
     {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/load:tools:gmail:2019"
+    },
+    {
+        "duration": "21.0",
+        "name": "system_health.memory_desktop/load:tools:stackoverflow:2018"
+    },
+    {
+        "duration": "21.0",
+        "name": "system_health.memory_desktop/load:tools:weather:2019"
+    },
+    {
         "duration": "17.0",
         "name": "system_health.memory_desktop/load_accessibility:media:wikipedia:2018"
     },
     {
-        "duration": "32.0",
+        "duration": "33.0",
         "name": "system_health.memory_desktop/load_accessibility:shopping:amazon:2018"
     },
     {
-        "duration": "2.0",
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/long_running:tools:gmail-background"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/long_running:tools:gmail-foreground"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/multitab:misc:typical24"
+    },
+    {
+        "duration": "1.0",
+        "name": "system_health.memory_desktop/multitab:misc:typical24:2018"
+    },
+    {
+        "duration": "1.0",
         "name": "system_health.memory_desktop/play:media:google_play_music"
     },
     {
+        "duration": "47.0",
+        "name": "system_health.memory_desktop/play:media:soundcloud:2018"
+    },
+    {
         "duration": "900.0",
         "name": "base_perftests/_gtest_"
     }
diff --git a/tools/perf/core/shard_maps/timing_data/fuchsia-perf-shk_timing.json b/tools/perf/core/shard_maps/timing_data/fuchsia-perf-shk_timing.json
new file mode 100644
index 0000000..4ecf637
--- /dev/null
+++ b/tools/perf/core/shard_maps/timing_data/fuchsia-perf-shk_timing.json
@@ -0,0 +1,6 @@
+[
+    {
+        "duration": "900.0",
+        "name": "base_perftests/_gtest_"
+    }
+]
\ No newline at end of file
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc
index 870e686..a424230 100644
--- a/ui/accessibility/ax_node.cc
+++ b/ui/accessibility/ax_node.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "base/no_destructor.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -993,6 +994,110 @@
   return GetComputedNodeData().GetOrComputeTextContentLengthUTF16();
 }
 
+gfx::RectF AXNode::GetTextContentRangeBoundsUTF8(int start_offset,
+                                                 int end_offset) const {
+  DCHECK(!tree_->GetTreeUpdateInProgressState());
+  DCHECK_LE(start_offset, end_offset)
+      << "Invalid `start_offset` and `end_offset`.\n"
+      << start_offset << ' ' << end_offset << "\nin\n"
+      << *this;
+  // Since we DCHECK that `start_offset` <= `end_offset`, there is no need to
+  // check whether `start_offset` is also in range.
+  if (end_offset > GetTextContentLengthUTF8())
+    return gfx::RectF();
+
+  // TODO(nektar): Update this to use
+  // "base/strings/utf_offset_string_conversions.h" which provides caching of
+  // offsets.
+  std::u16string out_trancated_string_utf16;
+  if (!base::UTF8ToUTF16(GetTextContentUTF8().data(),
+                         base::checked_cast<size_t>(start_offset),
+                         &out_trancated_string_utf16)) {
+    return gfx::RectF();
+  }
+  start_offset = base::checked_cast<int>(out_trancated_string_utf16.length());
+  if (!base::UTF8ToUTF16(GetTextContentUTF8().data(),
+                         base::checked_cast<size_t>(end_offset),
+                         &out_trancated_string_utf16)) {
+    return gfx::RectF();
+  }
+  end_offset = base::checked_cast<int>(out_trancated_string_utf16.length());
+  return GetTextContentRangeBoundsUTF16(start_offset, end_offset);
+}
+
+gfx::RectF AXNode::GetTextContentRangeBoundsUTF16(int start_offset,
+                                                  int end_offset) const {
+  DCHECK(!tree_->GetTreeUpdateInProgressState());
+  DCHECK_LE(start_offset, end_offset)
+      << "Invalid `start_offset` and `end_offset`.\n"
+      << start_offset << ' ' << end_offset << "\nin\n"
+      << *this;
+  // Since we DCHECK that `start_offset` <= `end_offset`, there is no need to
+  // check whether `start_offset` is also in range.
+  if (end_offset > GetTextContentLengthUTF16())
+    return gfx::RectF();
+
+  const std::vector<int32_t>& character_offsets =
+      GetIntListAttribute(ax::mojom::IntListAttribute::kCharacterOffsets);
+  int character_offsets_length =
+      base::checked_cast<int>(character_offsets.size());
+  // Charactger offsets are always based on the UTF-16 representation of the
+  // text.
+  if (character_offsets_length < GetTextContentLengthUTF16()) {
+    // Blink might not return pixel offsets for all characters. Clamp the
+    // character range to be within the number of provided pixels. Note that the
+    // first character always starts at pixel 0, so an offset for that character
+    // is not provided.
+    //
+    // TODO(accessibility): We need to fix this bug in Blink.
+    start_offset = std::min(start_offset, character_offsets_length);
+    end_offset = std::min(end_offset, character_offsets_length);
+  }
+
+  // TODO(nektar): Remove all this code and fix up the character offsets vector
+  // itself.
+  int start_pixel_offset =
+      start_offset > 0
+          ? character_offsets[base::checked_cast<size_t>(start_offset - 1)]
+          : 0;
+  int end_pixel_offset =
+      end_offset > 0
+          ? character_offsets[base::checked_cast<size_t>(end_offset - 1)]
+          : 0;
+  int max_pixel_offset = character_offsets_length > 0
+                             ? character_offsets[character_offsets_length - 1]
+                             : 0;
+  const gfx::RectF& node_bounds = data().relative_bounds.bounds;
+
+  gfx::RectF out_bounds;
+  switch (static_cast<ax::mojom::WritingDirection>(
+      GetIntAttribute(ax::mojom::IntAttribute::kTextDirection))) {
+    case ax::mojom::WritingDirection::kNone:
+    case ax::mojom::WritingDirection::kLtr:
+      out_bounds = gfx::RectF(start_pixel_offset, 0,
+                              end_pixel_offset - start_pixel_offset,
+                              node_bounds.height());
+      break;
+    case ax::mojom::WritingDirection::kRtl: {
+      int left = max_pixel_offset - end_pixel_offset;
+      int right = max_pixel_offset - start_pixel_offset;
+      out_bounds = gfx::RectF(left, 0, right - left, node_bounds.height());
+      break;
+    }
+    case ax::mojom::WritingDirection::kTtb:
+      out_bounds = gfx::RectF(0, start_pixel_offset, node_bounds.width(),
+                              end_pixel_offset - start_pixel_offset);
+      break;
+    case ax::mojom::WritingDirection::kBtt: {
+      int top = max_pixel_offset - end_pixel_offset;
+      int bottom = max_pixel_offset - start_pixel_offset;
+      out_bounds = gfx::RectF(0, top, node_bounds.width(), bottom - top);
+      break;
+    }
+  }
+  return out_bounds;
+}
+
 std::string AXNode::GetLanguage() const {
   DCHECK(!tree_->GetTreeUpdateInProgressState());
   // Walk up tree considering both detected and author declared languages.
diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h
index f922cd5..a40f016 100644
--- a/ui/accessibility/ax_node.h
+++ b/ui/accessibility/ax_node.h
@@ -24,6 +24,7 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/ax_text_attributes.h"
 #include "ui/accessibility/ax_tree_id.h"
+#include "ui/gfx/geometry/rect_f.h"
 
 namespace ui {
 
@@ -515,6 +516,18 @@
   int GetTextContentLengthUTF8() const;
   int GetTextContentLengthUTF16() const;
 
+  // Returns the smallest bounding box that can enclose the given range of
+  // characters in the node's text contents. The bounding box is relative to
+  // this node's coordinate system as specified in
+  // `AXNodeData::relative_bounds`.
+  //
+  // Note that `start_offset` and `end_offset` are either in UTF8 or UTF16 code
+  // units, not in grapheme clusters.
+  gfx::RectF GetTextContentRangeBoundsUTF8(int start_offset,
+                                           int end_offset) const;
+  gfx::RectF GetTextContentRangeBoundsUTF16(int start_offset,
+                                            int end_offset) const;
+
   // Returns a string representing the language code.
   //
   // This will consider the language declared in the DOM, and may eventually
diff --git a/ui/accessibility/ax_node_unittest.cc b/ui/accessibility/ax_node_unittest.cc
index 94a24f18..7355369 100644
--- a/ui/accessibility/ax_node_unittest.cc
+++ b/ui/accessibility/ax_node_unittest.cc
@@ -11,6 +11,7 @@
 
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/accessibility/ax_enums.mojom-shared.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/ax_position.h"
@@ -18,6 +19,7 @@
 #include "ui/accessibility/ax_tree_data.h"
 #include "ui/accessibility/ax_tree_id.h"
 #include "ui/accessibility/test_ax_tree_manager.h"
+#include "ui/gfx/geometry/rect_f.h"
 
 namespace ui {
 
@@ -631,6 +633,112 @@
   EXPECT_EQ(text_field_node, inline_box_2_node->GetLowestPlatformAncestor());
 }
 
+TEST(AXNodeTest, GetTextContentRangeBounds) {
+  constexpr char16_t kEnglishText[] = u"Hey";
+  const std::vector<int32_t> kEnglishCharacterOffsets = {12, 19, 27};
+  // A Hindi word (which means "Hindi") consisting of two letters.
+  constexpr char16_t kHindiText[] = u"\x0939\x093F\x0928\x094D\x0926\x0940";
+  const std::vector<int32_t> kHindiCharacterOffsets = {40, 40, 59, 59, 59, 59};
+  // A Thai word (which means "feel") consisting of 3 letters.
+  constexpr char16_t kThaiText[] = u"\x0E23\x0E39\x0E49\x0E2A\x0E36\x0E01";
+  const std::vector<int32_t> kThaiCharacterOffsets = {66, 66, 66, 76, 76, 85};
+
+  AXNodeData root_data;
+  root_data.id = 1;
+  root_data.role = ax::mojom::Role::kRootWebArea;
+
+  AXNodeData text_data1;
+  text_data1.id = 2;
+  text_data1.role = ax::mojom::Role::kStaticText;
+  text_data1.SetName(kEnglishText);
+  text_data1.AddIntAttribute(
+      ax::mojom::IntAttribute::kTextDirection,
+      static_cast<int32_t>(ax::mojom::WritingDirection::kLtr));
+  text_data1.AddIntListAttribute(ax::mojom::IntListAttribute::kCharacterOffsets,
+                                 kEnglishCharacterOffsets);
+
+  AXNodeData text_data2;
+  text_data2.id = 3;
+  text_data2.role = ax::mojom::Role::kStaticText;
+  text_data2.SetName(kHindiText);
+  text_data2.AddIntAttribute(
+      ax::mojom::IntAttribute::kTextDirection,
+      static_cast<int32_t>(ax::mojom::WritingDirection::kRtl));
+  text_data2.AddIntListAttribute(ax::mojom::IntListAttribute::kCharacterOffsets,
+                                 kHindiCharacterOffsets);
+
+  AXNodeData text_data3;
+  text_data3.id = 4;
+  text_data3.role = ax::mojom::Role::kStaticText;
+  text_data3.SetName(kThaiText);
+  text_data3.AddIntAttribute(
+      ax::mojom::IntAttribute::kTextDirection,
+      static_cast<int32_t>(ax::mojom::WritingDirection::kTtb));
+  text_data3.AddIntListAttribute(ax::mojom::IntListAttribute::kCharacterOffsets,
+                                 kThaiCharacterOffsets);
+
+  root_data.child_ids = {text_data1.id, text_data2.id, text_data3.id};
+
+  AXTreeUpdate update;
+  update.root_id = root_data.id;
+  update.nodes = {root_data, text_data1, text_data2, text_data3};
+  update.has_tree_data = true;
+
+  AXTreeData tree_data;
+  tree_data.tree_id = AXTreeID::CreateNewAXTreeID();
+  tree_data.title = "Application";
+  update.tree_data = tree_data;
+
+  AXTree tree;
+  ASSERT_TRUE(tree.Unserialize(update)) << tree.error();
+
+  const AXNode* root_node = tree.root();
+  ASSERT_EQ(root_data.id, root_node->id());
+
+  const AXNode* text1_node = root_node->GetUnignoredChildAtIndex(0);
+  ASSERT_EQ(text_data1.id, text1_node->id());
+  const AXNode* text2_node = root_node->GetUnignoredChildAtIndex(1);
+  ASSERT_EQ(text_data2.id, text2_node->id());
+  const AXNode* text3_node = root_node->GetUnignoredChildAtIndex(2);
+  ASSERT_EQ(text_data3.id, text3_node->id());
+
+  // Bounds should be the same between UTF-8 and UTF-16 for `kEnglishText`.
+  EXPECT_EQ(gfx::RectF(0, 0, 27, 0),
+            text1_node->GetTextContentRangeBoundsUTF8(0, 3));
+  EXPECT_EQ(gfx::RectF(12, 0, 7, 0),
+            text1_node->GetTextContentRangeBoundsUTF8(1, 2));
+  EXPECT_EQ(gfx::RectF(), text1_node->GetTextContentRangeBoundsUTF8(2, 4));
+  EXPECT_EQ(gfx::RectF(0, 0, 27, 0),
+            text1_node->GetTextContentRangeBoundsUTF16(0, 3));
+  EXPECT_EQ(gfx::RectF(12, 0, 7, 0),
+            text1_node->GetTextContentRangeBoundsUTF16(1, 2));
+  EXPECT_EQ(gfx::RectF(), text1_node->GetTextContentRangeBoundsUTF16(2, 4));
+
+  // Offsets are manually converted between UTF-8 and UTF-16.
+  //
+  // `kHindiText` is 6 code units in UTF-16 and 18 in UTF-8.
+  EXPECT_EQ(gfx::RectF(0, 0, 59, 0),
+            text2_node->GetTextContentRangeBoundsUTF8(0, 18));
+  EXPECT_EQ(gfx::RectF(0, 0, 19, 0),
+            text2_node->GetTextContentRangeBoundsUTF8(6, 12));
+  EXPECT_EQ(gfx::RectF(0, 0, 59, 0),
+            text2_node->GetTextContentRangeBoundsUTF16(0, 6));
+  EXPECT_EQ(gfx::RectF(0, 0, 19, 0),
+            text2_node->GetTextContentRangeBoundsUTF16(2, 4));
+
+  // Offsets are manually converted between UTF-8 and UTF-16.
+  //
+  // `kThaiText` is 6 code units in UTF-16 and 18 in UTF-8.
+  EXPECT_EQ(gfx::RectF(0, 0, 0, 85),
+            text3_node->GetTextContentRangeBoundsUTF8(0, 18));
+  EXPECT_EQ(gfx::RectF(0, 66, 0, 10),
+            text3_node->GetTextContentRangeBoundsUTF8(6, 12));
+  EXPECT_EQ(gfx::RectF(0, 0, 0, 85),
+            text3_node->GetTextContentRangeBoundsUTF16(0, 6));
+  EXPECT_EQ(gfx::RectF(0, 66, 0, 10),
+            text3_node->GetTextContentRangeBoundsUTF16(2, 4));
+}
+
 TEST(AXNodeTest, IsGridCellReadOnlyOrDisabled) {
   // ++kRootWebArea
   // ++++kGrid
diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc
index 3beaa67..c29465e 100644
--- a/ui/base/ime/input_method_base.cc
+++ b/ui/base/ime/input_method_base.cc
@@ -48,20 +48,6 @@
 
 void InputMethodBase::OnTouch(ui::EventPointerType pointerType) {}
 
-#if BUILDFLAG(IS_WIN)
-bool InputMethodBase::OnUntranslatedIMEMessage(
-    const CHROME_MSG event,
-    InputMethod::NativeEventResult* result) {
-  return false;
-}
-
-void InputMethodBase::OnInputLocaleChanged() {}
-
-bool InputMethodBase::IsInputLocaleCJK() const {
-  return false;
-}
-#endif
-
 void InputMethodBase::SetFocusedTextInputClient(TextInputClient* client) {
   SetFocusedTextInputClientInternal(client);
 }
diff --git a/ui/base/ime/input_method_base.h b/ui/base/ime/input_method_base.h
index 040c4eb8..394ee52 100644
--- a/ui/base/ime/input_method_base.h
+++ b/ui/base/ime/input_method_base.h
@@ -46,13 +46,6 @@
   void OnTouch(ui::EventPointerType pointerType) override;
   void OnBlur() override;
 
-#if BUILDFLAG(IS_WIN)
-  bool OnUntranslatedIMEMessage(const CHROME_MSG event,
-                                NativeEventResult* result) override;
-  void OnInputLocaleChanged() override;
-  bool IsInputLocaleCJK() const override;
-#endif
-
   void SetFocusedTextInputClient(TextInputClient* client) override;
   void DetachTextInputClient(TextInputClient* client) override;
   TextInputClient* GetTextInputClient() const override;
diff --git a/ui/base/ime/input_method_base_unittest.cc b/ui/base/ime/input_method_base_unittest.cc
index f1f368b..0ffe6670 100644
--- a/ui/base/ime/input_method_base_unittest.cc
+++ b/ui/base/ime/input_method_base_unittest.cc
@@ -135,6 +135,16 @@
   void CancelComposition(const TextInputClient* client) override {}
   bool IsCandidatePopupOpen() const override { return false; }
 
+#if BUILDFLAG(IS_WIN)
+  bool OnUntranslatedIMEMessage(
+      const CHROME_MSG event,
+      InputMethod::NativeEventResult* result) override {
+    return false;
+  }
+  void OnInputLocaleChanged() override {}
+  bool IsInputLocaleCJK() const override { return false; }
+#endif
+
   // InputMethodBase:
   void OnWillChangeFocusedClient(TextInputClient* focused_before,
                                  TextInputClient* focused) override {
diff --git a/ui/base/ime/win/input_method_win_tsf.cc b/ui/base/ime/win/input_method_win_tsf.cc
index 9e9682a9..ebe2ee1 100644
--- a/ui/base/ime/win/input_method_win_tsf.cc
+++ b/ui/base/ime/win/input_method_win_tsf.cc
@@ -129,6 +129,8 @@
   ui::TSFBridge::GetInstance()->RemoveFocusedClient(client);
 }
 
+void InputMethodWinTSF::OnInputLocaleChanged() {}
+
 bool InputMethodWinTSF::IsInputLocaleCJK() const {
   if (!ui::TSFBridge::GetInstance()) {
     return false;
diff --git a/ui/base/ime/win/input_method_win_tsf.h b/ui/base/ime/win/input_method_win_tsf.h
index 5fa810a..e6ded2e 100644
--- a/ui/base/ime/win/input_method_win_tsf.h
+++ b/ui/base/ime/win/input_method_win_tsf.h
@@ -35,6 +35,7 @@
   void OnCaretBoundsChanged(const TextInputClient* client) override;
   void CancelComposition(const TextInputClient* client) override;
   void DetachTextInputClient(TextInputClient* client) override;
+  void OnInputLocaleChanged() override;
   bool IsInputLocaleCJK() const override;
   bool IsCandidatePopupOpen() const override;
 
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index f943df1..c78333f7 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -117,19 +117,19 @@
     Older
   </message>
   <message name="IDS_FILE_BROWSER_RECENT_EMPTY_FOLDER" desc="Empty state message for all filter in Recent view.">
-    Your recent files will appear here
+    No recent files
   </message>
   <message name="IDS_FILE_BROWSER_RECENT_EMPTY_IMAGES_FOLDER" desc="Empty state message for image filter in Recent view.">
-    Your recent images will appear here
+    No recent images
   </message>
   <message name="IDS_FILE_BROWSER_RECENT_EMPTY_AUDIO_FOLDER" desc="Empty state message for audio filter in Recent view.">
-    Your recent audio files will appear here
+    No recent audio files
   </message>
   <message name="IDS_FILE_BROWSER_RECENT_EMPTY_VIDEOS_FOLDER" desc="Empty state message for video filter in Recent view.">
-    Your recent videos will appear here
+    No recent videos
   </message>
   <message name="IDS_FILE_BROWSER_RECENT_EMPTY_DOCUMENTS_FOLDER" desc="Empty state message for document filter in Recent view.">
-    Your recent documents will appear here
+    No recent documents
   </message>
   <message name="IDS_FILE_BROWSER_PLUGIN_VM_DIRECTORY_LABEL" desc="Parallels local directory label.">
     Windows files
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_AUDIO_FOLDER.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_AUDIO_FOLDER.png.sha1
index 5243b6c3e..070683e 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_AUDIO_FOLDER.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_AUDIO_FOLDER.png.sha1
@@ -1 +1 @@
-c51a1a8ed6053c6ed29b92402234c4993327d11f
\ No newline at end of file
+dae69b3790d9840fab9d91873e4077bbe06d987e
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_DOCUMENTS_FOLDER.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_DOCUMENTS_FOLDER.png.sha1
index 251fc60..4e946065 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_DOCUMENTS_FOLDER.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_DOCUMENTS_FOLDER.png.sha1
@@ -1 +1 @@
-da418eb5ac877f69520978cba5bea8740bdb8d02
\ No newline at end of file
+61fc7c9c2b0e29b7ee7a2fb3e697e0d6c5e2e677
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_FOLDER.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_FOLDER.png.sha1
index 8f91c129..c74d8aa1 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_FOLDER.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_FOLDER.png.sha1
@@ -1 +1 @@
-e9e29e2c755096e6a43122a4748d84c4dcf1f2ce
\ No newline at end of file
+9ee7b404d756568425aace7c9262a8d0b9bca2ef
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_IMAGES_FOLDER.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_IMAGES_FOLDER.png.sha1
index 3e4944e7..e0cfa62 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_IMAGES_FOLDER.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_IMAGES_FOLDER.png.sha1
@@ -1 +1 @@
-41daf9034c32b65d8ead0eb65903df20211fb634
\ No newline at end of file
+e79a4fc353a6296f2d6ad66e6f98881e7882819c
\ No newline at end of file
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_VIDEOS_FOLDER.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_VIDEOS_FOLDER.png.sha1
index bdfb3bf..b58c3df 100644
--- a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_VIDEOS_FOLDER.png.sha1
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_RECENT_EMPTY_VIDEOS_FOLDER.png.sha1
@@ -1 +1 @@
-6a508b2d3ae4a15c673081a83f063a93a75cd33a
\ No newline at end of file
+305a0437fe59b0a3dee29050c9b0d06b70743537
\ No newline at end of file
diff --git a/ui/chromeos/styles/cros_colors.json5 b/ui/chromeos/styles/cros_colors.json5
index 82a2d271..620c99d2 100644
--- a/ui/chromeos/styles/cros_colors.json5
+++ b/ui/chromeos/styles/cros_colors.json5
@@ -341,7 +341,7 @@
     },
     /* button-icon */
     button_icon_color_primary: {
-      light: "$google_grey_200",
+      light: "$white",
       dark: "$google_grey_900",
     },
     button_icon_color_primary_disabled: {
@@ -397,6 +397,11 @@
     /* slider */
     slider_color_active: "$color_prominent",
     slider_color_inactive: "$color_secondary",
+    slider_label_background_color: "$color_prominent",
+    slider_label_text_color: {
+      light: "$white",
+      dark: "$google_grey_900",
+    },
     slider_track_color_active: "rgba($slider_color_active.rgb, $second_tone_opacity)",
     slider_track_color_inactive: "rgba($slider_color_inactive.rgb, $second_tone_opacity)",
 
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn
index ce9f354c..618573e 100644
--- a/ui/file_manager/BUILD.gn
+++ b/ui/file_manager/BUILD.gn
@@ -246,21 +246,11 @@
   deps = [
     ":build_ts",
     "file_manager:build_static_grdp",
-    "//ui/file_manager/file_manager:fix_broken_images",
     "//ui/file_manager/image_loader:build",
   ]
 
   input_files_base_dir = rebase_path(target_gen_dir, root_build_dir)
-  input_files = [
-    # Fix broken images:
-    "file_manager/images/files/ui/arrow_right.svg",
-    "file_manager/images/files/ui/state_banner_icon.svg",
-    "file_manager/images/files/ui/warning_banner_icon.svg",
-    "file_manager/images/files/ui/error_banner_icon.svg",
-    "file_manager/images/files/ui/menu_ng.svg",
-
-    "image_loader/background.rollup.js",
-  ]
+  input_files = [ "image_loader/background.rollup.js" ]
 
   resource_path_rewrites =
       [ "image_loader/background.rollup.js|image_loader/background.js" ]
diff --git a/ui/file_manager/file_manager/BUILD.gn b/ui/file_manager/file_manager/BUILD.gn
index c489a16..cca9a804 100644
--- a/ui/file_manager/file_manager/BUILD.gn
+++ b/ui/file_manager/file_manager/BUILD.gn
@@ -4,18 +4,6 @@
 
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-# TODO: Remove this file copy when breadcrumb.js supports only JS modules.
-copy("fix_broken_images") {
-  sources = [
-    "foreground/images/files/ui/arrow_right.svg",
-    "foreground/images/files/ui/error_banner_icon.svg",
-    "foreground/images/files/ui/menu_ng.svg",
-    "foreground/images/files/ui/state_banner_icon.svg",
-    "foreground/images/files/ui/warning_banner_icon.svg",
-  ]
-  outputs = [ "$target_gen_dir/images/files/ui/{{source_file_part}}" ]
-}
-
 generated_static_grdp = "$target_gen_dir/static_resources.grdp"
 
 generate_grd("build_static_grdp") {
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_impl.js b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
index d27c9e1..8f8ab6f7 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_impl.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
@@ -418,10 +418,15 @@
     const volumeInfo = this.getVolumeInfo(entry);
 
     if (util.isFakeEntry(entry)) {
-      const isReadOnly =
-          entry.rootType === VolumeManagerCommon.RootType.RECENT ?
-          !util.isRecentsFilterV2Enabled() :
-          true;
+      // Aggregated views like RECENTS and TRASH exist as fake entries but may
+      // actually defer their logic to some underlying implementation or
+      // delegate to the location filesystem.
+      let isReadOnly = true;
+      if ((entry.rootType === VolumeManagerCommon.RootType.RECENT &&
+           util.isRecentsFilterV2Enabled()) ||
+          entry.rootType === VolumeManagerCommon.RootType.TRASH) {
+        isReadOnly = false;
+      }
       return new EntryLocationImpl(
           volumeInfo, assert(entry.rootType),
           true /* The entry points a root directory. */, isReadOnly);
diff --git a/ui/file_manager/file_manager/common/js/trash.js b/ui/file_manager/file_manager/common/js/trash.js
index a34ca00..6081806 100644
--- a/ui/file_manager/file_manager/common/js/trash.js
+++ b/ui/file_manager/file_manager/common/js/trash.js
@@ -88,6 +88,25 @@
 ];
 
 /**
+ * Returns a list of strings that represent volumes that are enabled for Trash.
+ * Used to validate drag drop data without resolving the URLs to Entry's.
+ * @param {!VolumeManager} volumeManager
+ * @returns {!Array<!string>}
+ */
+export function getEnabledTrashVolumeURLs(volumeManager) {
+  const urls = [];
+  for (let i = 0; i < volumeManager.volumeInfoList.length; i++) {
+    const volumeInfo = volumeManager.volumeInfoList.item(i);
+    for (const config of TrashConfig.CONFIG) {
+      if (volumeInfo.volumeType === config.volumeType) {
+        urls.push(volumeInfo.fileSystem.root.toURL());
+      }
+    }
+  }
+  return urls;
+}
+
+/**
  * Wrapper for /.Trash/files and /.Trash/info directories.
  */
 export class TrashDirs {
diff --git a/ui/file_manager/file_manager/containers/breadcrumb_container.ts b/ui/file_manager/file_manager/containers/breadcrumb_container.ts
index 915eb922..daea36c2 100644
--- a/ui/file_manager/file_manager/containers/breadcrumb_container.ts
+++ b/ui/file_manager/file_manager/containers/breadcrumb_container.ts
@@ -43,7 +43,7 @@
     // be listed as search results regardless of current location.
     // In this case, showing current location is confusing, so use the Drive
     // root "My Drive" as the current location.
-    if (search && search.term && search.status === PropStatus.SUCCESS) {
+    if (search && search.query && search.status === PropStatus.SUCCESS) {
       const entry = state.allEntries[currentDirectory.key];
       if (entry && entry.volumeType === VolumeManagerCommon.VolumeType.DRIVE) {
         const root = currentDirectory.pathComponents[0];
diff --git a/ui/file_manager/file_manager/externs/ts/state.js b/ui/file_manager/file_manager/externs/ts/state.js
index 9910b63e..308d1b4 100644
--- a/ui/file_manager/file_manager/externs/ts/state.js
+++ b/ui/file_manager/file_manager/externs/ts/state.js
@@ -52,7 +52,7 @@
  * Data for search. It should be empty `{}` when the user isn't searching.
  * @typedef {{
  *   status: (PropStatus|undefined),
- *   term: (string|undefined),
+ *   query: (string|undefined),
  * }}
  */
 export let SearchData;
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index b9d7659..9e515fe 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -805,6 +805,7 @@
     "//ui/file_manager/file_manager/common/js:api",
     "//ui/file_manager/file_manager/common/js:file_type",
     "//ui/file_manager/file_manager/common/js:progress_center_common",
+    "//ui/file_manager/file_manager/common/js:trash",
     "//ui/file_manager/file_manager/common/js:util",
     "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/file_manager/file_manager/externs:entry_location",
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index 960725d..6f24006c 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -67,8 +67,6 @@
 
     /** @private {?function(Event): void} */
     this.onSearchCompleted_ = null;
-    /** @private {?Function} */
-    this.onClearSearch_ = null;
 
     /**
      * @private {boolean}
@@ -1238,11 +1236,9 @@
       event.newDirEntry = dirEntry;
       event.volumeChanged = previousVolumeInfo !== currentVolumeInfo;
       this.dispatchEvent(event);
-      if (util.isFilesAppExperimental()) {
-        // Notify the Store that the new directory has successfully changed.
-        this.store_.dispatch(
-            changeDirectory({to: dirEntry, status: PropStatus.SUCCESS}));
-      }
+      // Notify the Store that the new directory has successfully changed.
+      this.store_.dispatch(
+          changeDirectory({to: dirEntry, status: PropStatus.SUCCESS}));
     });
   }
 
@@ -1641,11 +1637,8 @@
    * @param {string} query Query that will be searched for.
    * @param {function(Event)} onSearchRescan Function that will be called when
    *     the search directory is rescanned (i.e. search results are displayed).
-   * @param {function()} onClearSearch Function to be called when search state
-   *     gets cleared.
-   * TODO(olege): Change callbacks to events.
    */
-  search(query, onSearchRescan, onClearSearch) {
+  search(query, onSearchRescan) {
     this.lastSearchQuery_ = query;
     this.clearSearch_();
     const currentDirEntry = this.getCurrentDirEntry();
@@ -1685,9 +1678,8 @@
 
         // Notify the store-aware parts.
         this.store_.dispatch(
-            searchAction({term: query, status: PropStatus.SUCCESS}));
+            searchAction({query: query, status: PropStatus.SUCCESS}));
       };
-      this.onClearSearch_ = onClearSearch;
       this.addEventListener('scan-completed', this.onSearchCompleted_);
       this.clearAndScan_(newDirContents, callback);
     });
@@ -1708,11 +1700,6 @@
       this.onSearchCompleted_ = null;
     }
 
-    if (this.onClearSearch_) {
-      this.onClearSearch_();
-      this.onClearSearch_ = null;
-    }
-
     this.store_.dispatch(searchAction({}));
   }
 
@@ -1731,6 +1718,7 @@
       chrome.fileManagerPrivate.IOTaskType.EMPTY_TRASH,
       chrome.fileManagerPrivate.IOTaskType.MOVE,
       chrome.fileManagerPrivate.IOTaskType.RESTORE,
+      chrome.fileManagerPrivate.IOTaskType.TRASH,
     ]);
     /** @type {!Set<?VolumeManagerCommon.RootType>} */
     const rootTypesRequireRefresh = new Set([
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 1d51166..46384fb 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -944,10 +944,8 @@
     await this.initSettingsPromise_;
     const fileSystemUIPromise = this.initFileSystemUI_();
     // Initialize the Store for the whole app.
-    if (util.isFilesAppExperimental()) {
-      const store = getStore();
-      store.init({});
-    }
+    const store = getStore();
+    store.init({});
     this.initUIFocus_();
     metrics.recordInterval('Load.InitUI');
     return fileSystemUIPromise;
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
index 452e58d..6fef096c 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -6,9 +6,10 @@
 import {Command} from 'chrome://resources/js/cr/ui/command.js';
 import {List} from 'chrome://resources/js/cr/ui/list.m.js';
 
-import {getDirectory, getDisallowedTransfers, startIOTask} from '../../common/js/api.js';
+import {getDisallowedTransfers, startIOTask} from '../../common/js/api.js';
 import {FileType} from '../../common/js/file_type.js';
 import {ProgressCenterItem, ProgressItemState, ProgressItemType} from '../../common/js/progress_center_common.js';
+import {getEnabledTrashVolumeURLs} from '../../common/js/trash.js';
 import {str, strf, util} from '../../common/js/util.js';
 import {VolumeManagerCommon} from '../../common/js/volume_manager_types.js';
 import {FileOperationManager} from '../../externs/background/file_operation_manager.js';
@@ -948,12 +949,37 @@
    * @param {!Event} event A dragleave event of DOM.
    * @private
    */
-  onDrop_(onlyIntoDirectories, event) {
+  async onDrop_(onlyIntoDirectories, event) {
     if (onlyIntoDirectories && !this.dropTarget_) {
       return;
     }
     const destinationEntry =
         this.destinationEntry_ || this.directoryModel_.getCurrentDirEntry();
+    if (destinationEntry.rootType === VolumeManagerCommon.RootType.TRASH &&
+        this.canTrashSelection_(destinationEntry, event.dataTransfer)) {
+      event.preventDefault();
+      const sourceURLs =
+          (event.dataTransfer.getData('fs/sources') || '').split('\n');
+      const {entries, failureUrls} =
+          await FileTransferController.URLsToEntriesWithAccess(sourceURLs);
+
+      // The list of entries should not be special entries (e.g. Camera, Linux
+      // files) and should not already exist in Trash (i.e. you can't trash
+      // something that's already trashed).
+      const isModifiableAndNotInTrashRoot = entry => {
+        return !util.isNonModifiable(this.volumeManager_, entry) &&
+            !util.isTrashEntry(entry);
+      };
+      const canTrashEntries = entries && entries.length > 0 &&
+          entries.every(isModifiableAndNotInTrashRoot);
+      if (canTrashEntries && (!failureUrls || failureUrls.length === 0)) {
+        startIOTask(
+            chrome.fileManagerPrivate.IOTaskType.TRASH, entries,
+            /*params=*/ {});
+      }
+      this.clearDropTarget_();
+      return;
+    }
     if (!this.canPasteOrDrop_(event.dataTransfer, destinationEntry)) {
       return;
     }
@@ -1335,6 +1361,13 @@
       return false;  // Unsupported type of content.
     }
 
+    // A drop on the Trash root should always perform a "Send to Trash"
+    // operation.
+    if (destinationLocationInfo.rootType ===
+        VolumeManagerCommon.RootType.TRASH) {
+      return this.canTrashSelection_(destinationLocationInfo, clipboardData);
+    }
+
     const sourceUrls = (clipboardData.getData('fs/sources') || '').split('\n');
     if (this.getSourceRootURL_(
             clipboardData, this.getDragAndDropGlobalData_()) !==
@@ -1539,6 +1572,16 @@
           DropEffectType.NONE,
           strf('DROP_TARGET_FOLDER_NO_MOVE_PERMISSION', destinationEntry.name));
     }
+    // Files can be dragged onto the TrashRootEntry, but they must reside on a
+    // volume that is trashable.
+    if (destinationLocationInfo.rootType ===
+        VolumeManagerCommon.RootType.TRASH) {
+      const effect = (this.canTrashSelection_(
+                         destinationLocationInfo, event.dataTransfer)) ?
+          DropEffectType.MOVE :
+          DropEffectType.NONE;
+      return new DropEffectAndLabel(effect, null);
+    }
     if (util.isDropEffectAllowed(event.dataTransfer.effectAllowed, 'move')) {
       if (!util.isDropEffectAllowed(event.dataTransfer.effectAllowed, 'copy')) {
         return new DropEffectAndLabel(DropEffectType.MOVE, null);
@@ -1558,6 +1601,65 @@
   }
 
   /**
+   * Identifies if the current selection can be sent to the trash. Items can be
+   * dragged and dropped onto the TrashRootEntry, but they must all come from a
+   * valid location that supports trash.
+   * The URLs are compared against the volumes that are enabled for trashing.
+   * This is to avoid blocking the drag drop operation with resolution of the
+   * URLs to entries. This has the unfortunate side effect of not being able to
+   * identify any non modifiable entries after a directory change but prior to
+   * the drop event occurring.
+   * @param {DirectoryEntry|FilesAppDirEntry|EntryLocation|null}
+   *     destinationEntry The destination for the current selection.
+   * @param {DataTransfer} clipboardData Data transfer object.
+   * @returns {boolean} True if the selection can be trashed, false otherwise.
+   * @private
+   */
+  canTrashSelection_(destinationEntry, clipboardData) {
+    if (!util.isTrashEnabled() || !destinationEntry) {
+      return false;
+    }
+    if (destinationEntry.rootType !== VolumeManagerCommon.RootType.TRASH) {
+      return false;
+    }
+    if (!clipboardData) {
+      return false;
+    }
+    const enabledTrashURLs = getEnabledTrashVolumeURLs(this.volumeManager_);
+    // When the dragDrop event starts the selectionHandler_ contains the initial
+    // selection, this is preferable to identify whether the selection is
+    // available or not as the sources have resolved entries already.
+    const {entries} = this.selectionHandler_.selection;
+    if (entries && entries.length > 0) {
+      for (const entry of entries) {
+        if (util.isNonModifiable(this.volumeManager_, entry)) {
+          return false;
+        }
+        const entryURL = entry.toURL();
+        if (enabledTrashURLs.some(
+                volumeURL => entryURL.startsWith(volumeURL))) {
+          continue;
+        }
+        return false;
+      }
+      return true;
+    }
+    // If the selection is cleared the directory may have changed but the drag
+    // event is still active. The only way to validate if the selection is
+    // trashable now is to compare the `sourceRootURL` against the enabled trash
+    // locations.
+    // TODO(b/241517469): At this point the sourceRootURL may be on an enabled
+    // location but the entry may not be trashable (e.g. Downloads and the
+    // Camera folder). When the drop event occurs the URLs get resolved to
+    // entries to ensure the operation can occur, but this may result in a move
+    // operation showing as allowed when the drop doesn't accept it.
+    const sourceRootURL =
+        this.getSourceRootURL_(clipboardData, this.getDragAndDropGlobalData_());
+    return enabledTrashURLs.some(
+        volumeURL => sourceRootURL.startsWith(volumeURL));
+  }
+
+  /**
    * Blinks the selection. Used to give feedback when copying or cutting the
    * selection.
    * @private
diff --git a/ui/file_manager/file_manager/foreground/js/main_window_component.js b/ui/file_manager/file_manager/foreground/js/main_window_component.js
index 2167c86..1c132c0 100644
--- a/ui/file_manager/file_manager/foreground/js/main_window_component.js
+++ b/ui/file_manager/file_manager/foreground/js/main_window_component.js
@@ -144,10 +144,6 @@
         'focus', this.onFileListFocus_.bind(this));
     ui.listContainer.grid.addEventListener(
         'focus', this.onFileListFocus_.bind(this));
-    if (!util.isFilesAppExperimental()) {
-      ui.breadcrumbController.addEventListener(
-          'pathclick', this.onBreadcrumbClick_.bind(this));
-    }
     /**
      * We are binding both click/keyup event here because "click" event will
      * be triggered multiple times if the Enter/Space key is being pressed
@@ -199,14 +195,6 @@
   }
 
   /**
-   * @param {Event} event Click event.
-   * @private
-   */
-  onBreadcrumbClick_(event) {
-    this.directoryModel_.changeDirectoryEntry(event.entry);
-  }
-
-  /**
    * File list focus handler. Used to select the top most element on the list
    * if nothing was selected.
    *
@@ -419,27 +407,14 @@
     switch (util.getKeyModifiers(event) + event.key) {
       case 'Backspace':  // Backspace => Up one directory.
         event.preventDefault();
-        if (util.isFilesAppExperimental()) {
-          const store = getStore();
-          const state = store.getState();
-          const components = state.currentDirectory?.pathComponents;
-          if (!components || components.length < 2) {
-            break;
-          }
-          const parent = components[components.length - 2];
-          store.dispatch(changeDirectory({toKey: parent.key}));
-        } else {
-          const components =
-              this.ui_.breadcrumbController.getCurrentPathComponents();
-          if (components.length < 2) {
-            break;
-          }
-          const parentPathComponent = components[components.length - 2];
-          parentPathComponent.resolveEntry().then((parentEntry) => {
-            this.directoryModel_.changeDirectoryEntry(
-                /** @type {!DirectoryEntry} */ (parentEntry));
-          });
+        const store = getStore();
+        const state = store.getState();
+        const components = state.currentDirectory?.pathComponents;
+        if (!components || components.length < 2) {
+          break;
         }
+        const parent = components[components.length - 2];
+        store.dispatch(changeDirectory({toKey: parent.key}));
         break;
 
       case 'Enter':  // Enter => Change directory or perform default action.
@@ -500,9 +475,6 @@
     this.ui_.element.toggleAttribute('unformatted', /*force=*/ unformatted);
 
     if (event.newDirEntry) {
-      if (!util.isFilesAppExperimental()) {
-        this.ui_.breadcrumbController.show(event.newDirEntry);
-      }
       // Updates UI.
       if (this.dialogType_ === DialogType.FULL_PAGE) {
         const locationInfo =
@@ -516,10 +488,6 @@
               event.newDirEntry.fullPath);
         }
       }
-    } else {
-      if (!util.isFilesAppExperimental()) {
-        this.ui_.breadcrumbController.hide();
-      }
     }
   }
 
diff --git a/ui/file_manager/file_manager/foreground/js/search_controller.js b/ui/file_manager/file_manager/foreground/js/search_controller.js
index d8759acf..e5c1367 100644
--- a/ui/file_manager/file_manager/foreground/js/search_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/search_controller.js
@@ -132,7 +132,7 @@
     // {@code DirectoryModel.search()}.
     if (this.directoryModel_.isSearching() &&
         this.directoryModel_.getLastSearchQuery() != searchString) {
-      this.directoryModel_.search('', () => {}, () => {});
+      this.directoryModel_.search('', () => {});
     }
 
     this.requestAutocompleteSuggestions_();
@@ -274,30 +274,8 @@
           count === 0 ? 'SEARCH_A11Y_NO_RESULT' : 'SEARCH_A11Y_RESULT';
       const msg = strf(msgId, searchString);
       this.a11y_.speakA11yMessage(msg);
-
-      // If the current location is somewhere in Drive, all files in Drive can
-      // be listed as search results regardless of current location.
-      // In this case, showing current location is confusing, so use the Drive
-      // root "My Drive" as the current location.
-      if (this.isOnDrive_) {
-        const locationInfo = this.currentLocationInfo_;
-        const rootEntry = locationInfo.volumeInfo.displayRoot;
-        if (rootEntry) {
-          if (!util.isFilesAppExperimental()) {
-            this.breadcrumbController_.show(rootEntry);
-          }
-        }
-      }
     };
 
-    const onClearSearch = function() {
-      if (!util.isFilesAppExperimental()) {
-        this.breadcrumbController_.show(
-            this.directoryModel_.getCurrentDirEntry());
-      }
-    };
-
-    this.directoryModel_.search(
-        searchString, onSearchRescan.bind(this), onClearSearch.bind(this));
+    this.directoryModel_.search(searchString, onSearchRescan.bind(this));
   }
 }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_offline_pinning_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_offline_pinning_banner.html
index 55c4b4e..207f11cb 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_offline_pinning_banner.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_offline_pinning_banner.html
@@ -1,6 +1,6 @@
 <style>
   educational-banner {
-    --feature-icon-bg: url(./foreground/images/files/ui/drive_offline_icon.svg);
+    --feature-icon-bg: url(/foreground/images/files/ui/drive_offline_icon.svg);
   }
 </style>
 <educational-banner>
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_out_of_individual_space_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_out_of_individual_space_banner.html
index c28733d..3421ad4 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_out_of_individual_space_banner.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_out_of_individual_space_banner.html
@@ -1,6 +1,6 @@
 <style>
   warning-banner {
-    --icon-src: url(../../../images/files/ui/error_banner_icon.svg);
+    --icon-src: url(/foreground/images/files/ui/error_banner_icon.svg);
   }
 </style>
 <warning-banner>
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_out_of_organization_space_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_out_of_organization_space_banner.html
index 93fea881e..ef7f702 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_out_of_organization_space_banner.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_out_of_organization_space_banner.html
@@ -1,6 +1,6 @@
 <style>
   warning-banner {
-    --icon-src: url(../../../images/files/ui/error_banner_icon.svg);
+    --icon-src: url(/foreground/images/files/ui/error_banner_icon.svg);
   }
 </style>
 <warning-banner>
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_welcome_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_welcome_banner.html
index c71d960..3ffa8dd5 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/drive_welcome_banner.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/drive_welcome_banner.html
@@ -1,6 +1,6 @@
 <style>
   educational-banner {
-    --feature-icon-bg: url(./foreground/images/files/ui/drive_logo.svg);
+    --feature-icon-bg: url(/foreground/images/files/ui/drive_logo.svg);
   }
 </style>
 <educational-banner>
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/holding_space_welcome_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/holding_space_welcome_banner.html
index 8250a44..718a488 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/holding_space_welcome_banner.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/holding_space_welcome_banner.html
@@ -1,6 +1,6 @@
 <style>
   educational-banner {
-    --feature-icon-bg: url(./foreground/images/files/ui/holding_space_welcome_image.svg);
+    --feature-icon-bg: url(/foreground/images/files/ui/holding_space_welcome_image.svg);
   }
 
   .tablet-mode-enabled {
@@ -18,7 +18,7 @@
   }
 
   .icon {
-    -webkit-mask-image: url(./foreground/images/files/ui/menu_ng.svg);
+    -webkit-mask-image: url(/foreground/images/files/ui/menu_ng.svg);
     -webkit-mask-position: center;
     -webkit-mask-repeat: no-repeat;
     -webkit-mask-size: 100%;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/photos_welcome_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/photos_welcome_banner.html
index 7e7b54e..927b3bb 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/photos_welcome_banner.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/photos_welcome_banner.html
@@ -1,6 +1,6 @@
 <style>
   educational-banner {
-    --feature-icon-bg: url(./foreground/images/files/ui/photos_logo.svg);
+    --feature-icon-bg: url(/foreground/images/files/ui/photos_logo.svg);
   }
 </style>
 <educational-banner>
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/state_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/state_banner.html
index e164e8e..2a98a50 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/state_banner.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/state_banner.html
@@ -19,7 +19,7 @@
   }
 
   .state-icon {
-    background-image: url(../../../images/files/ui/state_banner_icon.svg);
+    background-image: url(/foreground/images/files/ui/state_banner_icon.svg);
     background-size: 32px 32px;
     flex: none;
     height: 32px;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners/warning_banner.html b/ui/file_manager/file_manager/foreground/js/ui/banners/warning_banner.html
index b7ca1c9..b6e9202 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners/warning_banner.html
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners/warning_banner.html
@@ -20,7 +20,7 @@
 
   .warning-icon {
     background-image: var(--icon-src,
-      url(../../../images/files/ui/warning_banner_icon.svg));
+      url(/foreground/images/files/ui/warning_banner_icon.svg));
     background-size: 32px 32px;
     flex: none;
     height: 32px;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
index a48ff216..c804cc79 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -451,15 +451,8 @@
         this.dialogType_);
 
     // Breadcrumb controller.
-    if (util.isFilesAppExperimental()) {
-      // TODO: Rename location-breadcrumbs to location-breadcrumb.
-      this.breadcrumbController = new BreadcrumbContainer(
-          util.queryRequiredElement('#location-breadcrumbs', this.element));
-    } else {
-      this.breadcrumbController = new BreadcrumbController(
-          util.queryRequiredElement('#location-breadcrumbs', this.element),
-          volumeManager, this.listContainer);
-    }
+    this.breadcrumbController = new BreadcrumbContainer(
+        util.queryRequiredElement('#location-breadcrumbs', this.element));
 
     // Splitter.
     this.decorateSplitter_(
diff --git a/ui/file_manager/file_manager/lib/base_store.ts b/ui/file_manager/file_manager/lib/base_store.ts
index bc5221b..6f2b7cc5 100644
--- a/ui/file_manager/file_manager/lib/base_store.ts
+++ b/ui/file_manager/file_manager/lib/base_store.ts
@@ -6,8 +6,12 @@
  * The base interface for actions.
  * The application should extend this to enforce its own Actions.
  */
-export interface BaseAction {
+export interface BaseAction<TPayload = any> {
+  // Unique type for the Action.
   type: string;
+
+  // Any additional data used by the Action.
+  payload?: TPayload;
 }
 
 /**
diff --git a/ui/file_manager/file_manager/state/actions.ts b/ui/file_manager/file_manager/state/actions.ts
index 4e3fd5f8..8309aba 100644
--- a/ui/file_manager/file_manager/state/actions.ts
+++ b/ui/file_manager/file_manager/state/actions.ts
@@ -8,32 +8,43 @@
 import {FileKey} from './file_key.js';
 
 /**
- * Base class for all Actions in Files app.
+ * Union of all types of Actions in Files app.
  *
- * It enforces the type/enum for the `type` attribute.
+ * It enforces the type/enum for the `type` and `payload` attributes.
+ * A good explanation of this feature is here:
+ * https://mariusschulz.com/blog/tagged-union-types-in-typescript
  */
-export interface Action extends BaseAction {
-  type: Actions;
-}
+export type Action =
+    ChangeDirectoryAction|ClearStaleCachedEntriesAction|SearchAction;
+
 
 /** Enum to identify every Action in Files app. */
-export const enum Actions {
+export const enum ActionType {
   CHANGE_DIRECTORY = 'change-directory',
   CLEAR_STALE_CACHED_ENTRIES = 'clear-stale-cached-entries',
   SEARCH = 'search',
 }
 
 /** Action to request to change the Current Directory. */
-export interface ChangeDirectoryAction extends Action {
-  newDirectory?: Entry;
-  key: FileKey;
-  status: PropStatus;
+export interface ChangeDirectoryAction extends BaseAction {
+  type: ActionType.CHANGE_DIRECTORY;
+  payload: {
+    newDirectory?: Entry, key: FileKey, status: PropStatus,
+  };
+}
+
+export interface ClearStaleCachedEntriesAction extends BaseAction {
+  type: ActionType.CLEAR_STALE_CACHED_ENTRIES;
+  payload?: undefined;
 }
 
 /** Action to update the search state. */
-export interface SearchAction extends Action {
-  term?: string;
-  status?: PropStatus;
+export interface SearchAction extends BaseAction {
+  type: ActionType.SEARCH;
+  payload: {
+    query?: string,
+    status?: PropStatus,
+  };
 }
 
 /** Factory for the ChangeDirectoryAction. */
@@ -41,18 +52,23 @@
     {to, toKey, status}: {to?: Entry, toKey: FileKey, status?: PropStatus}):
     ChangeDirectoryAction {
   return {
-    type: Actions.CHANGE_DIRECTORY,
-    newDirectory: to,
-    key: toKey ? toKey : to!.toURL(),
-    status: status ? status : PropStatus.STARTED,
+    type: ActionType.CHANGE_DIRECTORY,
+    payload: {
+      newDirectory: to,
+      key: toKey ? toKey : to!.toURL(),
+      status: status ? status : PropStatus.STARTED,
+    },
   };
 }
 
 export function searchAction(
-    {term, status}: {term?: string, status?: PropStatus}): SearchAction {
+    {query: query, status}: {query?: string, status?: PropStatus}):
+    SearchAction {
   return {
-    type: Actions.SEARCH,
-    term,
-    status,
+    type: ActionType.SEARCH,
+    payload: {
+      query: query,
+      status,
+    },
   };
 }
diff --git a/ui/file_manager/file_manager/state/reducers/all_entries.ts b/ui/file_manager/file_manager/state/reducers/all_entries.ts
index 87668af..1a898bf 100644
--- a/ui/file_manager/file_manager/state/reducers/all_entries.ts
+++ b/ui/file_manager/file_manager/state/reducers/all_entries.ts
@@ -4,7 +4,7 @@
 
 import {FilesAppEntry} from '../../externs/files_app_entry_interfaces.js';
 import {State} from '../../externs/ts/state.js';
-import {Action, Actions, ChangeDirectoryAction} from '../actions.js';
+import {Action, ActionType, ChangeDirectoryAction, ClearStaleCachedEntriesAction} from '../actions.js';
 import {getStore} from '../store.js';
 
 /**
@@ -22,7 +22,7 @@
 /** Starts the action CLEAR_STALE_CACHED_ENTRIES.  */
 function startClearCache() {
   const store = getStore();
-  store.dispatch({type: Actions.CLEAR_STALE_CACHED_ENTRIES});
+  store.dispatch({type: ActionType.CLEAR_STALE_CACHED_ENTRIES});
   clearCachedEntriesRequestId = 0;
 }
 
@@ -30,10 +30,10 @@
  * Scans the current state for entries still in use to be able to remove the
  * stale entries from the `allEntries`.
  */
-export function clearCachedEntries(state: State, _action: Action): State {
+export function clearCachedEntries(
+    state: State, _action: ClearStaleCachedEntriesAction): State {
   const entries = state.allEntries;
-  const currentDirectoryKey =
-      state.currentDirectory ? state.currentDirectory.key : null;
+  const currentDirectoryKey = state.currentDirectory?.key;
   const entriesToKeep = new Set<string>();
 
   if (currentDirectoryKey) {
@@ -61,7 +61,7 @@
  */
 function getEntry(state: State, action: ChangeDirectoryAction): Entry|
     FilesAppEntry|null {
-  const {newDirectory, key} = action;
+  const {newDirectory, key} = action.payload;
   if (newDirectory) {
     return newDirectory;
   }
@@ -78,8 +78,8 @@
   // Schedule to clear the cached entries from the state.
   scheduleClearCachedEntries();
 
-  if (action.type === Actions.CHANGE_DIRECTORY) {
-    const {key} = (action as ChangeDirectoryAction);
+  if (action.type === ActionType.CHANGE_DIRECTORY) {
+    const {key} = action.payload;
     const allEntries = currentState.allEntries || {};
 
     const entry = getEntry(currentState, (action as ChangeDirectoryAction));
diff --git a/ui/file_manager/file_manager/state/reducers/all_entries_unittest.ts b/ui/file_manager/file_manager/state/reducers/all_entries_unittest.ts
index e2f2ff04..8b9373b 100644
--- a/ui/file_manager/file_manager/state/reducers/all_entries_unittest.ts
+++ b/ui/file_manager/file_manager/state/reducers/all_entries_unittest.ts
@@ -7,7 +7,7 @@
 import {MockVolumeManager} from '../../background/js/mock_volume_manager.js';
 import {MockFileSystem} from '../../common/js/mock_entry.js';
 import {waitUntil} from '../../common/js/test_error_reporting.js';
-import {Actions, changeDirectory} from '../actions.js';
+import {ActionType, changeDirectory, ClearStaleCachedEntriesAction} from '../actions.js';
 import {getEmptyState, getStore, Store} from '../store.js';
 
 import {clearCachedEntries} from './all_entries.js';
@@ -85,7 +85,10 @@
       ['filesystem:downloads/dir-2', 'filesystem:downloads/dir-2/sub-dir']);
 
   // Running the clear multiple times should not change:
-  const action = {type: Actions.CLEAR_STALE_CACHED_ENTRIES};
+  const action: ClearStaleCachedEntriesAction = {
+    type: ActionType.CLEAR_STALE_CACHED_ENTRIES,
+    payload: undefined,
+  };
   clearCachedEntries(store.getState(), action);
   clearCachedEntries(store.getState(), action);
   assertEquals(
diff --git a/ui/file_manager/file_manager/state/reducers/current_directory.ts b/ui/file_manager/file_manager/state/reducers/current_directory.ts
index c28d8c39..4952b033 100644
--- a/ui/file_manager/file_manager/state/reducers/current_directory.ts
+++ b/ui/file_manager/file_manager/state/reducers/current_directory.ts
@@ -9,10 +9,10 @@
 /** Reducer that updates the `currentDirectory` attributes. */
 export function changeDirectory(
     currentState: State, action: ChangeDirectoryAction): CurrentDirectory {
-  const fileData = currentState.allEntries[action.key];
+  const fileData = currentState.allEntries[action.payload.key];
   const emptyDir = {
-    key: action.key,
-    status: action.status,
+    key: action.payload.key,
+    status: action.payload.status,
     pathComponents: [],
   };
 
@@ -35,8 +35,8 @@
       PathComponent.computeComponentsFromEntry(fileData.entry!, volumeManager);
 
   return Object.assign(currentState.currentDirectory || {}, {
-    status: action.status,
-    key: (action as ChangeDirectoryAction).key,
+    status: action.payload.status,
+    key: action.payload.key,
     pathComponents: components.map(c => {
       return {
         name: c.name,
diff --git a/ui/file_manager/file_manager/state/reducers/root.ts b/ui/file_manager/file_manager/state/reducers/root.ts
index 2be5d80..644912ae 100644
--- a/ui/file_manager/file_manager/state/reducers/root.ts
+++ b/ui/file_manager/file_manager/state/reducers/root.ts
@@ -3,15 +3,19 @@
 // found in the LICENSE file.
 
 import {State} from '../../externs/ts/state.js';
-import {Action, Actions, ChangeDirectoryAction} from '../actions.js';
+import {Action, ActionType} from '../actions.js';
 
 import {cacheEntries, clearCachedEntries} from './all_entries.js';
 import {changeDirectory} from './current_directory.js';
 import {search} from './search.js';
 
 /**
- * Root reducer for Files app.
- * It dispatches to other reducers to update different parts of the State.
+ * Root reducer for the State for Files app.
+ * It dispatches the ` action` to other reducers that update each part of the
+ * State.
+ *
+ * Every top-level attribute of the State should have its reducer being called
+ * from here.
  */
 export function rootReducer(currentState: State, action: Action): State {
   // Before any actual Reducer, we cache the entries, so the reducers can just
@@ -19,22 +23,21 @@
   const state = cacheEntries(currentState, action);
 
   switch (action.type) {
-    case Actions.CHANGE_DIRECTORY:
+    case ActionType.CHANGE_DIRECTORY:
       return Object.assign(state, {
-        currentDirectory:
-            changeDirectory(state, action as ChangeDirectoryAction),
+        currentDirectory: changeDirectory(state, action),
       });
 
-    case Actions.CLEAR_STALE_CACHED_ENTRIES:
+    case ActionType.CLEAR_STALE_CACHED_ENTRIES:
       return clearCachedEntries(state, action);
 
-    case Actions.SEARCH:
+    case ActionType.SEARCH:
       return Object.assign(state, {
         search: search(state, action),
       });
 
     default:
-      console.error(`invalid action: ${action.type}`);
+      console.error(`invalid action: ${action}`);
       return state;
   }
 }
diff --git a/ui/file_manager/file_manager/state/reducers/search.ts b/ui/file_manager/file_manager/state/reducers/search.ts
index 42ab426..e2930073 100644
--- a/ui/file_manager/file_manager/state/reducers/search.ts
+++ b/ui/file_manager/file_manager/state/reducers/search.ts
@@ -7,7 +7,7 @@
 
 export function search(_state: State, action: SearchAction): SearchData {
   return {
-    term: action.term,
-    status: action.status,
+    query: action.payload.query,
+    status: action.payload.status,
   };
 }
diff --git a/ui/file_manager/file_manager/state/store.ts b/ui/file_manager/file_manager/state/store.ts
index e3f22ed..67be655 100644
--- a/ui/file_manager/file_manager/state/store.ts
+++ b/ui/file_manager/file_manager/state/store.ts
@@ -42,7 +42,7 @@
     allEntries: {},
     currentDirectory: undefined,
     search: {
-      term: undefined,
+      query: undefined,
       status: undefined,
     },
   };
diff --git a/ui/file_manager/file_manager/widgets/xf_breadcrumb.html b/ui/file_manager/file_manager/widgets/xf_breadcrumb.html
index 9c5e342..0679ce0 100644
--- a/ui/file_manager/file_manager/widgets/xf_breadcrumb.html
+++ b/ui/file_manager/file_manager/widgets/xf_breadcrumb.html
@@ -20,7 +20,7 @@
   }
 
   span[caret] {
-    -webkit-mask-image: url(../../images/files/ui/arrow_right.svg);
+    -webkit-mask-image: url(/foreground/images/files/ui/arrow_right.svg);
     -webkit-mask-position: center;
     -webkit-mask-repeat: no-repeat;
     background-color: var(--cros-icon-color-secondary);
@@ -71,7 +71,7 @@
 
   span[elider] {
     --tap-target-shift: -7px;
-    -webkit-mask-image: url(../../images/files/ui/menu_ng.svg);
+    -webkit-mask-image: url(/foreground/images/files/ui/menu_ng.svg);
     -webkit-mask-position: center;
     -webkit-mask-repeat: no-repeat;
     background-color: var(--cros-icon-color-primary);
diff --git a/ui/file_manager/integration_tests/file_manager/breadcrumbs.js b/ui/file_manager/integration_tests/file_manager/breadcrumbs.js
index 04f1799..af62da7 100644
--- a/ui/file_manager/integration_tests/file_manager/breadcrumbs.js
+++ b/ui/file_manager/integration_tests/file_manager/breadcrumbs.js
@@ -11,10 +11,7 @@
 import {expandTreeItem, navigateWithDirectoryTree, remoteCall, setupAndWaitUntilReady} from './background.js';
 
 async function getBreadcrumbTagName() {
-  const isFilesAppExperimental =
-      await sendTestMessage({name: 'isFilesAppExperimental'}) === 'true';
-
-  return isFilesAppExperimental ? 'xf-breadcrumb' : 'bread-crumb';
+  return 'xf-breadcrumb';
 }
 
 testcase.breadcrumbsNavigate = async () => {
diff --git a/ui/file_manager/integration_tests/file_manager/recents.js b/ui/file_manager/integration_tests/file_manager/recents.js
index 7dd5f85d..0886f90 100644
--- a/ui/file_manager/integration_tests/file_manager/recents.js
+++ b/ui/file_manager/integration_tests/file_manager/recents.js
@@ -1056,22 +1056,20 @@
       RootPath.DOWNLOADS, [ENTRIES.directoryA], []);
   await navigateToRecent(appId);
   // All filter is on by default.
-  await waitForEmptyFolderMessage(appId, 'Your recent files will appear here');
+  await waitForEmptyFolderMessage(appId, 'No recent files');
   // Activates to audio filter.
   await remoteCall.waitAndClickElement(appId, [`[file-type-filter="audio"]`]);
-  await waitForEmptyFolderMessage(
-      appId, 'Your recent audio files will appear here');
+  await waitForEmptyFolderMessage(appId, 'No recent audio files');
   // Activates to documents filter.
   await remoteCall.waitAndClickElement(
       appId, [`[file-type-filter="document"]`]);
-  await waitForEmptyFolderMessage(
-      appId, 'Your recent documents will appear here');
+  await waitForEmptyFolderMessage(appId, 'No recent documents');
   // Activates to images filter.
   await remoteCall.waitAndClickElement(appId, [`[file-type-filter="image"]`]);
-  await waitForEmptyFolderMessage(appId, 'Your recent images will appear here');
+  await waitForEmptyFolderMessage(appId, 'No recent images');
   // Activates to videos filter.
   await remoteCall.waitAndClickElement(appId, [`[file-type-filter="video"]`]);
-  await waitForEmptyFolderMessage(appId, 'Your recent videos will appear here');
+  await waitForEmptyFolderMessage(appId, 'No recent videos');
 };
 
 
@@ -1086,5 +1084,5 @@
   const files = TestEntryInfo.getExpectedRows([ENTRIES.beautiful]);
   await remoteCall.waitForFiles(appId, files);
   await deleteFile(appId, ENTRIES.beautiful.nameText);
-  await waitForEmptyFolderMessage(appId, 'Your recent files will appear here');
+  await waitForEmptyFolderMessage(appId, 'No recent files');
 };
diff --git a/ui/file_manager/integration_tests/file_manager/trash.js b/ui/file_manager/integration_tests/file_manager/trash.js
index cc58051..d4743bd 100644
--- a/ui/file_manager/integration_tests/file_manager/trash.js
+++ b/ui/file_manager/integration_tests/file_manager/trash.js
@@ -7,7 +7,7 @@
 
 import {expandTreeItem, IGNORE_APP_ERRORS, mountCrostini, navigateWithDirectoryTree, openNewWindow, remoteCall, setupAndWaitUntilReady} from './background.js';
 import {DOWNLOADS_FAKE_TASKS} from './tasks.js';
-import {BASIC_LOCAL_ENTRY_SET} from './test_data.js';
+import {BASIC_ANDROID_ENTRY_SET, BASIC_LOCAL_ENTRY_SET} from './test_data.js';
 
 /**
  * Delete files in MyFiles and ensure they are moved to /.Trash.
@@ -422,3 +422,184 @@
       ['#file-list [file-name="My files › Downloads › hello.txt"]']);
   await remoteCall.waitForElement(appId, '.files-alert-dialog');
 };
+
+/**
+ * Tests that dragging an accepted file over Trash shows that it accepts the
+ * action and performs a trash operation (move a move).
+ */
+testcase.trashDragDropRootAcceptsEntries = async () => {
+  const appId = await setupAndWaitUntilReady(
+      RootPath.DOWNLOADS, BASIC_LOCAL_ENTRY_SET, []);
+
+  // The drag has to start in the file list column "name" text, otherwise it
+  // starts a drag-selection instead of a drag operation.
+  const source = '#file-list [file-name="hello.txt"] .entry-name';
+
+  // Select the source file.
+  await remoteCall.waitAndClickElement(appId, source);
+
+  // Wait for the directory tree target.
+  const target = '#directory-tree [entry-label="Trash"]';
+  await remoteCall.waitForElement(appId, target);
+
+  // Drag the source and hover it over the target.
+  const skipDrop = true;
+  chrome.test.assertTrue(
+      await remoteCall.callRemoteTestUtil(
+          'fakeDragAndDrop', appId, [source, target, skipDrop]),
+      'fakeDragAndDrop failed');
+
+  // Check: drag hovering should navigate the file list.
+  await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/Trash');
+
+  // Check: the target should have accepts class.
+  const willAcceptDrop = '#directory-tree [entry-label="Trash"].accepts';
+  await remoteCall.waitForElement(appId, willAcceptDrop);
+
+  // Check: the target should not have denies class.
+  const willDenyDrop = '#directory-tree [entry-label="Trash"].denies';
+  await remoteCall.waitForElementLost(appId, willDenyDrop);
+
+  // Send a dragdrop event to the target to start a trash operation.
+  const dragLeave = false;
+  chrome.test.assertTrue(
+      await remoteCall.callRemoteTestUtil(
+          'fakeDragLeaveOrDrop', appId, ['#file-list', target, dragLeave]),
+      'fakeDragLeaveOrDrop failed');
+
+  // The Trash root should not have either accepts nor denies after stopping the
+  // dragdrop event.
+  await remoteCall.waitForElementLost(appId, willAcceptDrop);
+  await remoteCall.waitForElementLost(appId, willDenyDrop);
+};
+
+/**
+ * Tests that dragging a file from a location that Trash is not enabled (Android
+ * files in this case) shows it is denied.
+ */
+testcase.trashDragDropFromDisallowedRootsFails = async () => {
+  // Open Files app on Play Files.
+  await addEntries(['android_files'], BASIC_ANDROID_ENTRY_SET);
+  const appId = await openNewWindow(RootPath.ANDROID_FILES);
+
+  // Wait for the file list to appear.
+  await remoteCall.waitForElement(appId, '#file-list');
+
+  // Set the source of the drag event to the name of the file.
+  const source = `#file-list li[file-name="${
+      BASIC_ANDROID_ENTRY_SET[0].nameText}"] .entry-name`;
+
+  // Select the source file.
+  await remoteCall.waitAndClickElement(appId, source);
+
+  // Wait for the directory tree target to be visible.
+  const target = '#directory-tree [entry-label="Trash"]';
+  await remoteCall.waitForElement(appId, target);
+
+  // Drag the source and hover it over the target.
+  const skipDrop = true;
+  chrome.test.assertTrue(
+      await remoteCall.callRemoteTestUtil(
+          'fakeDragAndDrop', appId, [source, target, skipDrop]),
+      'fakeDragAndDrop failed');
+
+  // Wait for the directory to change to the Trash root.
+  await remoteCall.waitUntilCurrentDirectoryIsChanged(appId, '/Trash');
+
+  // The Trash root in the directory tree shouldn't have the accepts class.
+  const willAcceptDrop = '#directory-tree [entry-label="Trash"].accepts';
+  await remoteCall.waitForElementLost(appId, willAcceptDrop);
+
+  // The Trash root should have a denies class.
+  const willDenyDrop = '#directory-tree [entry-label="Trash"].denies';
+  await remoteCall.waitForElement(appId, willDenyDrop);
+
+  // Send a dragleave event to the target to stop the drag event.
+  const dragLeave = true;
+  chrome.test.assertTrue(
+      await remoteCall.callRemoteTestUtil(
+          'fakeDragLeaveOrDrop', appId, ['#file-list', target, dragLeave]),
+      'fakeDragLeaveOrDrop failed');
+
+  // The Trash root should not have either accepts nor denies after stopping the
+  // dragdrop event.
+  await remoteCall.waitForElementLost(appId, willAcceptDrop);
+  await remoteCall.waitForElementLost(appId, willDenyDrop);
+};
+
+/**
+ * Tests that dragging and dropping on the Trash root actually trashes the item
+ * and it appears in Trash after drop completed.
+ */
+testcase.trashDragDropRootPerformsTrashAction = async () => {
+  const appId = await setupAndWaitUntilReady(
+      RootPath.DOWNLOADS, BASIC_LOCAL_ENTRY_SET, []);
+
+  // The drag has to start in the file list column "name" text, otherwise it
+  // starts a drag-selection instead of a drag operation.
+  const source = '#file-list [file-name="hello.txt"] .entry-name';
+
+  // Select the source file.
+  await remoteCall.waitAndClickElement(appId, source);
+
+  // Wait for the directory tree target.
+  const target = '#directory-tree [entry-label="Trash"]';
+  await remoteCall.waitForElement(appId, target);
+
+  // Send a dragdrop event to the target to start a trash operation.
+  const skipDrop = false;
+  chrome.test.assertTrue(
+      await remoteCall.callRemoteTestUtil(
+          'fakeDragAndDrop', appId, [source, target, skipDrop]),
+      'fakeDragLeaveOrDrop failed');
+
+  // Wait for element to disappear from the "Downloads" view, this indicates it
+  // should be in trash.
+  await remoteCall.waitForElementLost(appId, source);
+
+  // Navigate to the Trash root.
+  await navigateWithDirectoryTree(appId, '/Trash');
+
+  // Wait for the element to appear in the Trash.
+  await remoteCall.waitForElement(
+      appId, '#file-list [file-name="My files › Downloads › hello.txt"]');
+};
+
+/**
+ * Tests that dragging an entry that is non-modifiable (Downloads in this case)
+ * should not be allowed despite residing in a trashable location.
+ */
+testcase.trashDragDropNonModifiableEntriesCantBeTrashed = async () => {
+  const appId = await setupAndWaitUntilReady(
+      RootPath.DOWNLOADS, BASIC_LOCAL_ENTRY_SET, []);
+
+  // Navigate to My files.
+  await navigateWithDirectoryTree(appId, '/My files');
+
+  // Use Downloads entry as the drag source. Although this is technically a
+  // folder and resides on a trashable location "My files", it is a special
+  // entry so we should disallow this from being acceptable as a drop target on
+  // Trash.
+  const source = '#file-list [file-name="Downloads"] .entry-name';
+
+  // Select the source file.
+  await remoteCall.waitAndClickElement(appId, source);
+
+  // Wait for the directory tree target.
+  const target = '#directory-tree [entry-label="Trash"]';
+  await remoteCall.waitForElement(appId, target);
+
+  // Send a dragdrop event to the target to try Trash the downloads folder.
+  const skipDrop = false;
+  chrome.test.assertTrue(
+      await remoteCall.callRemoteTestUtil(
+          'fakeDragAndDrop', appId, [source, target, skipDrop]),
+      'fakeDragLeaveOrDrop failed');
+
+  // Navigate to Trash to ensure Downloads wasn't sent there.
+  await navigateWithDirectoryTree(appId, '/Trash');
+
+  // Ensure the Downloads entry doesn't exist in Trash.
+  await remoteCall.waitForElement(appId, `[scan-completed="Trash"]`);
+  await remoteCall.waitForFiles(appId, []);
+};
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index 876e872..3f77efc 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -162,6 +162,16 @@
       count_show_virtual_keyboard_++;
   }
 
+#if BUILDFLAG(IS_WIN)
+  bool OnUntranslatedIMEMessage(
+      const CHROME_MSG event,
+      InputMethod::NativeEventResult* result) override {
+    return false;
+  }
+  void OnInputLocaleChanged() override {}
+  bool IsInputLocaleCJK() const override { return false; }
+#endif
+
   bool untranslated_ime_message_called() const {
     return untranslated_ime_message_called_;
   }