diff --git a/BUILD.gn b/BUILD.gn
index c1eec77..77b7cdc 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -466,7 +466,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     deps += [ "//chromeos:chromeos_unittests" ]
   }
 
diff --git a/DEPS b/DEPS
index 2410a19..a685fcbc 100644
--- a/DEPS
+++ b/DEPS
@@ -253,11 +253,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'c422f3ea06923e7333f38567bc1184139f34b4a7',
+  'skia_revision': '0361abf39d1504966799b1cdb5450e07f88b2bc2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '5c89c56a6151c9709e462256feaaf2f6d73f2e17',
+  'v8_revision': '41c4ff564b2a2c1332cc660b97f655c5c0ddb572',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -300,7 +300,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': 'a8e4563c3418ed74d39019a6c5e2122d12c8f56f',
+  'freetype_revision': '119e404b892dc8bf7db53e868039aec187042587',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -320,7 +320,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': '9c152c573064413fea60e676d08fa703e4bb8a58',
+  'catapult_revision': 'f3641e43856292fc2f472de5bbbbe36b0f33e9a8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -328,7 +328,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': '0152106222e975df0ebb8c91d64726f7df45fcf6',
+  'devtools_frontend_revision': '02de12c839bce5e5eba2605a23ece72245fb1d38',
   # 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.
@@ -1058,7 +1058,7 @@
   },
 
   'src/third_party/breakpad/breakpad':
-    Var('chromium_git') + '/breakpad/breakpad.git' + '@' + '08bd844599bf04c71707e8f59a8013a941264695',
+    Var('chromium_git') + '/breakpad/breakpad.git' + '@' + 'e09741c609dcd5f5274d40182c5e2cc9a002d5ba',
 
   'src/third_party/byte_buddy': {
       'packages': [
@@ -1112,7 +1112,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7b9366d9ccdde65c6376f923b69fab5e9a687556',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8930841ac0a2f6f030f00ad6a69d53a620d5e0f9',
       'condition': 'checkout_chromeos',
   },
 
@@ -1132,7 +1132,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0213e4b2d80793e359f52b809fbb9dc34ebdde46',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c0169f32a31c17c50c7bcaab4462e8c17a8a986a',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1272,7 +1272,7 @@
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '41cdffd71c9948f63c7ad36e1fb0ff519aa7a37e',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'a9359a84a3969b3019db7d62899afb19642eefcd',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'a84f25cef95162b6d1ecd94552b7bb41c3934639',
 
   'src/third_party/icu4j': {
       'packages': [
@@ -1343,7 +1343,7 @@
     Var('chromium_git') + '/external/libaddressinput.git' + '@' + '3b8ee157a8f3536bbf5ad2448e9e3370463c1e40',
 
   'src/third_party/libaom/source/libaom':
-    Var('aomedia_git') + '/aom.git' + '@' +  'a68079299d655eb98cbc624c0e3059e1a0609a39',
+    Var('aomedia_git') + '/aom.git' + '@' +  '46e8b1da9e10663ef1bb9868ee20fd24cb175448',
 
   'src/third_party/libavif/src':
     Var('chromium_git') + '/external/github.com/AOMediaCodec/libavif.git' + '@' + Var('libavif_revision'),
@@ -1515,7 +1515,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '03d5ae5e403b60c94ba420e6a7cc50443142aa14',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4e2255781b131bf3be20ca0084ea3f929afc406a',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1612,7 +1612,7 @@
   },
 
   'src/third_party/re2/src':
-    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '248b65f44d9145261328f8b5831a597f6eef7826',
+    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '0c5616df9c0aaa44c9440d87422012423d91c7d1',
 
   'src/third_party/r8': {
       'packages': [
@@ -1697,7 +1697,7 @@
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '62d7d0c928c9a040dce96aa2f16c00e7e67d59cb',
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@f9e3d5a50ca27d120be6a30adae42fb49f85db79',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@8ecd4bddb9370f290f32bfb3e95e1bf29be50f50',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1806,7 +1806,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e957fddd8d769ba5ddf66c934d69ff32ee6f7d3e',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e03116334afbc42f293f0e3bc0acceacd7a87fb6',
     'condition': 'checkout_src_internal',
   },
 
@@ -1814,7 +1814,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/assistant/ambient',
-        'version': 'version:float_on_by_initial_version',
+        'version': 'version:float_on_by_rounded_corners_and_shadows',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index 626ae75c..17390db 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -326,6 +326,7 @@
             // WebView needs to make sure to always use the wrapped application context.
             ctx = ClassLoaderContextWrapperFactory.get(ctx);
             ContextUtils.initApplicationContext(ctx);
+            ContextUtils.setSdkSandboxProcess(isSdkSandboxProcess());
 
             // Find the package ID for the package that WebView's resources come from.
             // This will be the donor package if there is one, not our main package.
@@ -864,4 +865,10 @@
         // TODO: Put the downstream implementation inline and remove this method.
         return false;
     }
+
+    boolean isSdkSandboxProcess() {
+        // TODO: This shall be removed and ContextUtil.isSdkSandboxProcess() calls
+        // Process.isSdkSandbox() directly.
+        return false;
+    }
 }
diff --git a/android_webview/tools/cts_utils.py b/android_webview/tools/cts_utils.py
index bc1610c..dba0752 100644
--- a/android_webview/tools/cts_utils.py
+++ b/android_webview/tools/cts_utils.py
@@ -305,9 +305,11 @@
     deps_file = os.path.join(self._root_dir, DEPS_FILE)
 
     # Use the gclient command instead of gclient_eval since the latter is not
-    # intended for direct use outside of depot_tools.
+    # intended for direct use outside of depot_tools. The .bat file extension
+    # must be explicitly specified when shell=False.
+    gclient = 'gclient.bat' if os.name == 'nt' else 'gclient'
     cmd = [
-        'gclient', 'getdep', '--revision',
+        gclient, 'getdep', '--revision',
         '%s:%s' % (CTS_DEP_NAME, CTS_DEP_PACKAGE), '--deps-file', deps_file
     ]
     env = os.environ
diff --git a/android_webview/tools/cts_utils_test.py b/android_webview/tools/cts_utils_test.py
index 62409a9..793bbac 100755
--- a/android_webview/tools/cts_utils_test.py
+++ b/android_webview/tools/cts_utils_test.py
@@ -312,6 +312,8 @@
 class CTSUtilsTest(unittest.TestCase):
   """Unittests for the cts_utils.py."""
 
+  @unittest.skipIf(os.name == "nt", "Opening NamedTemporaryFile by name "
+                   "doesn't work in Windows.")
   def testCTSCIPDYamlSanity(self):
     yaml_data = cts_utils.CTSCIPDYaml(cts_utils.CIPD_PATH)
     self.assertTrue(yaml_data.get_package())
@@ -321,6 +323,8 @@
       with open(cts_utils.CIPD_PATH) as cipdFile:
         self.assertEqual(cipdFile.readlines(), outputFile.readlines())
 
+  @unittest.skipIf(os.name == "nt", "Opening NamedTemporaryFile by name "
+                   "doesn't work in Windows.")
   def testCTSCIPDYamlOperations(self):
     with tempfile.NamedTemporaryFile('w+t') as yamlFile:
       yamlFile.writelines(CIPD_DATA['yaml'])
@@ -350,6 +354,8 @@
            CIPD_DATA['file4'], 'arch2/platform3/file5.zip'), new_yaml_contents)
 
   @patch('devil.utils.cmd_helper.RunCmd')
+  @unittest.skipIf(os.name == "nt", "Opening NamedTemporaryFile by name "
+                   "doesn't work in Windows.")
   def testCTSCIPDDownload(self, run_mock):
     fake_cipd = FakeCIPD()
     fake_run_cmd = FakeRunCmd(cipd=fake_cipd)
@@ -377,6 +383,8 @@
     self.assertTrue(cts_config.get_origin(platform, archs[0]))
     self.assertTrue(cts_config.get_apks(platform))
 
+  @unittest.skipIf(os.name == "nt", "Opening NamedTemporaryFile by name "
+                   "doesn't work in Windows.")
   def testCTSConfig(self):
     with tempfile.NamedTemporaryFile('w+t') as configFile:
       configFile.writelines(CONFIG_DATA['json'])
@@ -405,6 +413,8 @@
     self.assertTrue(['p2/test1.apk', 'p2/test2.apk'],
                     cts_config.get_apks('platform2'))
 
+  @unittest.skipIf(os.name == "nt", "This fails on Windows, probably because "
+                   "the temporary directory is not empty when it gets deleted.")
   def testFilterZip(self):
     with tempfile_ext.NamedTemporaryDirectory() as workDir,\
          cts_utils.chdir(workDir):
@@ -421,7 +431,10 @@
       self.assertEqual(b'def', zf.read('a/b/two.apk'))
 
   @patch('cts_utils.filterzip')
-  def testFilterCTS(self, filterzip_mock):  # pylint: disable=no-self-use
+  @unittest.skipIf(os.name == "nt", "Opening NamedTemporaryFile by name "
+                   "doesn't work in Windows.")
+  # pylint: disable=no-self-use
+  def testFilterCTS(self, filterzip_mock):
     with tempfile.NamedTemporaryFile('w+t') as configFile:
       configFile.writelines(CONFIG_DATA['json'])
       configFile.flush()
@@ -432,6 +445,8 @@
         os.path.join('/filtered', CONFIG_DATA['base11']))
 
   @patch('devil.utils.cmd_helper.RunCmd')
+  @unittest.skipIf(os.name == "nt", "Opening NamedTemporaryFile by name "
+                   "doesn't work in Windows.")
   def testUpdateCIPDPackage(self, run_mock):
     fake_cipd = FakeCIPD()
     fake_run_cmd = FakeRunCmd(cipd=fake_cipd)
diff --git a/android_webview/tools/run_cts_test.py b/android_webview/tools/run_cts_test.py
index b67b4e5..9330329 100755
--- a/android_webview/tools/run_cts_test.py
+++ b/android_webview/tools/run_cts_test.py
@@ -144,6 +144,8 @@
     self.assertEqual([run_cts.TEST_FILTER_OPT + '=good.t1:good.t2-' + skip],
                      run_cts.GetTestRunFilterArg(mock_args, self._CTS_RUN))
 
+  @unittest.skipIf(os.name == "nt", "Opening NamedTemporaryFile by name "
+                   "doesn't work in Windows.")
   def testFilterFile_CombinesExcludedMatches(self):
     with tempfile.NamedTemporaryFile(prefix='cts_run_test') as filter_file:
       filter_file.write('suite.goodtest'.encode())
@@ -153,6 +155,8 @@
       self.assertEqual([run_cts.TEST_FILTER_OPT + '=suite.goodtest'],
                        run_cts.GetTestRunFilterArg(mock_args, self._CTS_RUN))
 
+  @unittest.skipIf(os.name == "nt", "Opening NamedTemporaryFile by name "
+                   "doesn't work in Windows.")
   def testFilterFile_CombinesAll(self):
     with tempfile.NamedTemporaryFile(prefix='cts_run_test') as filter_file:
       filter_file.write('suite.goodtest'.encode())
diff --git a/android_webview/tools/update_cts_test.py b/android_webview/tools/update_cts_test.py
index e6bb54b..cf297c3 100755
--- a/android_webview/tools/update_cts_test.py
+++ b/android_webview/tools/update_cts_test.py
@@ -179,6 +179,10 @@
         verify_zip_file(CONFIG_DATA['base12'], CONFIG_DATA['apk1'])
 
   @patch('devil.utils.cmd_helper.RunCmd')
+  @unittest.skipIf(os.name == "nt", "This fails on Windows because it calls "
+                   "download_cipd which ultimately calls cipd_ensure which "
+                   "creates a file with NamedTemporaryFile and then opens it "
+                   "by name, which hits permission errors.")
   def testDownloadCIPD(self, run_mock):
     with tempfile_ext.NamedTemporaryDirectory() as workDir,\
          tempfile_ext.NamedTemporaryDirectory() as repoRoot,\
@@ -200,6 +204,10 @@
             cts_utils_test.readfile(
                 os.path.join(workDir, 'cipd', CIPD_DATA['file' + i])))
 
+  @unittest.skipIf(os.name == "nt", "This fails on Windows because it calls "
+                   "download_cipd which ultimately calls cipd_ensure which "
+                   "creates a file with NamedTemporaryFile and then opens it "
+                   "by name, which hits permission errors.")
   def testDownloadCIPD_dirExists(self):
     with tempfile_ext.NamedTemporaryDirectory() as workDir,\
          tempfile_ext.NamedTemporaryDirectory() as repoRoot,\
@@ -264,6 +272,10 @@
 
   @patch('devil.utils.cmd_helper.RunCmd')
   @patch('devil.utils.cmd_helper.GetCmdOutput')
+  @unittest.skipIf(os.name == "nt", "This fails on Windows because it calls "
+                   "update_repository which calls cipd_ensure which creates a "
+                   "file with NamedTemporaryFile and then opens it by name, "
+                   "which hits permission errors.")
   def testUpdateRepository(self, cmd_mock, run_mock):
     with tempfile_ext.NamedTemporaryDirectory() as workDir,\
          tempfile_ext.NamedTemporaryDirectory() as repoRoot,\
@@ -354,6 +366,11 @@
   @patch('devil.utils.cmd_helper.GetCmdOutput')
   @patch.object(cts_utils.ChromiumRepoHelper, 'update_testing_json')
   @patch('urllib.urlretrieve' if six.PY2 else 'urllib.request.urlretrieve')
+  @unittest.skipIf(os.name == "nt", "This fails on Windows because it calls "
+                   "create_cipd_cmd which calls download_cipd which ultimately "
+                   "calls cipd_ensure which creates a file with "
+                   "NamedTemporaryFile and then opens it by name, which hits "
+                   "permission errors.")
   def testCompleteUpdate(self, retrieve_mock, update_json_mock, cmd_mock,
                          run_mock):
     with tempfile_ext.NamedTemporaryDirectory() as workDir,\
diff --git a/ash/accelerators/accelerator_commands.cc b/ash/accelerators/accelerator_commands.cc
index 3cf6fdf..544d2bc 100644
--- a/ash/accelerators/accelerator_commands.cc
+++ b/ash/accelerators/accelerator_commands.cc
@@ -226,7 +226,7 @@
 }
 
 void ToggleFloating() {
-  DCHECK(features::IsWindowControlMenuEnabled());
+  DCHECK(features::IsFloatWindowEnabled());
   aura::Window* active_window = window_util::GetActiveWindow();
   if (!active_window)
     return;
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc
index eac14c3..b87e793c 100644
--- a/ash/accelerators/accelerator_controller_impl.cc
+++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -690,7 +690,7 @@
 }
 
 bool CanHandleToggleFloatingWindow() {
-  return features::IsWindowControlMenuEnabled() &&
+  return features::IsFloatWindowEnabled() &&
          !Shell::Get()->tablet_mode_controller()->InTabletMode();
 }
 
@@ -827,7 +827,7 @@
 }
 
 void HandleToggleFloating() {
-  DCHECK(features::IsWindowControlMenuEnabled());
+  DCHECK(features::IsFloatWindowEnabled());
   // Floating is currently not supported for tablet mode, see timeline here:
   // https://crbug.com/1240411
   DCHECK(!Shell::Get()->tablet_mode_controller()->InTabletMode());
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc
index 4a9b9e8..0ea54d0 100644
--- a/ash/app_list/views/app_list_folder_view.cc
+++ b/ash/app_list/views/app_list_folder_view.cc
@@ -34,7 +34,9 @@
 #include "ash/public/cpp/metrics_util.h"
 #include "ash/public/cpp/pagination/pagination_model.h"
 #include "ash/public/cpp/style/color_provider.h"
+#include "ash/public/cpp/view_shadow.h"
 #include "ash/strings/grit/ash_strings.h"
+#include "ash/style/highlight_border.h"
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/check.h"
@@ -77,6 +79,8 @@
 
 constexpr int kTileSpacingInFolder = 8;
 
+constexpr int kShadowElevation = 3;
+
 // Insets for the vertical scroll bar. The top is pushed down slightly to align
 // with the icons, which keeps the scroll bar out of the rounded corner area.
 constexpr auto kVerticalScrollInsets =
@@ -87,16 +91,31 @@
 // for flying in or out the folder.
 constexpr base::TimeDelta kFolderTransitionDuration = base::Milliseconds(250);
 
+// A utility function for `background_view` to update its background color.
+void SetBackgroundViewColor(views::View* background_view,
+                            SkColor color,
+                            bool is_productivity_launcher_enabled) {
+  if (is_productivity_launcher_enabled) {
+    background_view->SetBackground(color == SK_ColorTRANSPARENT
+                                       ? nullptr
+                                       : views::CreateSolidBackground(color));
+  } else {
+    background_view->layer()->SetColor(color);
+  }
+}
+
 // Transit from the background of the folder item's icon to the opened
 // folder's background when opening the folder. Transit the other way when
 // closing the folder.
 class BackgroundAnimation : public AppListFolderView::Animation,
                             public ui::ImplicitAnimationObserver {
  public:
-  BackgroundAnimation(bool show,
+  BackgroundAnimation(bool is_productivity_launcher_enabled,
+                      bool show,
                       AppListFolderView* folder_view,
                       views::View* background_view)
-      : show_(show),
+      : is_productivity_launcher_enabled_(is_productivity_launcher_enabled),
+        show_(show),
         folder_view_(folder_view),
         background_view_(background_view) {}
 
@@ -131,7 +150,8 @@
     const SkColor from_color = show_ ? bubble_color : background_color;
     const SkColor to_color = show_ ? background_color : bubble_color;
 
-    background_view_->layer()->SetColor(from_color);
+    SetBackgroundViewColor(background_view_, from_color,
+                           is_productivity_launcher_enabled_);
     background_view_->layer()->SetClipRect(from_rect);
     background_view_->layer()->SetRoundedCornerRadius(
         gfx::RoundedCornersF(from_radius));
@@ -141,7 +161,8 @@
     settings.SetTransitionDuration(kFolderTransitionDuration);
     settings.SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
     settings.AddObserver(this);
-    background_view_->layer()->SetColor(to_color);
+    SetBackgroundViewColor(background_view_, to_color,
+                           is_productivity_launcher_enabled_);
     background_view_->layer()->SetClipRect(to_rect);
     background_view_->layer()->SetRoundedCornerRadius(
         gfx::RoundedCornersF(to_radius));
@@ -151,7 +172,18 @@
   bool IsAnimationRunning() override { return is_animating_; }
 
   // ui::ImplicitAnimationObserver:
+  void OnImplicitAnimationsScheduled() override {
+    // Remove the border and shadow at the start of the closing animation.
+    if (is_productivity_launcher_enabled_ && !show_)
+      folder_view_->UpdateBorderAndShadow(false);
+  }
+
+  // ui::ImplicitAnimationObserver:
   void OnImplicitAnimationsCompleted() override {
+    // Add the border and shadow when the showing animation is completed.
+    if (is_productivity_launcher_enabled_ && show_)
+      folder_view_->UpdateBorderAndShadow(true);
+
     is_animating_ = false;
     folder_view_->RecordAnimationSmoothness();
 
@@ -159,9 +191,11 @@
       std::move(completion_callback_).Run();
   }
 
+  // Caches the productivity launcher feature flag.
+  bool is_productivity_launcher_enabled_ = false;
+
   // True if opening the folder.
   const bool show_;
-
   bool is_animating_ = false;
 
   AppListFolderView* const folder_view_;  // Not owned.
@@ -594,7 +628,9 @@
                                      ContentsView* contents_view,
                                      AppListA11yAnnouncer* a11y_announcer,
                                      AppListViewDelegate* view_delegate)
-    : folder_controller_(folder_controller),
+    : is_productivity_launcher_enabled_(
+          features::IsProductivityLauncherEnabled()),
+      folder_controller_(folder_controller),
       root_apps_grid_view_(root_apps_grid_view),
       a11y_announcer_(a11y_announcer),
       view_delegate_(view_delegate) {
@@ -608,7 +644,9 @@
   // contents container using layer animation, so use another layer to perform
   // such changes.
   background_view_ = AddChildView(std::make_unique<views::View>());
-  background_view_->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
+  background_view_->SetPaintToLayer(is_productivity_launcher_enabled_
+                                        ? ui::LAYER_TEXTURED
+                                        : ui::LAYER_SOLID_COLOR);
   background_view_->layer()->SetFillsBoundsOpaquely(false);
   background_view_->layer()->SetBackgroundBlur(
       ColorProvider::kBackgroundBlurSigma);
@@ -618,7 +656,7 @@
   contents_container_ = AddChildView(std::make_unique<views::View>());
   contents_container_->SetPaintToLayer(ui::LAYER_NOT_DRAWN);
 
-  if (features::IsProductivityLauncherEnabled())
+  if (is_productivity_launcher_enabled_)
     CreateScrollableAppsGrid();
   else
     CreatePagedAppsGrid(contents_view);
@@ -779,7 +817,7 @@
             "Apps.AppListFolder.ShowHide.AnimationSmoothness", smoothness);
       })));
 
-  if (!features::IsProductivityLauncherEnabled()) {
+  if (!is_productivity_launcher_enabled_) {
     static_cast<PagedAppsGridView*>(items_grid_view_)
         ->pagination_model()
         ->SelectPage(0, false);
@@ -794,8 +832,8 @@
   NotifyAccessibilityEvent(ax::mojom::Event::kStateChanged, true);
 
   // Animate the background corner radius, opacity and bounds.
-  folder_visibility_animations_.push_back(
-      std::make_unique<BackgroundAnimation>(show, this, background_view_));
+  folder_visibility_animations_.push_back(std::make_unique<BackgroundAnimation>(
+      is_productivity_launcher_enabled_, show, this, background_view_));
 
   // Animate the folder item's title's opacity.
   folder_visibility_animations_.push_back(
@@ -925,7 +963,8 @@
 
   // Transition all the states immediately to the end of folder closing
   // animation.
-  background_view_->layer()->SetColor(SK_ColorTRANSPARENT);
+  SetBackgroundViewColor(background_view_, SK_ColorTRANSPARENT,
+                         is_productivity_launcher_enabled_);
   if (restore_folder_item_view_state && folder_item_view_) {
     folder_item_view_->SetIconVisible(true);
     folder_item_view_->title()->SetEnabledColor(
@@ -968,6 +1007,24 @@
     std::move(animation_done_test_callback_).Run();
 }
 
+void AppListFolderView::UpdateBorderAndShadow(bool show) {
+  if (!show) {
+    view_shadow_.reset();
+    background_view_->SetBorder(nullptr);
+    return;
+  }
+
+  // Add a shadow to the folder view.
+  view_shadow_ =
+      std::make_unique<ViewShadow>(background_view_, kShadowElevation);
+  view_shadow_->SetRoundedCornerRadius(
+      GetAppListConfig()->folder_background_radius());
+  background_view_->SetBorder(std::make_unique<HighlightBorder>(
+      GetAppListConfig()->folder_background_radius(),
+      HighlightBorder::Type::kHighlightBorder1,
+      /*use_light_colors=*/true));
+}
+
 void AppListFolderView::UpdatePreferredBounds() {
   if (!folder_item_view_)
     return;
@@ -1263,7 +1320,7 @@
   // Productivity launcher uses scrollable grid for folders, which handles the
   // case where the items grid does not fit into bounds provided by the folder
   // bounding box.
-  if (features::IsProductivityLauncherEnabled())
+  if (is_productivity_launcher_enabled_)
     return;
 
   if (bounding_box_.IsEmpty() || !GetAppListConfig())
diff --git a/ash/app_list/views/app_list_folder_view.h b/ash/app_list/views/app_list_folder_view.h
index 5261de2..13ec82da 100644
--- a/ash/app_list/views/app_list_folder_view.h
+++ b/ash/app_list/views/app_list_folder_view.h
@@ -38,6 +38,7 @@
 class FolderHeaderView;
 class PageSwitcher;
 class ScrollViewGradientHelper;
+class ViewShadow;
 
 // Displays folder contents via an AppsGridView. App items can be dragged out
 // of the folder to the main apps grid.
@@ -144,6 +145,10 @@
   // to be in the parent view's coordinate system.
   void SetBoundingBox(const gfx::Rect& bounding_box);
 
+  // Updates the border and shadow of the folder view according to the folder
+  // animation.
+  void UpdateBorderAndShadow(bool show);
+
   // Sets the callback that runs when the folder animation ends.
   void SetAnimationDoneTestCallback(base::OnceClosure animation_done_callback);
 
@@ -247,6 +252,9 @@
   // the root grid view.
   void OnHideAnimationDone(bool hide_for_reparent);
 
+  // Caches the feature flag to check if the productivity launcher is enabled.
+  bool is_productivity_launcher_enabled_ = false;
+
   // Controller interface implemented by the container for this view.
   AppListFolderController* const folder_controller_;
 
@@ -288,6 +296,8 @@
   // The folder item in the root apps grid associated with this folder.
   AppListItemView* folder_item_view_ = nullptr;
 
+  std::unique_ptr<ViewShadow> view_shadow_;
+
   // The bounds of the activated folder item icon relative to this view.
   gfx::Rect folder_item_icon_bounds_;
 
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc
index e4e39bbf..3216c640 100644
--- a/ash/app_list/views/search_result_view.cc
+++ b/ash/app_list/views/search_result_view.cc
@@ -88,6 +88,7 @@
 views::ImageView* SetupChildImageView(views::FlexLayoutView* parent) {
   views::ImageView* image_view =
       parent->AddChildView(std::make_unique<views::ImageView>());
+  image_view->GetViewAccessibility().OverrideIsIgnored(true);
   image_view->SetCanProcessEventsWithinSubtree(false);
   image_view->SetVerticalAlignment(views::ImageView::Alignment::kCenter);
   image_view->SetVisible(false);
@@ -100,6 +101,9 @@
     SearchResultView::LabelType label_type) {
   // Create and setup label.
   views::Label* label = parent->AddChildView(std::make_unique<views::Label>());
+  // Ignore labels for accessibility - the result accessible name is defined on
+  // the whole result view.
+  label->GetViewAccessibility().OverrideIsIgnored(true);
   label->SetBackgroundColor(SK_ColorTRANSPARENT);
   label->SetVisible(false);
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -128,6 +132,7 @@
   SearchResultInlineIconView* inline_icon_view =
       parent->AddChildView(std::make_unique<SearchResultInlineIconView>());
   inline_icon_view->SetCanProcessEventsWithinSubtree(false);
+  inline_icon_view->GetViewAccessibility().OverrideIsIgnored(true);
   inline_icon_view->SetVisible(false);
   inline_icon_view->SetProperty(
       views::kFlexBehaviorKey,
@@ -239,14 +244,13 @@
   set_actions_view(actions_view);
 
   icon_->SetCanProcessEventsWithinSubtree(false);
+  icon_->GetViewAccessibility().OverrideIsIgnored(true);
   badge_icon_->SetCanProcessEventsWithinSubtree(false);
+  badge_icon_->GetViewAccessibility().OverrideIsIgnored(true);
 
   SetNotifyEnterExitOnChild(true);
 
   text_container_ = AddChildView(std::make_unique<views::FlexLayoutView>());
-  // View contents are announced as part of the result view's accessible name.
-  text_container_->GetViewAccessibility().OverrideIsLeaf(true);
-  text_container_->GetViewAccessibility().OverrideIsIgnored(true);
   text_container_->SetCrossAxisAlignment(views::LayoutAlignment::kStretch);
   text_container_->SetOrientation(views::LayoutOrientation::kHorizontal);
 
@@ -282,6 +286,7 @@
                                          view_type_, LabelType::kDetails);
   separator_label_->SetText(
       l10n_util::GetStringUTF16(IDS_ASH_SEARCH_RESULT_SEPARATOR));
+  separator_label_->GetViewAccessibility().OverrideIsIgnored(true);
 
   details_container_ = title_and_details_container_->AddChildView(
       std::make_unique<views::FlexLayoutView>());
diff --git a/ash/ash_prefs.cc b/ash/ash_prefs.cc
index cb1e2ef..4aa5c1a0 100644
--- a/ash/ash_prefs.cc
+++ b/ash/ash_prefs.cc
@@ -57,6 +57,7 @@
 #include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/live_caption/pref_names.h"
+#include "components/soda/constants.h"
 
 namespace ash {
 
@@ -117,6 +118,8 @@
     registry->RegisterBooleanPref(chromeos::prefs::kSuggestedContentEnabled,
                                   true);
     registry->RegisterBooleanPref(::prefs::kLiveCaptionEnabled, false);
+    registry->RegisterStringPref(::prefs::kLiveCaptionLanguageCode,
+                                 speech::kUsEnglishLocale);
     registry->RegisterStringPref(language::prefs::kApplicationLocale,
                                  std::string());
   }
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index b5c444c..1d4a2b28 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -453,6 +453,12 @@
       <message name="IDS_ASH_STATUS_TRAY_DARK_THEME_ON_STATE" desc="Button label for the Dark theme feature." meaning="Dark theme feature is on. [CHAR_LIMIT=14]">
         On
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_DARK_THEME_ON_STATE_AUTO_SCHEDULED" desc="Button label for the Dark theme feature when auto scheduling is enabled." meaning="Dark mode is automatically scheduled to be on until sunrise. [CHAR_LIMIT=16]">
+        On until sunrise
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_DARK_THEME_OFF_STATE_AUTO_SCHEDULED" desc="Button label for the Dark theme feature when auto scheduling is enabled." meaning="Dark mode is automatically scheduled to be off until sunset. [CHAR_LIMIT=16]">
+        Off until sunset
+      </message>
       <message name="IDS_ASH_STATUS_TRAY_CAST_CAST_DESKTOP_ACCESSIBILITY_STOP" desc="Stop button accessibility label used in the tray popup to tell the user to stop a cast to the desktop.">
         Stop casting screen to <ph name="RECEIVER_NAME">$1<ex>Living Room</ex></ph>
       </message>
@@ -3880,6 +3886,9 @@
       <message name="IDS_ASH_SCREEN_CAPTURE_POLICY_DISABLED_TITLE" desc="The title of the notification when capture mode is disabled because of a policy.">
         Can't capture content
       </message>
+      <message name="IDS_ASH_SCREEN_CAPTURE_MANAGED_BY_POLICY" desc="The title of the tooltip for a setting that is managed by a policy controlled by the admin.">
+        This setting is managed by your administrator
+      </message>
       <message name="IDS_ASH_SCREEN_CAPTURE_FAILURE_TITLE" desc="The title of the notification when capture mode fails.">
         An error occurred
       </message>
@@ -4377,13 +4386,13 @@
       </message>
 
       <!-- SODA Download strings -->
-      <message name="IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE" desc="Description explaining that the speech recognition library download has completed.">
+      <message name="IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE" desc="Description explaining that the speech recognition library download has completed.">
         Speech files downloaded
       </message>
-      <message name="IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS" desc="Description explaining the progress for the speech recognition library download.">
+      <message name="IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS" desc="Description explaining the progress for the speech recognition library download.">
         Downloading speech recognition files... <ph name="PERCENT">$1<ex>17</ex></ph>%
       </message>
-      <message name="IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR" desc="Description explaining that there was an error with the speech recognition library download.">
+      <message name="IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR" desc="Description explaining that there was an error with the speech recognition library download.">
         Can't download speech files. Try again later.
       </message>
       <message name="IDS_ASH_ACCESSIBILITY_DICTATION_BUTTON_TOOLTIP_SODA_DOWNLOADING" desc="A tooltip explaining that speech recognition files are downloading." >
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE.png.sha1
similarity index 100%
rename from ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE.png.sha1
rename to ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE.png.sha1
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR.png.sha1
similarity index 100%
rename from ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR.png.sha1
rename to ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR.png.sha1
diff --git a/ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS.png.sha1 b/ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS.png.sha1
similarity index 100%
rename from ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS.png.sha1
rename to ash/ash_strings_grd/IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS.png.sha1
diff --git a/ash/ash_strings_grd/IDS_ASH_SCREEN_CAPTURE_MANAGED_BY_POLICY.png.sha1 b/ash/ash_strings_grd/IDS_ASH_SCREEN_CAPTURE_MANAGED_BY_POLICY.png.sha1
new file mode 100644
index 0000000..8705e48
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_SCREEN_CAPTURE_MANAGED_BY_POLICY.png.sha1
@@ -0,0 +1 @@
+917ef49911d0966bea6d26163799e1d266f71b4d
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DARK_THEME_OFF_STATE_AUTO_SCHEDULED.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DARK_THEME_OFF_STATE_AUTO_SCHEDULED.png.sha1
new file mode 100644
index 0000000..3dbc5d0
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DARK_THEME_OFF_STATE_AUTO_SCHEDULED.png.sha1
@@ -0,0 +1 @@
+bdf636dc9512d2d9873945b213c03bebabf5a41c
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DARK_THEME_ON_STATE_AUTO_SCHEDULED.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DARK_THEME_ON_STATE_AUTO_SCHEDULED.png.sha1
new file mode 100644
index 0000000..6f571ad
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_DARK_THEME_ON_STATE_AUTO_SCHEDULED.png.sha1
@@ -0,0 +1 @@
+0c768a66fe0ee51cd9c80abcb8fbed79f03b4bd6
\ No newline at end of file
diff --git a/ash/capture_mode/capture_mode_camera_controller.cc b/ash/capture_mode/capture_mode_camera_controller.cc
index 9449593..d945973 100644
--- a/ash/capture_mode/capture_mode_camera_controller.cc
+++ b/ash/capture_mode/capture_mode_camera_controller.cc
@@ -248,6 +248,10 @@
   observers_.RemoveObserver(observer);
 }
 
+bool CaptureModeCameraController::IsCameraDisabledByPolicy() const {
+  return delegate_->IsCameraDisabledByPolicy();
+}
+
 std::string CaptureModeCameraController::GetDisplayNameOfSelectedCamera()
     const {
   if (selected_camera_.is_valid()) {
@@ -260,6 +264,13 @@
 }
 
 void CaptureModeCameraController::SetSelectedCamera(CameraId camera_id) {
+  // When cameras are disabled by policy, we don't allow any camera selection.
+  if (IsCameraDisabledByPolicy()) {
+    LOG(WARNING) << "Camera is disabled by policy. Selecting camera: "
+                 << camera_id.ToString() << " will be ignored.";
+    camera_id = CameraId{};
+  }
+
   if (selected_camera_ == camera_id)
     return;
 
@@ -526,6 +537,8 @@
     camera_preview_view_ = nullptr;
   }
 
+  DCHECK(!IsCameraDisabledByPolicy());
+
   if (!camera_preview_widget_) {
     const auto preview_bounds = GetPreviewWidgetBounds();
     camera_preview_widget_ = std::make_unique<views::Widget>();
diff --git a/ash/capture_mode/capture_mode_camera_controller.h b/ash/capture_mode/capture_mode_camera_controller.h
index d889d3db..258c1b6 100644
--- a/ash/capture_mode/capture_mode_camera_controller.h
+++ b/ash/capture_mode/capture_mode_camera_controller.h
@@ -148,6 +148,10 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
+  // Returns true if camera support is disabled by admins via
+  // the `SystemFeaturesDisableList` policy, false otherwise.
+  bool IsCameraDisabledByPolicy() const;
+
   // Returns the display name of `selected_camera_`. Returns an empty string if
   // the selected camera is not set.
   std::string GetDisplayNameOfSelectedCamera() const;
diff --git a/ash/capture_mode/capture_mode_camera_unittests.cc b/ash/capture_mode/capture_mode_camera_unittests.cc
index faf715fed..175a7bb 100644
--- a/ash/capture_mode/capture_mode_camera_unittests.cc
+++ b/ash/capture_mode/capture_mode_camera_unittests.cc
@@ -629,6 +629,42 @@
   EXPECT_FALSE(camera_controller->should_show_preview());
 }
 
+TEST_F(CaptureModeCameraTest, ManagedByPolicyCameraOptions) {
+  GetTestDelegate()->set_is_camera_disabled_by_policy(true);
+
+  StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
+  OpenSettingsView();
+
+  // At this moment, there are no camera devices connected. The camera menu
+  // group should be hidden.
+  CaptureModeSettingsTestApi test_api;
+  CaptureModeMenuGroup* camera_menu_group = test_api.GetCameraMenuGroup();
+  ASSERT_TRUE(camera_menu_group);
+  EXPECT_FALSE(camera_menu_group->GetVisible());
+
+  // Camera addition/removal are still observed even when managed by policy, but
+  // once a camera is added, the group becomes visible, but shows only a dimmed
+  // "Off" option.
+  AddDefaultCamera();
+  EXPECT_TRUE(camera_menu_group->GetVisible());
+  EXPECT_TRUE(camera_menu_group->IsOptionChecked(kCameraOff));
+  EXPECT_FALSE(camera_menu_group->IsOptionEnabled(kCameraOff));
+  EXPECT_FALSE(test_api.GetCameraOption(kCameraDevicesBegin));
+
+  // Selecting a camera will be ignored.
+  auto* camera_controller = GetCameraController();
+  camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
+  EXPECT_FALSE(camera_controller->selected_camera().is_valid());
+  EXPECT_TRUE(camera_menu_group->IsOptionChecked(kCameraOff));
+  EXPECT_FALSE(camera_controller->camera_preview_widget());
+
+  // Removing the existing camera should hide the camera menu group and remove
+  // all its options.
+  RemoveDefaultCamera();
+  EXPECT_FALSE(camera_menu_group->GetVisible());
+  EXPECT_FALSE(test_api.GetCameraOption(kCameraOff));
+}
+
 // Tests that the options on camera menu are shown and checked correctly when
 // adding or removing cameras. Also tests that `selected_camera_` is updated
 // correspondently.
diff --git a/ash/capture_mode/capture_mode_menu_group.cc b/ash/capture_mode/capture_mode_menu_group.cc
index 9fe8119..a0da31ce 100644
--- a/ash/capture_mode/capture_mode_menu_group.cc
+++ b/ash/capture_mode/capture_mode_menu_group.cc
@@ -17,6 +17,7 @@
 #include "base/containers/cxx20_erase_vector.h"
 #include "base/ranges/algorithm.h"
 #include "ui/accessibility/ax_enums.mojom-shared.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/accessibility/view_accessibility.h"
@@ -80,19 +81,34 @@
   METADATA_HEADER(CaptureModeMenuHeader);
 
   CaptureModeMenuHeader(const gfx::VectorIcon& icon,
-                        std::u16string header_laber)
+                        std::u16string header_laber,
+                        bool managed_by_policy)
       : icon_view_(AddChildView(std::make_unique<views::ImageView>())),
         label_view_(AddChildView(
-            std::make_unique<views::Label>(std::move(header_laber)))) {
+            std::make_unique<views::Label>(std::move(header_laber)))),
+        managed_icon_view_(
+            managed_by_policy
+                ? AddChildView(std::make_unique<views::ImageView>())
+                : nullptr) {
     icon_view_->SetImageSize(kIconSize);
     icon_view_->SetPreferredSize(kIconSize);
-    icon_view_->SetImage(gfx::CreateVectorIcon(
-        icon, AshColorProvider::Get()->GetContentLayerColor(
-                  AshColorProvider::ContentLayerType::kButtonIconColor)));
+    const auto icon_color = AshColorProvider::Get()->GetContentLayerColor(
+        AshColorProvider::ContentLayerType::kButtonIconColor);
+    icon_view_->SetImage(gfx::CreateVectorIcon(icon, icon_color));
+
+    if (managed_icon_view_) {
+      managed_icon_view_->SetImageSize(kIconSize);
+      managed_icon_view_->SetPreferredSize(kIconSize);
+      managed_icon_view_->SetImage(
+          gfx::CreateVectorIcon(kCaptureModeManagedIcon, icon_color));
+      managed_icon_view_->SetTooltipText(
+          l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_MANAGED_BY_POLICY));
+    }
 
     SetBorder(views::CreateEmptyBorder(kMenuHeaderPadding));
     ConfigLabelView(label_view_);
-    CreateAndInitBoxLayoutForView(this);
+    auto* box_layout = CreateAndInitBoxLayoutForView(this);
+    box_layout->SetFlexForView(label_view_, 1);
   }
 
   CaptureModeMenuHeader(const CaptureModeMenuHeader&) = delete;
@@ -116,6 +132,9 @@
  private:
   views::ImageView* icon_view_;
   views::Label* label_view_;
+  // `nullptr` if the menu group is not for a setting that is managed by a
+  // policy.
+  views::ImageView* managed_icon_view_;
 };
 
 BEGIN_METADATA(CaptureModeMenuHeader, views::View)
@@ -184,10 +203,6 @@
         id_(option_id) {
     checked_icon_view_->SetImageSize(kIconSize);
     checked_icon_view_->SetPreferredSize(kIconSize);
-    checked_icon_view_->SetImage(gfx::CreateVectorIcon(
-        kHollowCheckCircleIcon,
-        AshColorProvider::Get()->GetContentLayerColor(
-            AshColorProvider::ContentLayerType::kButtonLabelColorBlue)));
 
     SetBorder(views::CreateEmptyBorder(kOptionPadding));
     ConfigLabelView(label_view_);
@@ -198,7 +213,14 @@
     SetAccessibleName(GetOptionLabel());
 
     checked_icon_view_->SetVisible(checked);
-    SetEnabled(enabled);
+
+    // Calling `SetEnabled()` will result in calling `UpdateState()` only when
+    // the state changes, but by default the view's state is enabled, so we only
+    // need to call `UpdateState()` explicitly if `enabled` is true.
+    if (enabled)
+      UpdateState();
+    else
+      SetEnabled(false);
   }
 
   CaptureModeOption(const CaptureModeOption&) = delete;
@@ -223,14 +245,7 @@
   bool IsOptionChecked() { return checked_icon_view_->GetVisible(); }
 
   // views::Button:
-  void StateChanged(ButtonState old_state) override {
-    auto* provider = AshColorProvider::Get();
-    const auto enabled_color = provider->GetContentLayerColor(
-        AshColorProvider::ContentLayerType::kTextColorPrimary);
-    label_view_->SetEnabledColor(GetState() == STATE_DISABLED
-                                     ? provider->GetDisabledColor(enabled_color)
-                                     : enabled_color);
-  }
+  void StateChanged(ButtonState old_state) override { UpdateState(); }
 
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
     Button::GetAccessibleNodeData(node_data);
@@ -245,6 +260,23 @@
   views::View* GetView() override { return this; }
 
  private:
+  // Dims out the label and the checked icon if this view is disabled.
+  void UpdateState() {
+    auto* provider = AshColorProvider::Get();
+    const auto label_enabled_color = provider->GetContentLayerColor(
+        AshColorProvider::ContentLayerType::kTextColorPrimary);
+    const auto icon_enabled_color = provider->GetContentLayerColor(
+        AshColorProvider::ContentLayerType::kButtonLabelColorBlue);
+    const bool is_disabled = GetState() == STATE_DISABLED;
+    label_view_->SetEnabledColor(
+        is_disabled ? provider->GetDisabledColor(label_enabled_color)
+                    : label_enabled_color);
+    checked_icon_view_->SetImage(gfx::CreateVectorIcon(
+        kHollowCheckCircleIcon,
+        is_disabled ? provider->GetDisabledColor(icon_enabled_color)
+                    : icon_enabled_color));
+  }
+
   views::Label* label_view_;
   views::ImageView* checked_icon_view_;
   const int id_;
@@ -258,11 +290,13 @@
 
 CaptureModeMenuGroup::CaptureModeMenuGroup(Delegate* delegate,
                                            const gfx::VectorIcon& header_icon,
-                                           std::u16string header_label)
+                                           std::u16string header_label,
+                                           bool managed_by_policy)
     : delegate_(delegate),
       menu_header_(AddChildView(
           std::make_unique<CaptureModeMenuHeader>(header_icon,
-                                                  std::move(header_label)))) {
+                                                  std::move(header_label),
+                                                  managed_by_policy))) {
   options_container_ = AddChildView(std::make_unique<views::View>());
   options_container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical));
@@ -330,6 +364,11 @@
   return option && option->IsOptionChecked();
 }
 
+bool CaptureModeMenuGroup::IsOptionEnabled(int option_id) const {
+  auto* option = GetOptionById(option_id);
+  return option && option->GetEnabled();
+}
+
 void CaptureModeMenuGroup::AppendHighlightableItems(
     std::vector<CaptureModeSessionFocusCycler::HighlightableView*>&
         highlightable_items) {
diff --git a/ash/capture_mode/capture_mode_menu_group.h b/ash/capture_mode/capture_mode_menu_group.h
index 437c1e1f..13a6dce 100644
--- a/ash/capture_mode/capture_mode_menu_group.h
+++ b/ash/capture_mode/capture_mode_menu_group.h
@@ -45,9 +45,12 @@
     virtual ~Delegate() = default;
   };
 
+  // If `managed_by_policy` is true, the header of this menu group will show an
+  // enterprise-managed feature icon next to the `header_label`.
   CaptureModeMenuGroup(Delegate* delegate,
                        const gfx::VectorIcon& header_icon,
-                       std::u16string header_label);
+                       std::u16string header_label,
+                       bool managed_by_policy = false);
   CaptureModeMenuGroup(const CaptureModeMenuGroup&) = delete;
   CaptureModeMenuGroup& operator=(const CaptureModeMenuGroup&) = delete;
   ~CaptureModeMenuGroup() override;
@@ -81,10 +84,14 @@
   void AddMenuItem(views::Button::PressedCallback callback,
                    std::u16string item_label);
 
-  // Returns true if the option with the given |option_id| is checked, if such
+  // Returns true if the option with the given `option_id` is checked, if such
   // option exists.
   bool IsOptionChecked(int option_id) const;
 
+  // Returns true if the option with the given `option_id` is enabled, if such
+  // option exists.
+  bool IsOptionEnabled(int option_id) const;
+
   // Appends the enabled items from `options_` and `menu_items_` to the given
   // `highlightable_items`.
   void AppendHighlightableItems(
diff --git a/ash/capture_mode/capture_mode_settings_view.cc b/ash/capture_mode/capture_mode_settings_view.cc
index 11101b7..42f1514 100644
--- a/ash/capture_mode/capture_mode_settings_view.cc
+++ b/ash/capture_mode/capture_mode_settings_view.cc
@@ -87,14 +87,18 @@
     separator_1_ = AddChildView(std::make_unique<views::Separator>());
     separator_1_->SetColor(separator_color);
     auto* camera_controller = controller->camera_controller();
+    const bool managed_by_policy =
+        camera_controller->IsCameraDisabledByPolicy();
+    // Even if the camera feature is managed by policy, we still want to observe
+    // the camera controller, since we need to be notified with camera additions
+    // and removals, which affect the visibility of the `camera_menu_group_`.
     camera_controller->AddObserver(this);
     camera_menu_group_ = AddChildView(std::make_unique<CaptureModeMenuGroup>(
         this, kCaptureModeCameraIcon,
-        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_CAMERA)));
+        l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_CAMERA),
+        managed_by_policy));
 
-    const CameraInfoList& cameras = camera_controller->available_cameras();
-
-    AddCameraOptions(cameras);
+    AddCameraOptions(camera_controller->available_cameras(), managed_by_policy);
   }
 
   if (!is_in_projector_mode) {
@@ -219,6 +223,7 @@
       camera_controller->SetSelectedCamera(CameraId());
       break;
     default:
+      DCHECK(!camera_controller->IsCameraDisabledByPolicy());
       DCHECK_GE(option_id, kCameraDevicesBegin);
       const CameraId* camera_id = FindCameraIdByOptionId(option_id);
       DCHECK(camera_id);
@@ -244,6 +249,7 @@
     case kCameraOff:
       return !camera_controller->selected_camera().is_valid();
     default:
+      DCHECK(!camera_controller->IsCameraDisabledByPolicy());
       DCHECK_GE(option_id, kCameraDevicesBegin);
       const CameraId* camera_id = FindCameraIdByOptionId(option_id);
       DCHECK(camera_id);
@@ -257,9 +263,14 @@
       return !capture_mode_session_->is_in_projector_mode();
     case kCustomFolder:
       return is_custom_folder_available_.value_or(false);
+    case kCameraOff: {
+      auto* camera_controller =
+          CaptureModeController::Get()->camera_controller();
+      DCHECK(camera_controller);
+      return !camera_controller->IsCameraDisabledByPolicy();
+    }
     case kAudioMicrophone:
     case kDownloadsFolder:
-    case kCameraOff:
     default:
       return true;
   }
@@ -267,9 +278,12 @@
 
 void CaptureModeSettingsView::OnAvailableCamerasChanged(
     const CameraInfoList& cameras) {
-  DCHECK(!CaptureModeController::Get()->is_recording_in_progress());
+  auto* controller = CaptureModeController::Get();
+  DCHECK(!controller->is_recording_in_progress());
   DCHECK(camera_menu_group_);
-  AddCameraOptions(cameras);
+  auto* camera_controller = controller->camera_controller();
+  DCHECK(camera_controller);
+  AddCameraOptions(cameras, camera_controller->IsCameraDisabledByPolicy());
 
   // If the size of the given `cameras` is equal to the size of the current
   // available cameras, the bounds of the `camera_menu_group_` won't be updated,
@@ -320,7 +334,8 @@
   return nullptr;
 }
 
-void CaptureModeSettingsView::AddCameraOptions(const CameraInfoList& cameras) {
+void CaptureModeSettingsView::AddCameraOptions(const CameraInfoList& cameras,
+                                               bool managed_by_policy) {
   DCHECK(camera_menu_group_);
   camera_menu_group_->DeleteOptions();
   option_camera_id_map_.clear();
@@ -329,11 +344,14 @@
     camera_menu_group_->AddOption(
         l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_CAMERA_OFF),
         kCameraOff);
-    int camera_option_id_begin = kCameraDevicesBegin;
-    for (const CameraInfo& camera_info : cameras) {
-      option_camera_id_map_[camera_option_id_begin] = camera_info.camera_id;
-      camera_menu_group_->AddOption(base::UTF8ToUTF16(camera_info.display_name),
-                                    camera_option_id_begin++);
+    if (!managed_by_policy) {
+      int camera_option_id_begin = kCameraDevicesBegin;
+      for (const CameraInfo& camera_info : cameras) {
+        option_camera_id_map_[camera_option_id_begin] = camera_info.camera_id;
+        camera_menu_group_->AddOption(
+            base::UTF8ToUTF16(camera_info.display_name),
+            camera_option_id_begin++);
+      }
     }
   }
   UpdateCameraMenuGroupVisibility(/*visible=*/has_cameras);
@@ -347,4 +365,4 @@
 BEGIN_METADATA(CaptureModeSettingsView, views::View)
 END_METADATA
 
-}  // namespace ash
\ No newline at end of file
+}  // namespace ash
diff --git a/ash/capture_mode/capture_mode_settings_view.h b/ash/capture_mode/capture_mode_settings_view.h
index 4686851e6..e388de9 100644
--- a/ash/capture_mode/capture_mode_settings_view.h
+++ b/ash/capture_mode/capture_mode_settings_view.h
@@ -114,7 +114,11 @@
   // `camera_menu_group_` before adding options. Called when initializing `this`
   // or `OnAvailableCamerasChanged` is triggered. It will also trigger
   // `UpdateCameraMenuGroupVisibility` at the end.
-  void AddCameraOptions(const CameraInfoList& cameras);
+  // Note that camera options are only added when `cameras` is not empty.
+  // When cameras are disabled by policy (i.e. `managed_by_policy` is true),
+  // only the "Off" option is added. Users are not allowed to choose any cameras
+  // in that case.
+  void AddCameraOptions(const CameraInfoList& cameras, bool managed_by_policy);
 
   void UpdateCameraMenuGroupVisibility(bool visible);
 
diff --git a/ash/capture_mode/test_capture_mode_delegate.cc b/ash/capture_mode/test_capture_mode_delegate.cc
index 1d728f9..e281ec1 100644
--- a/ash/capture_mode/test_capture_mode_delegate.cc
+++ b/ash/capture_mode/test_capture_mode_delegate.cc
@@ -178,4 +178,8 @@
   std::move(callback).Run(fake_drive_fs_free_bytes_);
 }
 
+bool TestCaptureModeDelegate::IsCameraDisabledByPolicy() const {
+  return is_camera_disabled_by_policy_;
+}
+
 }  // namespace ash
diff --git a/ash/capture_mode/test_capture_mode_delegate.h b/ash/capture_mode/test_capture_mode_delegate.h
index d15024009..d039bbe 100644
--- a/ash/capture_mode/test_capture_mode_delegate.h
+++ b/ash/capture_mode/test_capture_mode_delegate.h
@@ -49,6 +49,9 @@
   void set_should_save_after_dlp_check(bool value) {
     should_save_after_dlp_check_ = value;
   }
+  void set_is_camera_disabled_by_policy(bool value) {
+    is_camera_disabled_by_policy_ = value;
+  }
   void set_fake_drive_fs_free_bytes(int64_t bytes) {
     fake_drive_fs_free_bytes_ = bytes;
   }
@@ -108,6 +111,7 @@
       mojo::PendingReceiver<video_capture::mojom::VideoSourceProvider> receiver)
       override;
   void GetDriveFsFreeSpaceBytes(OnGotDriveFsFreeSpace callback) override;
+  bool IsCameraDisabledByPolicy() const override;
 
  private:
   std::unique_ptr<recording::RecordingServiceTestApi> recording_service_;
@@ -118,6 +122,7 @@
   bool is_allowed_by_dlp_ = true;
   bool is_allowed_by_policy_ = true;
   bool should_save_after_dlp_check_ = true;
+  bool is_camera_disabled_by_policy_ = false;
   base::ScopedTempDir fake_drive_fs_mount_path_;
   base::ScopedTempDir fake_android_files_path_;
   base::ScopedTempDir fake_linux_files_path_;
diff --git a/ash/components/arc/mojom/enterprise_reporting.mojom b/ash/components/arc/mojom/enterprise_reporting.mojom
index ac93f2d8..1213b27 100644
--- a/ash/components/arc/mojom/enterprise_reporting.mojom
+++ b/ash/components/arc/mojom/enterprise_reporting.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 3
+// Next MinVersion: 4
 module arc.mojom;
 
 // Enumerates the states that management can be in for a user.
@@ -19,10 +19,33 @@
   MANAGED_DO_LOST = 2
 };
 
-// Next method ID: 1
+[Extensible]
+enum TimedCloudDpcOp {
+  [Default] UNKNOWN_OP = 0,
+  DEVICE_SETUP = 1,
+  SETUP_TOTAL = 2,
+  SETUP_CHECK_FOR_ANDROID_ID = 3,
+  SETUP_CHECK_FOR_FIRST_ACCOUNT_READY = 4,
+  SETUP_REGISTER = 5,
+  SETUP_PULL_AND_APPLY_POLICIES = 6,
+  SETUP_REPORT_POLICY_COMPLIANCE = 7,
+  SETUP_QUARANTINED = 8,
+  SETUP_ADD_ACCOUNT = 9,
+  SETUP_INSTALL_APPS = 10,
+  SETUP_INSTALL_APPS_RETRY = 11,
+  SETUP_UPDATE_PLAY_SERVICES = 12,
+  SETUP_CHECK_REGISTRATION_TOKEN = 13,
+  SETUP_THIRD_PARTY_SIGNIN = 14
+};
+
+// Next method ID: 2
 interface EnterpriseReportingHost {
   // Reports the management status for the user.
   ReportManagementState@0(ManagementState state);
+
+  // Reports time in ms for a CloudDpc operation.
+  [MinVersion=3] ReportCloudDpcOperationTime@1(int64 time_ms,
+    TimedCloudDpcOp op, bool success);
 };
 
 // Deprecated method IDs: 0
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index ab66712f..92ac857 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -635,6 +635,11 @@
 const base::Feature kFastPairSoftwareScanning{
     "FastPairSoftwareScanning", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables the "Subsequent Pairing" Fast Pair scenario in Bluetooth Settings
+// and Quick Settings.
+const base::Feature kFastPairSubsequentPairingUX{
+    "FastPairSubsequentPairingUX", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables mounting various archive formats (in two tiers) in Files App. This
 // flag controls the first tier, whose support is very good.
 // https://crbug.com/1216245
@@ -679,6 +684,11 @@
 const base::Feature kFloatingWorkspace{"FloatingWorkspace",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables a window to float.
+// https://crbug.com/1240411
+const base::Feature kFloatWindow{"CrOSLabsFloatWindow",
+                                 base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Controls whether to allow keeping full screen mode after unlock.
 const base::Feature kFullscreenAfterUnlockAllowed = {
     "FullscreenAfterUnlockAllowed", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -1415,11 +1425,6 @@
 const base::Feature kWifiSyncApplyDeletes{"WifiSyncApplyDeletes",
                                           base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables a window control menu to snap, float and move window to another desk.
-// https://crbug.com/1240411
-const base::Feature kWindowControlMenu{"WindowControlMenu",
-                                       base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Change window creation to be based on cursor position when there are multiple
 // displays.
 const base::Feature kWindowsFollowCursor{"WindowsFollowCursor",
@@ -1662,6 +1667,10 @@
   return base::FeatureList::IsEnabled(kFastPairSoftwareScanning);
 }
 
+bool IsFastPairSubsequentPairingUXEnabled() {
+  return base::FeatureList::IsEnabled(kFastPairSubsequentPairingUX);
+}
+
 bool IsFileManagerFuseBoxEnabled() {
   return base::FeatureList::IsEnabled(kFuseBox);
 }
@@ -2092,8 +2101,8 @@
   return base::FeatureList::IsEnabled(kWifiSyncAndroid);
 }
 
-bool IsWindowControlMenuEnabled() {
-  return base::FeatureList::IsEnabled(kWindowControlMenu);
+bool IsFloatWindowEnabled() {
+  return base::FeatureList::IsEnabled(kFloatWindow);
 }
 
 bool ShouldShowPlayStoreInDemoMode() {
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 061d623..d46ddf3 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -256,6 +256,8 @@
 extern const base::FeatureParam<double> kFastPairLowPowerInactiveSeconds;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kFastPairSoftwareScanning;
+COMPONENT_EXPORT(ASH_CONSTANTS)
+extern const base::Feature kFastPairSubsequentPairingUX;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFilesArchivemount;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFilesArchivemount2;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFilesExtractArchive;
@@ -267,6 +269,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFiltersInRecents;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFirmwareUpdaterApp;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFloatingWorkspace;
+COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFloatWindow;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kFullscreenAfterUnlockAllowed;
 COMPONENT_EXPORT(ASH_CONSTANTS)
@@ -551,7 +554,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kWifiSyncAndroid;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kWifiSyncApplyDeletes;
-COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kWindowControlMenu;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kWindowsFollowCursor;
 
 // Keep alphabetized.
@@ -607,6 +609,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairLowPowerEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairSoftwareScanningEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFastPairSubsequentPairingUXEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFileManagerFuseBoxEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFileManagerSwaEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFirmwareUpdaterAppEnabled();
@@ -724,7 +727,7 @@
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWallpaperPerDeskEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWebUITabStripTabDragIntegrationEnabled();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWifiSyncAndroidEnabled();
-COMPONENT_EXPORT(ASH_CONSTANTS) bool IsWindowControlMenuEnabled();
+COMPONENT_EXPORT(ASH_CONSTANTS) bool IsFloatWindowEnabled();
 // TODO(michaelpg): Remove after M71 branch to re-enable Play Store by default.
 COMPONENT_EXPORT(ASH_CONSTANTS) bool ShouldShowPlayStoreInDemoMode();
 COMPONENT_EXPORT(ASH_CONSTANTS) bool ShouldUseAttachApn();
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc
index f39ab8e5..59486a9 100644
--- a/ash/frame/caption_buttons/frame_size_button_unittest.cc
+++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -78,8 +78,8 @@
       caption_button_container_->SetButtonImage(
           views::CAPTION_BUTTON_ICON_MINIMIZE,
           views::kWindowControlMinimizeIcon);
-      caption_button_container_->SetButtonImage(
-          views::CAPTION_BUTTON_ICON_MENU, chromeos::kWindowControlMenuIcon);
+      caption_button_container_->SetButtonImage(views::CAPTION_BUTTON_ICON_MENU,
+                                                chromeos::kFloatWindowIcon);
       caption_button_container_->SetButtonImage(
           views::CAPTION_BUTTON_ICON_CLOSE, views::kWindowControlCloseIcon);
       caption_button_container_->SetButtonImage(
diff --git a/ash/highlighter/highlighter_controller_unittest.cc b/ash/highlighter/highlighter_controller_unittest.cc
index 3abeeea..8cc3bef 100644
--- a/ash/highlighter/highlighter_controller_unittest.cc
+++ b/ash/highlighter/highlighter_controller_unittest.cc
@@ -424,7 +424,8 @@
 }
 
 // Test that the selection is never crossing the screen bounds.
-TEST_F(HighlighterControllerTest, SelectionInsideScreen) {
+// Flaky, https://crbug.com/1311772
+TEST_F(HighlighterControllerTest, DISABLED_SelectionInsideScreen) {
   controller_test_api_->SetEnabled(true);
   ui::test::EventGenerator* event_generator = GetEventGenerator();
   event_generator->EnterPenPointerMode();
diff --git a/ash/public/cpp/capture_mode/capture_mode_delegate.h b/ash/public/cpp/capture_mode/capture_mode_delegate.h
index ba126f4..3b59148 100644
--- a/ash/public/cpp/capture_mode/capture_mode_delegate.h
+++ b/ash/public/cpp/capture_mode/capture_mode_delegate.h
@@ -168,6 +168,10 @@
   // Gets the remaining free space on DriveFS and invokes `callback` with that
   // value, or -1 if there's an error in computing the DriveFS quota.
   virtual void GetDriveFsFreeSpaceBytes(OnGotDriveFsFreeSpace callback) = 0;
+
+  // Returns true if camera support is disabled by admins via
+  // the `SystemFeaturesDisableList` policy, false otherwise.
+  virtual bool IsCameraDisabledByPolicy() const = 0;
 };
 
 }  // namespace ash
diff --git a/ash/public/cpp/presentation_time_recorder.h b/ash/public/cpp/presentation_time_recorder.h
index 877ecd0..1471ba3 100644
--- a/ash/public/cpp/presentation_time_recorder.h
+++ b/ash/public/cpp/presentation_time_recorder.h
@@ -27,6 +27,10 @@
 
   virtual ~PresentationTimeRecorder() = default;
 
+  // Prepare to record timin for UI changes. Invoked before making UI changes
+  // so that the recorder could start to watch for UI changes if needed.
+  virtual void PrepareToRecord() {}
+
   // Request to record timing for the next frame. Returns true if the request
   // is accepted. Otherwise, returns false.
   virtual bool RequestNext() = 0;
diff --git a/ash/quick_pair/repository/fake_fast_pair_repository.cc b/ash/quick_pair/repository/fake_fast_pair_repository.cc
index f348a60..a4e8f68 100644
--- a/ash/quick_pair/repository/fake_fast_pair_repository.cc
+++ b/ash/quick_pair/repository/fake_fast_pair_repository.cc
@@ -33,7 +33,7 @@
 
 void FakeFastPairRepository::SetCheckAccountKeysResult(
     absl::optional<PairingMetadata> result) {
-  check_account_key_result_ = result;
+  check_account_keys_result_ = result;
 }
 
 bool FakeFastPairRepository::HasKeyForDevice(const std::string& mac_address) {
@@ -61,7 +61,7 @@
 void FakeFastPairRepository::CheckAccountKeys(
     const AccountKeyFilter& account_key_filter,
     CheckAccountKeysCallback callback) {
-  std::move(callback).Run(check_account_key_result_);
+  std::move(callback).Run(check_account_keys_result_);
 }
 
 void FakeFastPairRepository::AssociateAccountKey(
@@ -101,6 +101,11 @@
   return;
 }
 
+bool FakeFastPairRepository::IsAccountKeyPairedLocally(
+    const std::vector<uint8_t>& account_key) {
+  return is_account_key_paired_locally_;
+}
+
 // Unimplemented.
 bool FakeFastPairRepository::PersistDeviceImages(scoped_refptr<Device> device) {
   return true;
diff --git a/ash/quick_pair/repository/fake_fast_pair_repository.h b/ash/quick_pair/repository/fake_fast_pair_repository.h
index 8eeffa7..37ab80d 100644
--- a/ash/quick_pair/repository/fake_fast_pair_repository.h
+++ b/ash/quick_pair/repository/fake_fast_pair_repository.h
@@ -43,6 +43,10 @@
 
   void SetCheckAccountKeysResult(absl::optional<PairingMetadata> result);
 
+  void set_is_account_key_paired_locally(bool is_account_key_paired_locally) {
+    is_account_key_paired_locally_ = is_account_key_paired_locally;
+  }
+
   bool HasKeyForDevice(const std::string& mac_address);
 
   void set_is_network_connected(bool is_connected) {
@@ -71,6 +75,8 @@
       const std::vector<uint8_t>& account_key,
       DeleteAssociatedDeviceByAccountKeyCallback callback) override;
   void GetSavedDevices(GetSavedDevicesCallback callback) override;
+  bool IsAccountKeyPairedLocally(
+      const std::vector<uint8_t>& account_key) override;
 
  private:
   static void SetInstance(FastPairRepository* instance);
@@ -78,9 +84,10 @@
   nearby::fastpair::OptInStatus status_ =
       nearby::fastpair::OptInStatus::STATUS_UNKNOWN;
   bool is_network_connected_ = true;
+  bool is_account_key_paired_locally_ = true;
   base::flat_map<std::string, std::unique_ptr<DeviceMetadata>> data_;
   base::flat_map<std::string, std::vector<uint8_t>> saved_account_keys_;
-  absl::optional<PairingMetadata> check_account_key_result_;
+  absl::optional<PairingMetadata> check_account_keys_result_;
   base::WeakPtrFactory<FakeFastPairRepository> weak_ptr_factory_{this};
 };
 
diff --git a/ash/quick_pair/repository/fast_pair/saved_device_registry.cc b/ash/quick_pair/repository/fast_pair/saved_device_registry.cc
index c432af8..5a8089b 100644
--- a/ash/quick_pair/repository/fast_pair/saved_device_registry.cc
+++ b/ash/quick_pair/repository/fast_pair/saved_device_registry.cc
@@ -66,5 +66,33 @@
   return std::vector<uint8_t>(decoded.begin(), decoded.end());
 }
 
+bool SavedDeviceRegistry::IsAccountKeySavedToRegistry(
+    const std::vector<uint8_t>& account_key) {
+  PrefService* pref_service =
+      QuickPairBrowserDelegate::Get()->GetActivePrefService();
+  if (!pref_service) {
+    QP_LOG(WARNING) << __func__ << ": No user pref service available.";
+    return false;
+  }
+
+  const base::Value* saved_devices =
+      pref_service->GetDictionary(kFastPairSavedDevicesPref);
+  if (!saved_devices) {
+    QP_LOG(WARNING) << __func__
+                    << ": No Fast Pair Saved Devices pref available.";
+    return false;
+  }
+
+  std::string encoded_key = base::Base64Encode(account_key);
+  for (const auto it : saved_devices->DictItems()) {
+    const std::string* value = it.second.GetIfString();
+    if (value && *value == encoded_key) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 }  // namespace quick_pair
 }  // namespace ash
diff --git a/ash/quick_pair/repository/fast_pair/saved_device_registry.h b/ash/quick_pair/repository/fast_pair/saved_device_registry.h
index d53db99..d79bf428 100644
--- a/ash/quick_pair/repository/fast_pair/saved_device_registry.h
+++ b/ash/quick_pair/repository/fast_pair/saved_device_registry.h
@@ -38,6 +38,9 @@
   // empty vector.
   absl::optional<const std::vector<uint8_t>> GetAccountKey(
       const std::string& mac_address);
+
+  // Checks if the account key is in the registry.
+  bool IsAccountKeySavedToRegistry(const std::vector<uint8_t>& account_key);
 };
 
 }  // namespace quick_pair
diff --git a/ash/quick_pair/repository/fast_pair/saved_device_registry_unittest.cc b/ash/quick_pair/repository/fast_pair/saved_device_registry_unittest.cc
index 9108249..7b6060f 100644
--- a/ash/quick_pair/repository/fast_pair/saved_device_registry_unittest.cc
+++ b/ash/quick_pair/repository/fast_pair/saved_device_registry_unittest.cc
@@ -5,6 +5,9 @@
 #include "ash/quick_pair/repository/fast_pair/saved_device_registry.h"
 
 #include "ash/quick_pair/common/mock_quick_pair_browser_delegate.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
 #include "components/prefs/testing_pref_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -54,6 +57,11 @@
 
   ASSERT_EQ(kAccountKey1, *first);
   ASSERT_EQ(kAccountKey2, *second);
+
+  EXPECT_TRUE(
+      saved_device_registry_->IsAccountKeySavedToRegistry(kAccountKey1));
+  EXPECT_TRUE(
+      saved_device_registry_->IsAccountKeySavedToRegistry(kAccountKey2));
 }
 
 TEST_F(SavedDeviceRegistryTest, InvalidLookup) {
@@ -62,6 +70,29 @@
   auto invalid_result =
       saved_device_registry_->GetAccountKey(kNotSavedMacAddress);
   ASSERT_EQ(absl::nullopt, invalid_result);
+
+  EXPECT_TRUE(
+      saved_device_registry_->IsAccountKeySavedToRegistry(kAccountKey1));
+  EXPECT_FALSE(
+      saved_device_registry_->IsAccountKeySavedToRegistry(kAccountKey2));
+}
+
+TEST_F(SavedDeviceRegistryTest, MissingPrefService) {
+  ON_CALL(*browser_delegate_, GetActivePrefService())
+      .WillByDefault(testing::Return(nullptr));
+  saved_device_registry_->SaveAccountKey(kFirstSavedMacAddress, kAccountKey1);
+  saved_device_registry_->SaveAccountKey(kSecondSavedMacAddress, kAccountKey2);
+
+  auto first = saved_device_registry_->GetAccountKey(kFirstSavedMacAddress);
+  auto second = saved_device_registry_->GetAccountKey(kSecondSavedMacAddress);
+
+  ASSERT_EQ(absl::nullopt, first);
+  ASSERT_EQ(absl::nullopt, second);
+
+  EXPECT_FALSE(
+      saved_device_registry_->IsAccountKeySavedToRegistry(kAccountKey1));
+  EXPECT_FALSE(
+      saved_device_registry_->IsAccountKeySavedToRegistry(kAccountKey2));
 }
 
 }  // namespace quick_pair
diff --git a/ash/quick_pair/repository/fast_pair_repository.h b/ash/quick_pair/repository/fast_pair_repository.h
index 696bf33..a1e07ae7 100644
--- a/ash/quick_pair/repository/fast_pair_repository.h
+++ b/ash/quick_pair/repository/fast_pair_repository.h
@@ -62,6 +62,11 @@
   virtual void CheckAccountKeys(const AccountKeyFilter& account_key_filter,
                                 CheckAccountKeysCallback callback) = 0;
 
+  // Checks account keys saved to the device registry for a match to
+  // |account_key|. Return true if a match is found and false otherwise.
+  virtual bool IsAccountKeyPairedLocally(
+      const std::vector<uint8_t>& account_key) = 0;
+
   // Stores the given |account_key| for a |device| on the server.
   virtual void AssociateAccountKey(scoped_refptr<Device> device,
                                    const std::vector<uint8_t>& account_key) = 0;
diff --git a/ash/quick_pair/repository/fast_pair_repository_impl.cc b/ash/quick_pair/repository/fast_pair_repository_impl.cc
index 0525f546..bbf64ec 100644
--- a/ash/quick_pair/repository/fast_pair_repository_impl.cc
+++ b/ash/quick_pair/repository/fast_pair_repository_impl.cc
@@ -114,6 +114,11 @@
                           /*has_retryable_error=*/false);
 }
 
+bool FastPairRepositoryImpl::IsAccountKeyPairedLocally(
+    const std::vector<uint8_t>& account_key) {
+  return saved_device_registry_->IsAccountKeySavedToRegistry(account_key);
+}
+
 void FastPairRepositoryImpl::CheckAccountKeys(
     const AccountKeyFilter& account_key_filter,
     CheckAccountKeysCallback callback) {
@@ -325,9 +330,8 @@
     const device::BluetoothDevice* device) {
   absl::optional<const std::vector<uint8_t>> account_key =
       saved_device_registry_->GetAccountKey(device->GetAddress());
-  if (!account_key) {
+  if (!account_key)
     return false;
-  }
 
   QP_LOG(INFO) << __func__ << ": Removing device from Footprints.";
   footprints_fetcher_->DeleteUserDevice(base::HexEncode(*account_key),
diff --git a/ash/quick_pair/repository/fast_pair_repository_impl.h b/ash/quick_pair/repository/fast_pair_repository_impl.h
index fe588af..025f749 100644
--- a/ash/quick_pair/repository/fast_pair_repository_impl.h
+++ b/ash/quick_pair/repository/fast_pair_repository_impl.h
@@ -60,6 +60,8 @@
                          DeviceMetadataCallback callback) override;
   void CheckAccountKeys(const AccountKeyFilter& account_key_filter,
                         CheckAccountKeysCallback callback) override;
+  bool IsAccountKeyPairedLocally(
+      const std::vector<uint8_t>& account_key) override;
   void AssociateAccountKey(scoped_refptr<Device> device,
                            const std::vector<uint8_t>& account_key) override;
   bool DeleteAssociatedDevice(const device::BluetoothDevice* device) override;
diff --git a/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc b/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc
index eddb71d..aed72c8 100644
--- a/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc
+++ b/ash/quick_pair/repository/fast_pair_repository_impl_unittest.cc
@@ -42,9 +42,13 @@
 constexpr char kTestDeviceId[] = "test_ble_device_id";
 constexpr char kTestBLEAddress[] = "test_ble_address";
 constexpr char kTestClassicAddress[] = "test_classic_address";
+constexpr char kFirstSavedMacAddress[] = "00:11:22:33:44";
 const std::vector<uint8_t> kAccountKey1{0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
                                         0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB,
                                         0xCC, 0xDD, 0xEE, 0xFF};
+const std::vector<uint8_t> kAccountKey2{0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
+                                        0x44, 0x44, 0x55, 0x55, 0x66, 0x66,
+                                        0x77, 0x77, 0x88, 0x88};
 const std::vector<uint8_t> kFilterBytes1{0x0A, 0x42, 0x88, 0x10};
 const uint8_t salt = 0xC7;
 
@@ -512,5 +516,11 @@
   EXPECT_EQ(0u, devices_.size());
 }
 
+TEST_F(FastPairRepositoryImplTest, IsAccountKeyPairedLocally) {
+  saved_device_registry_->SaveAccountKey(kFirstSavedMacAddress, kAccountKey1);
+  EXPECT_TRUE(fast_pair_repository_->IsAccountKeyPairedLocally(kAccountKey1));
+  EXPECT_FALSE(fast_pair_repository_->IsAccountKeyPairedLocally(kAccountKey2));
+}
+
 }  // namespace quick_pair
 }  // namespace ash
diff --git a/ash/quick_pair/repository/mock_fast_pair_repository.h b/ash/quick_pair/repository/mock_fast_pair_repository.h
index 80ac749..7ee0a4e 100644
--- a/ash/quick_pair/repository/mock_fast_pair_repository.h
+++ b/ash/quick_pair/repository/mock_fast_pair_repository.h
@@ -73,6 +73,10 @@
               GetSavedDevices,
               (GetSavedDevicesCallback callback),
               (override));
+  MOCK_METHOD(bool,
+              IsAccountKeyPairedLocally,
+              (const std::vector<uint8_t>& account_key),
+              (override));
 };
 
 }  // namespace quick_pair
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl.cc b/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl.cc
index 56f6e985..7cdd247 100644
--- a/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl.cc
+++ b/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl.cc
@@ -225,6 +225,13 @@
   if (!metadata || !metadata->device_metadata)
     return;
 
+  if (FastPairRepository::Get()->IsAccountKeyPairedLocally(
+          metadata->account_key)) {
+    QP_LOG(INFO) << __func__
+                 << ": device already paired and saved to this Chromebook";
+    return;
+  }
+
   auto& details = metadata->device_metadata->GetDetails();
 
   // Convert the integer model id to uppercase hex string.
diff --git a/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl_unittest.cc b/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl_unittest.cc
index 0d3ebe8..3ed597a 100644
--- a/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl_unittest.cc
+++ b/ash/quick_pair/scanning/fast_pair/fast_pair_not_discoverable_scanner_impl_unittest.cc
@@ -229,6 +229,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
 
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   EXPECT_CALL(*process_manager_, GetProcessReference)
@@ -273,6 +274,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
 
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   EXPECT_CALL(*process_manager_, GetProcessReference)
@@ -319,6 +321,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
 
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   EXPECT_CALL(*process_manager_, GetProcessReference)
@@ -394,6 +397,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
   EXPECT_CALL(*process_manager_, GetProcessReference)
       .WillRepeatedly(
           [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
@@ -419,6 +423,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
 
   EXPECT_CALL(found_device_callback_, Run).Times(0);
   scanner_->NotifyDeviceFound(device);
@@ -438,6 +443,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
   EXPECT_CALL(*process_manager_, GetProcessReference)
       .WillRepeatedly(
           [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
@@ -461,6 +467,34 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(FastPairNotDiscoverableScannerImplTest, AlreadySavedToChromebook) {
+  device::BluetoothDevice* device = GetDevice(GetAdvServicedata());
+
+  nearby::fastpair::GetObservedDeviceResponse response;
+  response.mutable_device()->set_id(kModelIdLong);
+  response.mutable_device()->set_trigger_distance(2);
+
+  auto device_metadata =
+      std::make_unique<DeviceMetadata>(std::move(response), gfx::Image());
+  PairingMetadata pairing_metadata(device_metadata.get(),
+                                   std::vector<uint8_t>());
+  repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(true);
+  EXPECT_CALL(*process_manager_, GetProcessReference)
+      .WillRepeatedly(
+          [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
+            return std::make_unique<
+                QuickPairProcessManagerImpl::ProcessReferenceImpl>(
+                data_parser_remote_, base::DoNothing());
+          });
+
+  EXPECT_CALL(found_device_callback_, Run).Times(0);
+  EXPECT_CALL(lost_device_callback_, Run).Times(0);
+  scanner_->NotifyDeviceFound(device);
+
+  base::RunLoop().RunUntilIdle();
+}
+
 TEST_F(FastPairNotDiscoverableScannerImplTest, FactoryCreate) {
   not_discoverable_scanner_.reset();
   std::unique_ptr<FastPairNotDiscoverableScanner>
@@ -478,6 +512,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
   EXPECT_CALL(*process_manager_, GetProcessReference)
       .WillRepeatedly(
           [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
@@ -522,6 +557,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
 
   EXPECT_CALL(found_device_callback_, Run).Times(1);
   EXPECT_CALL(*process_manager_, GetProcessReference)
@@ -562,6 +598,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
 
   EXPECT_CALL(found_device_callback_, Run).Times(1);
   EXPECT_CALL(*process_manager_, GetProcessReference)
@@ -603,6 +640,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
 
   EXPECT_CALL(found_device_callback_, Run).Times(1);
   EXPECT_CALL(*process_manager_, GetProcessReference)
@@ -646,6 +684,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
   EXPECT_CALL(*process_manager_, GetProcessReference)
       .WillRepeatedly(
           [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
@@ -680,6 +719,7 @@
   PairingMetadata pairing_metadata(device_metadata.get(),
                                    std::vector<uint8_t>());
   repository_->SetCheckAccountKeysResult(pairing_metadata);
+  repository_->set_is_account_key_paired_locally(false);
   EXPECT_CALL(*process_manager_, GetProcessReference)
       .WillRepeatedly(
           [&](QuickPairProcessManager::ProcessStoppedCallback callback) {
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 2cce801..a4706ddb 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -48,6 +48,7 @@
     "capture_mode_folder.icon",
     "capture_mode_fullscreen.icon",
     "capture_mode_image.icon",
+    "capture_mode_managed.icon",
     "capture_mode_mic.icon",
     "capture_mode_mic_off.icon",
     "capture_mode_play.icon",
diff --git a/ash/resources/vector_icons/capture_mode_managed.icon b/ash/resources/vector_icons/capture_mode_managed.icon
new file mode 100644
index 0000000..190c3449
--- /dev/null
+++ b/ash/resources/vector_icons/capture_mode_managed.icon
@@ -0,0 +1,59 @@
+// 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 2, 17,
+V_LINE_TO, 3,
+R_H_LINE_TO, 10,
+R_V_LINE_TO, 4,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 10,
+H_LINE_TO, 2,
+CLOSE,
+R_MOVE_TO, 6, -8,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 2,
+H_LINE_TO, 8,
+V_LINE_TO, 9,
+CLOSE,
+R_MOVE_TO, 4, 2,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, -2,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, 4,
+V_LINE_TO, 9,
+R_H_LINE_TO, -4,
+R_V_LINE_TO, 2,
+CLOSE,
+R_MOVE_TO, -4, 2,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 2,
+H_LINE_TO, 8,
+R_V_LINE_TO, -2,
+CLOSE,
+R_MOVE_TO, -2, 0,
+H_LINE_TO, 4,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, -2,
+CLOSE,
+R_MOVE_TO, 0, -4,
+H_LINE_TO, 4,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, 2,
+V_LINE_TO, 9,
+CLOSE,
+R_MOVE_TO, 2, -4,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 2,
+H_LINE_TO, 8,
+V_LINE_TO, 5,
+CLOSE,
+MOVE_TO, 6, 5,
+H_LINE_TO, 4,
+R_V_LINE_TO, 2,
+R_H_LINE_TO, 2,
+V_LINE_TO, 5,
+CLOSE
diff --git a/ash/shell.cc b/ash/shell.cc
index c2e9aad..3916dc52 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -1386,7 +1386,7 @@
     projector_controller_ = std::make_unique<ProjectorControllerImpl>();
   }
 
-  if (features::IsWindowControlMenuEnabled())
+  if (features::IsFloatWindowEnabled())
     float_controller_ = std::make_unique<FloatController>();
 
   // Injects the factory which fulfills the implementation of the text context
diff --git a/ash/shortcut_viewer/views/keyboard_shortcut_view.cc b/ash/shortcut_viewer/views/keyboard_shortcut_view.cc
index c5f167461..bbe489f 100644
--- a/ash/shortcut_viewer/views/keyboard_shortcut_view.cc
+++ b/ash/shortcut_viewer/views/keyboard_shortcut_view.cc
@@ -151,7 +151,7 @@
     case IDS_KSV_DESCRIPTION_PRIVACY_SCREEN_TOGGLE:
       return !ash::Shell::Get()->privacy_screen_controller()->IsSupported();
     case IDS_KSV_DESCRIPTION_FLOAT:
-      return !ash::features::IsWindowControlMenuEnabled();
+      return !ash::features::IsFloatWindowEnabled();
   }
 
   return false;
diff --git a/ash/system/accessibility/tray_accessibility.cc b/ash/system/accessibility/tray_accessibility.cc
index 84ea3e0..5dbcda2 100644
--- a/ash/system/accessibility/tray_accessibility.cc
+++ b/ash/system/accessibility/tray_accessibility.cc
@@ -26,9 +26,11 @@
 #include "ash/system/tray/tri_view.h"
 #include "base/bind.h"
 #include "base/metrics/user_metrics.h"
+#include "components/live_caption/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/soda/soda_installer.h"
 #include "components/vector_icons/vector_icons.h"
+#include "media/base/media_switches.h"
 #include "ui/accessibility/accessibility_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/image/image.h"
@@ -36,6 +38,8 @@
 #include "ui/views/controls/separator.h"
 
 namespace ash {
+namespace tray {
+
 namespace {
 
 using ml::UserSettingsEvent;
@@ -68,21 +72,47 @@
   }
 }
 
-speech::LanguageCode GetDictationLocale() {
-  std::string dictation_locale = speech::kUsEnglishLocale;
+speech::LanguageCode GetSodaFeatureLocale(SodaFeature feature) {
+  std::string feature_locale = speech::kUsEnglishLocale;
   PrefService* pref_service =
       Shell::Get()->session_controller()->GetActivePrefService();
   if (pref_service) {
-    dictation_locale =
-        pref_service->GetString(prefs::kAccessibilityDictationLocale);
+    switch (feature) {
+      case SodaFeature::kDictation:
+        feature_locale =
+            pref_service->GetString(prefs::kAccessibilityDictationLocale);
+        break;
+      case SodaFeature::kLiveCaption:
+        feature_locale = ::prefs::GetLiveCaptionLanguageCode(pref_service);
+        break;
+    }
   }
-  return speech::GetLanguageCode(dictation_locale);
+  return speech::GetLanguageCode(feature_locale);
+}
+
+bool IsSodaFeatureEnabled(SodaFeature feature) {
+  AccessibilityControllerImpl* controller =
+      Shell::Get()->accessibility_controller();
+  switch (feature) {
+    case SodaFeature::kDictation:
+      return ::features::IsDictationOfflineAvailable() &&
+             controller->dictation().enabled();
+    case SodaFeature::kLiveCaption:
+      return controller->live_caption().enabled();
+  }
+}
+
+bool SodaFeatureHasUpdate(SodaFeature feature,
+                          speech::LanguageCode language_code) {
+  // Only show updates for this feature if the language code applies to the SODA
+  // binary (encoded by by LanguageCode::kNone) or the language pack matching
+  // the feature locale.
+  return language_code == speech::LanguageCode::kNone ||
+         language_code == GetSodaFeatureLocale(feature);
 }
 
 }  // namespace
 
-namespace tray {
-
 ////////////////////////////////////////////////////////////////////////////////
 // ash::tray::AccessibilityDetailedView
 
@@ -95,19 +125,27 @@
   AppendAccessibilityList();
   CreateTitleRow(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE);
   Layout();
-  UpdateSodaInstallerObserverStatus();
+
+  if (!::features::IsDictationOfflineAvailable() &&
+      !media::IsLiveCaptionFeatureEnabled()) {
+    return;
+  }
+  speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
+  if (soda_installer)
+    soda_installer->AddObserver(this);
 }
 
 AccessibilityDetailedView::~AccessibilityDetailedView() {
-  if (!::features::IsDictationOfflineAvailable())
+  if (!::features::IsDictationOfflineAvailable() &&
+      !media::IsLiveCaptionFeatureEnabled()) {
     return;
-
-  speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
-  if (soda_installer) {
-    // `soda_installer` is not guaranteed to be valid, since it's possible for
-    // this class to out-live it.
-    soda_installer->RemoveObserver(this);
   }
+  speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
+  // `soda_installer` is not guaranteed to be valid, since it's possible for
+  // this class to out-live it. This means that this class cannot use
+  // ScopedObservation and needs to manage removing the observer itself.
+  if (soda_installer)
+    soda_installer->RemoveObserver(this);
 }
 
 void AccessibilityDetailedView::OnAccessibilityStatusChanged() {
@@ -133,7 +171,6 @@
     dictation_enabled_ = controller->dictation().enabled();
     TrayPopupUtils::UpdateCheckMarkVisibility(dictation_view_,
                                               dictation_enabled_);
-    UpdateSodaInstallerObserverStatus();
   }
 
   if (high_contrast_view_ && controller->IsHighContrastSettingVisibleInTray()) {
@@ -582,89 +619,66 @@
   }
 }
 
-void AccessibilityDetailedView::UpdateSodaInstallerObserverStatus() {
-  if (!::features::IsDictationOfflineAvailable())
-    return;
-
-  speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
-  if (!soda_installer)
-    return;
-
-  bool dictation_enabled =
-      Shell::Get()->accessibility_controller()->dictation().enabled();
-  if (!dictation_enabled) {
-    soda_installer->RemoveObserver(this);
-    return;
-  }
-
-  if (!soda_installer->IsSodaInstalled(GetDictationLocale())) {
-    // Make sure this view observes SODA installation.
-    soda_installer->AddObserver(this);
-  }
-}
-
 // SodaInstaller::Observer:
 void AccessibilityDetailedView::OnSodaInstalled(
     speech::LanguageCode language_code) {
-  if (language_code != GetDictationLocale())
-    return;
-
-  // Show the success message if both the SODA binary and the language pack
-  // matching the Dictation locale have been downloaded.
-  speech::SodaInstaller::GetInstance()->RemoveObserver(this);
-  AccessibilityControllerImpl* controller =
-      Shell::Get()->accessibility_controller();
-  if (dictation_view_ && controller->IsDictationSettingVisibleInTray()) {
-    dictation_view_->SetSubText(l10n_util::GetStringUTF16(
-        IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE));
-  }
+  std::u16string message = l10n_util::GetStringUTF16(
+      IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE);
+  MaybeShowSodaMessage(SodaFeature::kDictation, language_code, message);
+  MaybeShowSodaMessage(SodaFeature::kLiveCaption, language_code, message);
 }
 
 void AccessibilityDetailedView::OnSodaError(
     speech::LanguageCode language_code) {
-  if (language_code != speech::LanguageCode::kNone &&
-      language_code != GetDictationLocale()) {
-    return;
-  }
-
-  // Show the failed message if either the Dictation locale failed or the SODA
-  // binary failed (encoded by LanguageCode::kNone).
-  speech::SodaInstaller::GetInstance()->RemoveObserver(this);
-  AccessibilityControllerImpl* controller =
-      Shell::Get()->accessibility_controller();
-  if (dictation_view_ && controller->IsDictationSettingVisibleInTray()) {
-    dictation_view_->SetSubText(l10n_util::GetStringUTF16(
-        IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR));
-  }
+  std::u16string message = l10n_util::GetStringUTF16(
+      IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR);
+  MaybeShowSodaMessage(SodaFeature::kDictation, language_code, message);
+  MaybeShowSodaMessage(SodaFeature::kLiveCaption, language_code, message);
 }
 
 void AccessibilityDetailedView::OnSodaProgress(
     speech::LanguageCode language_code,
     int progress) {
-  if (language_code != speech::LanguageCode::kNone &&
-      language_code != GetDictationLocale()) {
-    return;
-  }
+  std::u16string message = l10n_util::GetStringFUTF16Int(
+      IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS, progress);
+  MaybeShowSodaMessage(SodaFeature::kDictation, language_code, message);
+  MaybeShowSodaMessage(SodaFeature::kLiveCaption, language_code, message);
+}
 
-  // Only show the progress message if this applies to the SODA binary (encoded
-  // by LanguageCode::kNone) or the language pack matching the Dictation locale.
+void AccessibilityDetailedView::MaybeShowSodaMessage(
+    SodaFeature feature,
+    speech::LanguageCode language_code,
+    std::u16string message) {
+  if (IsSodaFeatureEnabled(feature) && IsSodaFeatureInTray(feature) &&
+      SodaFeatureHasUpdate(feature, language_code)) {
+    SetSodaFeatureSubtext(feature, message);
+  }
+}
+
+bool AccessibilityDetailedView::IsSodaFeatureInTray(SodaFeature feature) {
   AccessibilityControllerImpl* controller =
       Shell::Get()->accessibility_controller();
-  if (dictation_view_ && controller->IsDictationSettingVisibleInTray()) {
-    dictation_view_->SetSubText(l10n_util::GetStringFUTF16Int(
-        IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS,
-        progress));
+  switch (feature) {
+    case SodaFeature::kDictation:
+      return dictation_view_ && controller->IsDictationSettingVisibleInTray();
+    case SodaFeature::kLiveCaption:
+      return live_caption_view_ &&
+             controller->IsLiveCaptionSettingVisibleInTray();
   }
 }
 
-void AccessibilityDetailedView::SetDictationViewSubtitleTextForTesting(
-    std::u16string text) {
-  dictation_view_->SetSubText(text);
-}
-
-std::u16string
-AccessibilityDetailedView::GetDictationViewSubtitleTextForTesting() {
-  return dictation_view_->sub_text_label()->GetText();
+void AccessibilityDetailedView::SetSodaFeatureSubtext(SodaFeature feature,
+                                                      std::u16string message) {
+  switch (feature) {
+    case SodaFeature::kDictation:
+      DCHECK(dictation_view_);
+      dictation_view_->SetSubText(message);
+      break;
+    case SodaFeature::kLiveCaption:
+      DCHECK(live_caption_view_);
+      live_caption_view_->SetSubText(message);
+      break;
+  }
 }
 
 }  // namespace tray
diff --git a/ash/system/accessibility/tray_accessibility.h b/ash/system/accessibility/tray_accessibility.h
index b280c56..80a8fcbe 100644
--- a/ash/system/accessibility/tray_accessibility.h
+++ b/ash/system/accessibility/tray_accessibility.h
@@ -35,6 +35,11 @@
 
 namespace tray {
 
+enum class SodaFeature {
+  kDictation,
+  kLiveCaption,
+};
+
 // Create the detailed view of accessibility tray.
 class ASH_EXPORT AccessibilityDetailedView
     : public TrayDetailedView,
@@ -74,16 +79,19 @@
   // Add the accessibility feature list.
   void AppendAccessibilityList();
 
-  void UpdateSodaInstallerObserverStatus();
-
   // SodaInstaller::Observer:
   void OnSodaInstalled(speech::LanguageCode language_code) override;
   void OnSodaError(speech::LanguageCode language_code) override;
   void OnSodaProgress(speech::LanguageCode language_code,
                       int combined_progress) override;
 
-  void SetDictationViewSubtitleTextForTesting(std::u16string text);
-  std::u16string GetDictationViewSubtitleTextForTesting();
+  // Shows a message next to the feature icon in the tray if it is available
+  // and if the language code provided is relevant to the feature.
+  void MaybeShowSodaMessage(SodaFeature feature,
+                            speech::LanguageCode language_code,
+                            std::u16string message);
+  bool IsSodaFeatureInTray(SodaFeature feature);
+  void SetSodaFeatureSubtext(SodaFeature feature, std::u16string message);
 
   HoverHighlightView* spoken_feedback_view_ = nullptr;
   HoverHighlightView* select_to_speak_view_ = nullptr;
diff --git a/ash/system/accessibility/tray_accessibility_unittest.cc b/ash/system/accessibility/tray_accessibility_unittest.cc
index 8439b19..a7dd651 100644
--- a/ash/system/accessibility/tray_accessibility_unittest.cc
+++ b/ash/system/accessibility/tray_accessibility_unittest.cc
@@ -17,19 +17,23 @@
 #include "ash/test/ash_test_base.h"
 #include "base/command_line.h"
 #include "base/test/scoped_feature_list.h"
+#include "components/live_caption/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/soda/soda_installer_impl_chromeos.h"
 #include "media/base/media_switches.h"
 #include "ui/accessibility/accessibility_features.h"
 #include "ui/accessibility/ax_enums.mojom-shared.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/views/controls/label.h"
 
 namespace ash {
 namespace {
 
-const std::u16string kInitialDictationViewSubtitleText = u"This is a test";
+const std::u16string kInitialFeatureViewSubtitleText = u"This is a test";
 const std::u16string kSodaDownloaded = u"Speech files downloaded";
-const std::u16string kSodaInProgress =
+const std::u16string kSodaInProgress25 =
+    u"Downloading speech recognition files… 25%";
+const std::u16string kSodaInProgress50 =
     u"Downloading speech recognition files… 50%";
 const std::u16string kSodaFailed =
     u"Can't download speech files. Try again later.";
@@ -105,17 +109,24 @@
   Shell::Get()->accessibility_controller()->switch_access().SetEnabled(enabled);
 }
 
+speech::LanguageCode en_us() {
+  return speech::LanguageCode::kEnUs;
+}
+
+speech::LanguageCode fr_fr() {
+  return speech::LanguageCode::kFrFr;
+}
+
 }  // namespace
 
 class TrayAccessibilityTest : public AshTestBase, public AccessibilityObserver {
  public:
+  TrayAccessibilityTest() = default;
   TrayAccessibilityTest(const TrayAccessibilityTest&) = delete;
   TrayAccessibilityTest& operator=(const TrayAccessibilityTest&) = delete;
-
- protected:
-  TrayAccessibilityTest() = default;
   ~TrayAccessibilityTest() override = default;
 
+ protected:
   void SetUp() override {
     scoped_feature_list_.InitWithFeatures(
         {media::kLiveCaption, media::kLiveCaptionSystemWideOnChromeOS,
@@ -673,13 +684,20 @@
             GetDetailedViewClassName());
 }
 
-class TrayAccessibilitySodaTest : public TrayAccessibilityTest {
+enum SodaFeature {
+  kDictation,
+  kLiveCaption,
+};
+
+class TrayAccessibilitySodaTest
+    : public TrayAccessibilityTest,
+      public testing::WithParamInterface<SodaFeature> {
  protected:
   TrayAccessibilitySodaTest() { set_start_session(false); }
-  ~TrayAccessibilitySodaTest() override = default;
   TrayAccessibilitySodaTest(const TrayAccessibilitySodaTest&) = delete;
   TrayAccessibilitySodaTest& operator=(const TrayAccessibilitySodaTest&) =
       delete;
+  ~TrayAccessibilitySodaTest() override = default;
 
   void SetUp() override {
     TrayAccessibilityTest::SetUp();
@@ -687,42 +705,71 @@
     // SodaInstallerImplChromeOS is never created (it's normally created when
     // `ChromeBrowserMainPartsAsh` initializes). Create it here so that
     // calling speech::SodaInstaller::GetInstance() returns a valid instance.
-    scoped_feature_list_.InitWithFeatures(
-        {ash::features::kOnDeviceSpeechRecognition}, {});
+    std::vector<base::Feature> enabled_features(
+        {ash::features::kOnDeviceSpeechRecognition});
+    if (GetParam() == SodaFeature::kLiveCaption)
+      enabled_features.push_back(media::kLiveCaptionMultiLanguage);
+    scoped_feature_list_.InitWithFeatures(enabled_features, {});
     soda_installer_impl_ =
         std::make_unique<speech::SodaInstallerImplChromeOS>();
-    soda_installer()->UninstallSodaForTesting();
 
     CreateDetailedMenu();
-    EnableDictation(true);
-    SetDictationViewSubtitleText(kInitialDictationViewSubtitleText);
-    SetDictationLocale("en-US");
+    EnableFeature(true);
+    SetFeatureViewSubtitleText(kInitialFeatureViewSubtitleText);
+    SetFeatureLocale("en-US");
   }
 
   void TearDown() override {
-    soda_installer()->UninstallSodaForTesting();
     soda_installer_impl_.reset();
     TrayAccessibilityTest::TearDown();
   }
 
-  void SetDictationLocale(const std::string& locale) {
-    Shell::Get()->session_controller()->GetActivePrefService()->SetString(
-        prefs::kAccessibilityDictationLocale, locale);
+  void EnableFeature(bool enabled) {
+    switch (GetParam()) {
+      case kDictation:
+        EnableDictation(enabled);
+        break;
+      case kLiveCaption:
+        EnableLiveCaption(enabled);
+        break;
+    }
+  }
+
+  void SetFeatureLocale(const std::string& locale) {
+    switch (GetParam()) {
+      case kDictation:
+        Shell::Get()->session_controller()->GetActivePrefService()->SetString(
+            prefs::kAccessibilityDictationLocale, locale);
+        break;
+      case kLiveCaption:
+        Shell::Get()->session_controller()->GetActivePrefService()->SetString(
+            ::prefs::kLiveCaptionLanguageCode, locale);
+        break;
+    }
   }
 
   speech::SodaInstaller* soda_installer() {
     return speech::SodaInstaller::GetInstance();
   }
 
-  speech::LanguageCode en_us() { return speech::LanguageCode::kEnUs; }
-  speech::LanguageCode fr_fr() { return speech::LanguageCode::kFrFr; }
-
-  void SetDictationViewSubtitleText(std::u16string text) {
-    detailed_menu()->SetDictationViewSubtitleTextForTesting(text);
+  void SetFeatureViewSubtitleText(std::u16string text) {
+    switch (GetParam()) {
+      case kDictation:
+        detailed_menu()->dictation_view_->SetSubText(text);
+        break;
+      case kLiveCaption:
+        detailed_menu()->live_caption_view_->SetSubText(text);
+        break;
+    }
   }
 
-  std::u16string GetDictationViewSubtitleText() {
-    return detailed_menu()->GetDictationViewSubtitleTextForTesting();
+  std::u16string GetFeatureViewSubtitleText() {
+    switch (GetParam()) {
+      case kDictation:
+        return detailed_menu()->dictation_view_->sub_text_label()->GetText();
+      case kLiveCaption:
+        return detailed_menu()->live_caption_view_->sub_text_label()->GetText();
+    }
   }
 
  private:
@@ -730,54 +777,67 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-// Ensures that the Dictation subtitle changes when SODA AND the language pack
-// matching the Dictation locale are installed.
-TEST_F(TrayAccessibilitySodaTest, OnSodaInstalledNotification) {
-  SetDictationLocale("fr-FR");
+INSTANTIATE_TEST_SUITE_P(All,
+                         TrayAccessibilitySodaTest,
+                         ::testing::Values(SodaFeature::kDictation,
+                                           SodaFeature::kLiveCaption));
+
+// Ensures that the feature subtitle changes when SODA AND the language pack
+// matching the feature locale are installed.
+TEST_P(TrayAccessibilitySodaTest, OnSodaInstalledNotification) {
+  SetFeatureLocale("fr-FR");
 
   // Pretend that the SODA binary was installed. We still need to wait for the
   // correct language pack before doing anything.
   soda_installer()->NotifySodaInstalledForTesting();
-  EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
+  EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
   soda_installer()->NotifySodaInstalledForTesting(en_us());
-  EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
+  EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
   soda_installer()->NotifySodaInstalledForTesting(fr_fr());
-  EXPECT_EQ(kSodaDownloaded, GetDictationViewSubtitleText());
+  EXPECT_EQ(kSodaDownloaded, GetFeatureViewSubtitleText());
 }
 
 // Ensures we only notify the user of progress for the language pack matching
-// the Dictation locale.
-TEST_F(TrayAccessibilitySodaTest, OnSodaProgressNotification) {
-  soda_installer()->NotifySodaProgressForTesting(50, fr_fr());
-  EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
+// the feature locale.
+TEST_P(TrayAccessibilitySodaTest, OnSodaProgressNotification) {
+  SetFeatureLocale("en-US");
+
+  soda_installer()->NotifySodaProgressForTesting(75, fr_fr());
+  EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
   soda_installer()->NotifySodaProgressForTesting(50);
-  EXPECT_EQ(kSodaInProgress, GetDictationViewSubtitleText());
-  soda_installer()->NotifySodaProgressForTesting(50, en_us());
-  EXPECT_EQ(kSodaInProgress, GetDictationViewSubtitleText());
+  EXPECT_EQ(kSodaInProgress50, GetFeatureViewSubtitleText());
+  soda_installer()->NotifySodaProgressForTesting(25, en_us());
+  EXPECT_EQ(kSodaInProgress25, GetFeatureViewSubtitleText());
 }
 
-// Ensures we only notify the user of an error when the SODA binary fails to
+// Ensures we notify the user of an error when the SODA binary fails to
 // download.
-TEST_F(TrayAccessibilitySodaTest, SodaBinaryErrorNotification) {
+TEST_P(TrayAccessibilitySodaTest, SodaBinaryErrorNotification) {
   soda_installer()->NotifySodaErrorForTesting();
-  EXPECT_EQ(kSodaFailed, GetDictationViewSubtitleText());
+  EXPECT_EQ(kSodaFailed, GetFeatureViewSubtitleText());
 }
 
-TEST_F(TrayAccessibilitySodaTest, SodaLanguageErrorNotification) {
-  // Do nothing if the failed language pack is different than the Dictation
-  // locale.
+// Ensures we only notify the user of an error if the failed language pack
+// matches the feature locale.
+TEST_P(TrayAccessibilitySodaTest, SodaLanguageErrorNotification) {
+  SetFeatureLocale("en-US");
   soda_installer()->NotifySodaErrorForTesting(fr_fr());
-  EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
+  EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
   soda_installer()->NotifySodaErrorForTesting(en_us());
-  EXPECT_EQ(kSodaFailed, GetDictationViewSubtitleText());
+  EXPECT_EQ(kSodaFailed, GetFeatureViewSubtitleText());
 }
 
-// Ensures that we don't respond to SODA download updates when dictation is off.
-TEST_F(TrayAccessibilitySodaTest, SodaDownloadDictationDisabled) {
-  EnableDictation(false);
-  EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
+// Ensures that we don't respond to SODA download updates when the feature is
+// off.
+TEST_P(TrayAccessibilitySodaTest, SodaDownloadFeatureDisabled) {
+  EnableFeature(false);
+  EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
   soda_installer()->NotifySodaErrorForTesting();
-  EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
+  EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
+  soda_installer()->NotifySodaInstalledForTesting();
+  EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
+  soda_installer()->NotifySodaProgressForTesting(50);
+  EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
 }
 
 class TrayAccessibilityLoginScreenTest : public TrayAccessibilityTest {
diff --git a/ash/system/audio/audio_detailed_view.cc b/ash/system/audio/audio_detailed_view.cc
index 807f6f2..5d95a36 100644
--- a/ash/system/audio/audio_detailed_view.cc
+++ b/ash/system/audio/audio_detailed_view.cc
@@ -8,6 +8,7 @@
 #include "ash/components/audio/cras_audio_handler.h"
 #include "ash/constants/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
@@ -19,7 +20,9 @@
 #include "ash/system/tray/tri_view.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/live_caption/pref_names.h"
 #include "components/vector_icons/vector_icons.h"
+#include "media/base/media_switches.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/border.h"
@@ -75,6 +78,16 @@
   }
 }
 
+speech::LanguageCode GetLiveCaptionLocale() {
+  std::string live_caption_locale = speech::kUsEnglishLocale;
+  PrefService* pref_service =
+      Shell::Get()->session_controller()->GetActivePrefService();
+  if (pref_service) {
+    live_caption_locale = ::prefs::GetLiveCaptionLanguageCode(pref_service);
+  }
+  return speech::GetLanguageCode(live_caption_locale);
+}
+
 }  // namespace
 
 namespace tray {
@@ -84,10 +97,24 @@
   CreateItems();
 
   Shell::Get()->accessibility_controller()->AddObserver(this);
+
+  if (!media::IsLiveCaptionFeatureEnabled())
+    return;
+  speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
+  if (soda_installer)
+    soda_installer->AddObserver(this);
 }
 
 AudioDetailedView::~AudioDetailedView() {
   Shell::Get()->accessibility_controller()->RemoveObserver(this);
+  if (!media::IsLiveCaptionFeatureEnabled())
+    return;
+  speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
+  // `soda_installer` is not guaranteed to be valid, since it's possible for
+  // this class to out-live it. This means that this class cannot use
+  // ScopedObservation and needs to manage removing the observer itself.
+  if (soda_installer)
+    soda_installer->RemoveObserver(this);
 }
 
 void AudioDetailedView::Update() {
@@ -326,5 +353,43 @@
   }
 }
 
+// SodaInstaller::Observer:
+void AudioDetailedView::OnSodaInstalled(speech::LanguageCode language_code) {
+  std::u16string message = l10n_util::GetStringUTF16(
+      IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE);
+  MaybeShowSodaMessage(language_code, message);
+}
+
+void AudioDetailedView::OnSodaError(speech::LanguageCode language_code) {
+  std::u16string message = l10n_util::GetStringUTF16(
+      IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR);
+  MaybeShowSodaMessage(language_code, message);
+}
+
+void AudioDetailedView::OnSodaProgress(speech::LanguageCode language_code,
+                                       int progress) {
+  std::u16string message = l10n_util::GetStringFUTF16Int(
+      IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS, progress);
+  MaybeShowSodaMessage(language_code, message);
+}
+
+void AudioDetailedView::MaybeShowSodaMessage(speech::LanguageCode language_code,
+                                             std::u16string message) {
+  AccessibilityControllerImpl* controller =
+      Shell::Get()->accessibility_controller();
+  bool is_live_caption_enabled = controller->live_caption().enabled();
+  bool is_live_caption_in_tray =
+      live_caption_view_ && controller->IsLiveCaptionSettingVisibleInTray();
+  // Only show updates for this feature if the language code applies to the SODA
+  // binary (encoded by by LanguageCode::kNone) or the language pack matching
+  // the feature locale.
+  bool live_caption_has_update = language_code == speech::LanguageCode::kNone ||
+                                 language_code == GetLiveCaptionLocale();
+  if (is_live_caption_enabled && is_live_caption_in_tray &&
+      live_caption_has_update) {
+    live_caption_view_->SetSubText(message);
+  }
+}
+
 }  // namespace tray
 }  // namespace ash
diff --git a/ash/system/audio/audio_detailed_view.h b/ash/system/audio/audio_detailed_view.h
index c3ec5ca10..33544929 100644
--- a/ash/system/audio/audio_detailed_view.h
+++ b/ash/system/audio/audio_detailed_view.h
@@ -14,6 +14,7 @@
 #include "ash/system/tray/tray_detailed_view.h"
 #include "ash/system/tray/tray_toggle_button.h"
 #include "base/callback.h"
+#include "components/soda/soda_installer.h"
 #include "ui/views/controls/button/toggle_button.h"
 #include "ui/views/view.h"
 
@@ -23,12 +24,14 @@
 
 namespace ash {
 class MicGainSliderController;
+class UnifiedAudioDetailedViewControllerSodaTest;
 class UnifiedAudioDetailedViewControllerTest;
 
 namespace tray {
 
 class ASH_EXPORT AudioDetailedView : public TrayDetailedView,
-                                     public ::ash::AccessibilityObserver {
+                                     public ::ash::AccessibilityObserver,
+                                     public speech::SodaInstaller::Observer {
  public:
   explicit AudioDetailedView(DetailedViewDelegate* delegate);
 
@@ -51,6 +54,7 @@
   void OnAccessibilityStatusChanged() override;
 
  private:
+  friend class ::ash::UnifiedAudioDetailedViewControllerSodaTest;
   friend class ::ash::UnifiedAudioDetailedViewControllerTest;
 
   // Helper function to add non-clickable header rows within the scrollable
@@ -70,6 +74,15 @@
   // TrayDetailedView:
   void HandleViewClicked(views::View* view) override;
 
+  // SodaInstaller::Observer:
+  void OnSodaInstalled(speech::LanguageCode language_code) override;
+  void OnSodaError(speech::LanguageCode language_code) override;
+  void OnSodaProgress(speech::LanguageCode language_code,
+                      int combined_progress) override;
+
+  void MaybeShowSodaMessage(speech::LanguageCode language_code,
+                            std::u16string message);
+
   typedef std::map<views::View*, AudioDevice> AudioDeviceMap;
 
   std::unique_ptr<MicGainSliderController> mic_gain_controller_;
diff --git a/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc b/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc
index 5e971f40..3922a3b 100644
--- a/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc
+++ b/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc
@@ -8,6 +8,7 @@
 #include "ash/components/audio/audio_devices_pref_handler.h"
 #include "ash/components/audio/audio_devices_pref_handler_stub.h"
 #include "ash/constants/ash_features.h"
+#include "ash/session/session_controller_impl.h"
 #include "ash/shell.h"
 #include "ash/system/audio/audio_detailed_view.h"
 #include "ash/system/audio/mic_gain_slider_controller.h"
@@ -20,11 +21,14 @@
 #include "base/test/scoped_feature_list.h"
 #include "chromeos/dbus/audio/cras_audio_client.h"
 #include "chromeos/dbus/audio/fake_cras_audio_client.h"
+#include "components/live_caption/pref_names.h"
+#include "components/soda/soda_installer_impl_chromeos.h"
 #include "media/base/media_switches.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/events/base_event_utils.h"
+#include "ui/views/controls/label.h"
 #include "ui/views/test/button_test_api.h"
 #include "ui/views/widget/widget.h"
 
@@ -39,6 +43,23 @@
 constexpr uint64_t kFrontMicId = 10012;
 constexpr uint64_t kRearMicId = 10013;
 
+const std::u16string kInitialLiveCaptionViewSubtitleText = u"This is a test";
+const std::u16string kSodaDownloaded = u"Speech files downloaded";
+const std::u16string kSodaInProgress25 =
+    u"Downloading speech recognition files… 25%";
+const std::u16string kSodaInProgress50 =
+    u"Downloading speech recognition files… 50%";
+const std::u16string kSodaFailed =
+    u"Can't download speech files. Try again later.";
+
+speech::LanguageCode en_us() {
+  return speech::LanguageCode::kEnUs;
+}
+
+speech::LanguageCode fr_fr() {
+  return speech::LanguageCode::kFrFr;
+}
+
 struct AudioNodeInfo {
   bool is_input;
   uint64_t id;
@@ -161,7 +182,7 @@
     return audio_detailed_view_.get();
   }
 
-  views::View* live_caption_view() {
+  HoverHighlightView* live_caption_view() {
     return audio_detailed_view()->live_caption_view_;
   }
 
@@ -347,4 +368,135 @@
   EXPECT_FALSE(live_caption_enabled());
 }
 
+class UnifiedAudioDetailedViewControllerSodaTest
+    : public UnifiedAudioDetailedViewControllerTest {
+ protected:
+  UnifiedAudioDetailedViewControllerSodaTest() = default;
+  UnifiedAudioDetailedViewControllerSodaTest(
+      const UnifiedAudioDetailedViewControllerSodaTest&) = delete;
+  UnifiedAudioDetailedViewControllerSodaTest& operator=(
+      const UnifiedAudioDetailedViewControllerSodaTest&) = delete;
+  ~UnifiedAudioDetailedViewControllerSodaTest() override = default;
+
+  void SetUp() override {
+    UnifiedAudioDetailedViewControllerTest::SetUp();
+    // Since this test suite is part of ash unit tests, the
+    // SodaInstallerImplChromeOS is never created (it's normally created when
+    // `ChromeBrowserMainPartsAsh` initializes). Create it here so that
+    // calling speech::SodaInstaller::GetInstance() returns a valid instance.
+    scoped_feature_list_.InitWithFeatures(
+        {ash::features::kOnDeviceSpeechRecognition, media::kLiveCaption,
+         media::kLiveCaptionMultiLanguage,
+         media::kLiveCaptionSystemWideOnChromeOS},
+        {});
+    soda_installer_impl_ =
+        std::make_unique<speech::SodaInstallerImplChromeOS>();
+
+    EnableLiveCaption(true);
+    SetLiveCaptionViewSubtitleText(kInitialLiveCaptionViewSubtitleText);
+    SetLiveCaptionLocale("en-US");
+  }
+
+  void TearDown() override {
+    soda_installer_impl_.reset();
+    UnifiedAudioDetailedViewControllerTest::TearDown();
+  }
+
+  void EnableLiveCaption(bool enabled) {
+    Shell::Get()->accessibility_controller()->live_caption().SetEnabled(
+        enabled);
+  }
+
+  void SetLiveCaptionLocale(const std::string& locale) {
+    Shell::Get()->session_controller()->GetActivePrefService()->SetString(
+        ::prefs::kLiveCaptionLanguageCode, locale);
+  }
+
+  speech::SodaInstaller* soda_installer() {
+    return speech::SodaInstaller::GetInstance();
+  }
+
+  void SetLiveCaptionViewSubtitleText(std::u16string text) {
+    live_caption_view()->SetSubText(text);
+  }
+
+  std::u16string GetLiveCaptionViewSubtitleText() {
+    return live_caption_view()->sub_text_label()->GetText();
+  }
+
+ private:
+  std::unique_ptr<speech::SodaInstallerImplChromeOS> soda_installer_impl_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Ensures that the Dictation subtitle changes when SODA AND the language pack
+// matching the Live Caption locale are installed.
+TEST_F(UnifiedAudioDetailedViewControllerSodaTest,
+       OnSodaInstalledNotification) {
+  SetLiveCaptionLocale("fr-FR");
+
+  // Pretend that the SODA binary was installed. We still need to wait for the
+  // correct language pack before doing anything.
+  soda_installer()->NotifySodaInstalledForTesting();
+  EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
+            GetLiveCaptionViewSubtitleText());
+  soda_installer()->NotifySodaInstalledForTesting(en_us());
+  EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
+            GetLiveCaptionViewSubtitleText());
+  soda_installer()->NotifySodaInstalledForTesting(fr_fr());
+  EXPECT_EQ(kSodaDownloaded, GetLiveCaptionViewSubtitleText());
+}
+
+// Ensures we only notify the user of progress for the language pack matching
+// the Live Caption locale.
+TEST_F(UnifiedAudioDetailedViewControllerSodaTest, OnSodaProgressNotification) {
+  SetLiveCaptionLocale("en-US");
+
+  soda_installer()->NotifySodaProgressForTesting(75, fr_fr());
+  EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
+            GetLiveCaptionViewSubtitleText());
+  soda_installer()->NotifySodaProgressForTesting(50);
+  EXPECT_EQ(kSodaInProgress50, GetLiveCaptionViewSubtitleText());
+  soda_installer()->NotifySodaProgressForTesting(25, en_us());
+  EXPECT_EQ(kSodaInProgress25, GetLiveCaptionViewSubtitleText());
+}
+
+// Ensures we notify the user of an error when the SODA binary fails to
+// download.
+TEST_F(UnifiedAudioDetailedViewControllerSodaTest,
+       SodaBinaryErrorNotification) {
+  soda_installer()->NotifySodaErrorForTesting();
+  EXPECT_EQ(kSodaFailed, GetLiveCaptionViewSubtitleText());
+}
+
+// Ensures we only notify the user of an error if the failed language pack
+// matches the Live Caption locale.
+TEST_F(UnifiedAudioDetailedViewControllerSodaTest,
+       SodaLanguageErrorNotification) {
+  SetLiveCaptionLocale("en-US");
+  soda_installer()->NotifySodaErrorForTesting(fr_fr());
+  EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
+            GetLiveCaptionViewSubtitleText());
+  soda_installer()->NotifySodaErrorForTesting(en_us());
+  EXPECT_EQ(kSodaFailed, GetLiveCaptionViewSubtitleText());
+}
+
+// Ensures that we don't respond to SODA download updates when Live Caption is
+// off.
+TEST_F(UnifiedAudioDetailedViewControllerSodaTest,
+       SodaDownloadLiveCaptionDisabled) {
+  EnableLiveCaption(false);
+  EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
+            GetLiveCaptionViewSubtitleText());
+  soda_installer()->NotifySodaErrorForTesting();
+  EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
+            GetLiveCaptionViewSubtitleText());
+  soda_installer()->NotifySodaInstalledForTesting();
+  EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
+            GetLiveCaptionViewSubtitleText());
+  soda_installer()->NotifySodaProgressForTesting(50);
+  EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
+            GetLiveCaptionViewSubtitleText());
+}
+
 }  // namespace ash
diff --git a/ash/system/dark_mode/dark_mode_feature_pod_controller.cc b/ash/system/dark_mode/dark_mode_feature_pod_controller.cc
index 70155c8..4ea7aa5 100644
--- a/ash/system/dark_mode/dark_mode_feature_pod_controller.cc
+++ b/ash/system/dark_mode/dark_mode_feature_pod_controller.cc
@@ -10,6 +10,7 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
+#include "ash/style/dark_mode_controller.h"
 #include "ash/system/model/system_tray_model.h"
 #include "ash/system/tray/tray_popup_utils.h"
 #include "ash/system/unified/feature_pod_button.h"
@@ -68,9 +69,16 @@
 
 void DarkModeFeaturePodController::UpdateButton(bool dark_mode_enabled) {
   button_->SetToggled(dark_mode_enabled);
-  button_->SetSubLabel(l10n_util::GetStringUTF16(
-      dark_mode_enabled ? IDS_ASH_STATUS_TRAY_DARK_THEME_ON_STATE
-                        : IDS_ASH_STATUS_TRAY_DARK_THEME_OFF_STATE));
+  if (ash::Shell::Get()->dark_mode_controller()->GetAutoScheduleEnabled()) {
+    button_->SetSubLabel(l10n_util::GetStringUTF16(
+        dark_mode_enabled
+            ? IDS_ASH_STATUS_TRAY_DARK_THEME_ON_STATE_AUTO_SCHEDULED
+            : IDS_ASH_STATUS_TRAY_DARK_THEME_OFF_STATE_AUTO_SCHEDULED));
+  } else {
+    button_->SetSubLabel(l10n_util::GetStringUTF16(
+        dark_mode_enabled ? IDS_ASH_STATUS_TRAY_DARK_THEME_ON_STATE
+                          : IDS_ASH_STATUS_TRAY_DARK_THEME_OFF_STATE));
+  }
 
   std::u16string tooltip_state = l10n_util::GetStringUTF16(
       dark_mode_enabled
diff --git a/ash/system/eche/eche_tray.cc b/ash/system/eche/eche_tray.cc
index f6d8577..d250e24 100644
--- a/ash/system/eche/eche_tray.cc
+++ b/ash/system/eche/eche_tray.cc
@@ -223,7 +223,8 @@
   url_ = url;
 }
 
-void EcheTray::SetIcon(const gfx::Image& icon) {
+void EcheTray::SetIcon(const gfx::Image& icon,
+                       const std::u16string& tooltip_text) {
   views::ImageButton* icon_view = GetIcon();
   if (icon_view) {
     icon_view->SetImage(
@@ -231,13 +232,16 @@
         gfx::ImageSkiaOperations::CreateResizedImage(
             icon.AsImageSkia(), skia::ImageOperations::RESIZE_BEST,
             gfx::Size(kIconSize, kIconSize)));
+    icon_view->SetTooltipText(tooltip_text);
     SetIconVisibility(true);
   }
 }
 
-void EcheTray::LoadBubble(const GURL& url, const gfx::Image& icon) {
+void EcheTray::LoadBubble(const GURL& url,
+                          const gfx::Image& icon,
+                          const std::u16string& visible_name) {
   SetUrl(url);
-  SetIcon(icon);
+  SetIcon(icon, /*tooltip_text=*/visible_name);
   // If the bubble is already initialized, setting the icon and url was enough
   // to navigate the bubble to the new address.
   if (IsInitialized()) {
diff --git a/ash/system/eche/eche_tray.h b/ash/system/eche/eche_tray.h
index 795e86c0..878705d 100644
--- a/ash/system/eche/eche_tray.h
+++ b/ash/system/eche/eche_tray.h
@@ -83,14 +83,17 @@
   void SetUrl(const GURL& url);
 
   // Sets the icon that will be used on the tray.
-  void SetIcon(const gfx::Image& icon);
+  void SetIcon(const gfx::Image& icon, const std::u16string& tooltip_text);
 
   // Initializes the bubble with given parameters. If there is any previous
   // bubble already shown with a different URL it is going to be closed. The
-  // bubble is not shown initially until `ShowBubble` is called. The `url`
-  // parameter is used to load the `WebView` inside the bubble. The `icon` is
-  // used to update the tray icon for `EcheTray`.
-  void LoadBubble(const GURL& url, const gfx::Image& icon);
+  // bubble is not shown initially until `ShowBubble` is called.
+  // The `url` parameter is used to load the `WebView` inside the bubble.
+  // The `icon` is used to update the tray icon for `EcheTray`.
+  // The `visible_name` is shown as a tooltip for the Eche icon.
+  void LoadBubble(const GURL& url,
+                  const gfx::Image& icon,
+                  const std::u16string& visible_name);
 
   // Destroys the view inclusing the web view.
   // Note: `CloseBubble` only hides the view.
diff --git a/ash/system/eche/eche_tray_unittest.cc b/ash/system/eche/eche_tray_unittest.cc
index d6586f8..fe4f671 100644
--- a/ash/system/eche/eche_tray_unittest.cc
+++ b/ash/system/eche/eche_tray_unittest.cc
@@ -82,7 +82,7 @@
   EXPECT_FALSE(eche_tray()->GetVisible());
 
   eche_tray()->SetVisiblePreferred(true);
-  eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image());
+  eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1");
   eche_tray()->ShowBubble();
 
   EXPECT_TRUE(eche_tray()->is_active());
@@ -120,7 +120,7 @@
 
   // Allow us to create the bubble but it is not visible until we need this
   // bubble to show up.
-  eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image());
+  eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1");
 
   EXPECT_FALSE(eche_tray()->is_active());
   EXPECT_TRUE(eche_tray()->get_bubble_wrapper_for_test());
@@ -147,7 +147,7 @@
 
   // Allow us to create the bubble but it is not visible until we need this
   // bubble to show up.
-  eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image());
+  eche_tray()->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1");
 
   EXPECT_FALSE(eche_tray()->is_active());
   EXPECT_TRUE(eche_tray()->get_bubble_wrapper_for_test());
diff --git a/ash/system/message_center/unified_message_center_bubble.cc b/ash/system/message_center/unified_message_center_bubble.cc
index 8134b53f..f49dbd0 100644
--- a/ash/system/message_center/unified_message_center_bubble.cc
+++ b/ash/system/message_center/unified_message_center_bubble.cc
@@ -281,6 +281,13 @@
 }
 
 int UnifiedMessageCenterBubble::CalculateAvailableHeight() {
+  // TODO(crbug/1311738): Temporary fix to prevent crashes in case the quick
+  // settings bubble is destroyed before the message center bubble. In the long
+  // term we should remove this code altogether and calculate the max height for
+  // the message center bubble separately.
+  if (!tray_->bubble())
+    return 0;
+
   return tray_->bubble()->CalculateMaxHeight() -
          tray_->bubble()->GetCurrentTrayHeight() -
          GetBubbleInsetHotseatCompensation() -
diff --git a/ash/system/phonehub/phone_hub_notification_controller.cc b/ash/system/phonehub/phone_hub_notification_controller.cc
index a44f0e5..3570793 100644
--- a/ash/system/phonehub/phone_hub_notification_controller.cc
+++ b/ash/system/phonehub/phone_hub_notification_controller.cc
@@ -59,6 +59,11 @@
 const int kNotificationHeaderTextWidth = 180;
 const int kNotificationAppNameMaxWidth = 140;
 
+// The max age since a notification's creation on the Android for it to get
+// shown in a heads-up pop up. Notifications older than this will only silently
+// get added.
+constexpr base::TimeDelta kMaxRecentNotificationAge = base::Seconds(15);
+
 // The amount of time the reply button is disabled after sending an inline
 // reply. This is used to make sure that all the replies are received by the
 // phone in a correct order (a reply sent right after another could cause it to
@@ -391,8 +396,6 @@
 PhoneHubNotificationController::~PhoneHubNotificationController() {
   if (manager_)
     manager_->RemoveObserver(this);
-  if (feature_status_provider_)
-    feature_status_provider_->RemoveObserver(this);
   if (tether_controller_)
     tether_controller_->RemoveObserver(this);
   if (camera_roll_manager_)
@@ -410,15 +413,6 @@
     manager_ = nullptr;
   }
 
-  if (feature_status_provider_)
-    feature_status_provider_->RemoveObserver(this);
-  if (phone_hub_manager) {
-    feature_status_provider_ = phone_hub_manager->GetFeatureStatusProvider();
-    feature_status_provider_->AddObserver(this);
-  } else {
-    feature_status_provider_ = nullptr;
-  }
-
   if (tether_controller_)
     tether_controller_->RemoveObserver(this);
   if (phone_hub_manager) {
@@ -460,28 +454,6 @@
   return phone_model_->phone_name().value_or(std::u16string());
 }
 
-void PhoneHubNotificationController::OnFeatureStatusChanged() {
-  DCHECK(feature_status_provider_);
-
-  auto status = feature_status_provider_->GetStatus();
-
-  // Various states in which the feature is enabled, even if it is not actually
-  // in use (e.g., if Bluetooth is disabled or if the screen is locked).
-  bool is_feature_enabled =
-      status == phonehub::FeatureStatus::kUnavailableBluetoothOff ||
-      status == phonehub::FeatureStatus::kLockOrSuspended ||
-      status == phonehub::FeatureStatus::kEnabledButDisconnected ||
-      status == phonehub::FeatureStatus::kEnabledAndConnecting ||
-      status == phonehub::FeatureStatus::kEnabledAndConnected;
-
-  // Reset the set of shown notifications when Phone Hub is disabled. If it is
-  // enabled, we skip this step to ensure that notifications that have already
-  // been shown do not pop up again and spam the user. See
-  // https://crbug.com/1157523 for details.
-  if (!is_feature_enabled)
-    shown_notification_ids_.clear();
-}
-
 void PhoneHubNotificationController::OnNotificationsAdded(
     const base::flat_set<int64_t>& notification_ids) {
   for (int64_t id : notification_ids) {
@@ -764,8 +736,6 @@
     cros_notification->set_custom_view_type(kNotificationCustomViewType);
   }
 
-  shown_notification_ids_.insert(phone_hub_id);
-
   phone_hub_metrics::LogNotificationMessageLength(
       cros_notification->message().length());
 
@@ -878,20 +848,16 @@
 int PhoneHubNotificationController::GetSystemPriorityForNotification(
     const phonehub::Notification* notification,
     bool is_update) {
-  bool has_notification_been_shown =
-      base::Contains(shown_notification_ids_, notification->id());
-
-  // If the same notification was already shown and has not been updated,
-  // use LOW_PRIORITY so that the notification is silently added to the
-  // notification shade. This ensures that we don't spam users with the same
-  // information multiple times.
-  if (has_notification_been_shown && !is_update)
-    return message_center::LOW_PRIORITY;
+  bool is_recent = (notification->timestamp() + kMaxRecentNotificationAge) >
+                   base::Time::Now();
 
   // Use MAX_PRIORITY, which causes the notification to be shown in a popup
-  // so that users can see new messages come in as they are chatting. See
-  // https://crbug.com/1159063.
-  return message_center::MAX_PRIORITY;
+  // so that users can see new messages come in as they are chatting.
+  if (is_recent || is_update)
+    return message_center::MAX_PRIORITY;
+
+  // Silently add older notifications that are likely to be stale.
+  return message_center::LOW_PRIORITY;
 }
 
 std::u16string GetPhoneName(base::WeakPtr<ash::PhoneHubNotificationController>
diff --git a/ash/system/phonehub/phone_hub_notification_controller.h b/ash/system/phonehub/phone_hub_notification_controller.h
index afda1f2..224eb6d 100644
--- a/ash/system/phonehub/phone_hub_notification_controller.h
+++ b/ash/system/phonehub/phone_hub_notification_controller.h
@@ -41,7 +41,6 @@
 // PhoneHub corresponding notification.
 class ASH_EXPORT PhoneHubNotificationController
     : public phonehub::CameraRollManager::Observer,
-      public phonehub::FeatureStatusProvider::Observer,
       public phonehub::NotificationManager::Observer,
       public phonehub::TetherController::Observer {
  public:
@@ -68,9 +67,6 @@
 
   class NotificationDelegate;
 
-  // phonehub::FeatureStatusProvider::Observer:
-  void OnFeatureStatusChanged() override;
-
   // phonehub::NotificationManager::Observer:
   void OnNotificationsAdded(
       const base::flat_set<int64_t>& notification_ids) override;
@@ -142,18 +138,12 @@
   phonehub::NotificationInteractionHandler* notification_interaction_handler_ =
       nullptr;
   phonehub::NotificationManager* manager_ = nullptr;
-  phonehub::FeatureStatusProvider* feature_status_provider_ = nullptr;
   phonehub::TetherController* tether_controller_ = nullptr;
   phonehub::CameraRollManager* camera_roll_manager_ = nullptr;
   phonehub::PhoneModel* phone_model_ = nullptr;
   std::unordered_map<int64_t, std::unique_ptr<NotificationDelegate>>
       notification_map_;
 
-  // A set of notification ids that have been previously shown, even across
-  // disconnects. This is needed to prevent pop-ups from reappearing due to a
-  // flaky connection. See crbug.com/1150621.
-  std::unordered_set<uint64_t> shown_notification_ids_;
-
   base::WeakPtrFactory<PhoneHubNotificationController> weak_ptr_factory_{this};
 };
 
diff --git a/ash/system/phonehub/phone_hub_notification_controller_unittest.cc b/ash/system/phonehub/phone_hub_notification_controller_unittest.cc
index 1d523ac..d20e3dc 100644
--- a/ash/system/phonehub/phone_hub_notification_controller_unittest.cc
+++ b/ash/system/phonehub/phone_hub_notification_controller_unittest.cc
@@ -48,8 +48,11 @@
 
 const char kNotificationCustomViewType[] = "phonehub";
 
+// Max notification age for it to be shown heads-up (marked as MAX_PRIORITY)
+constexpr base::TimeDelta kMaxRecentNotificationAge = base::Seconds(15);
+
 // Time to wait until we enable the reply button
-constexpr base::TimeDelta kWaitForEnableButton = base::Seconds(1);
+constexpr base::TimeDelta kInlineReplyDisableTime = base::Seconds(1);
 
 phonehub::Notification CreateNotification(int64_t id) {
   return phonehub::Notification(
@@ -310,7 +313,7 @@
 }
 
 TEST_F(PhoneHubNotificationControllerTest, NotificationDataAndImages) {
-  base::Time timestamp = base::Time::FromJsTime(12345);
+  base::Time timestamp = base::Time::Now();
 
   SkBitmap icon_bitmap;
   icon_bitmap.allocN32Pixels(32, 32);
@@ -411,7 +414,7 @@
   EXPECT_FALSE(reply_button->GetEnabled());
 
   // After a brief moment, it should be enabled.
-  task_environment()->FastForwardBy(kWaitForEnableButton);
+  task_environment()->FastForwardBy(kInlineReplyDisableTime);
   EXPECT_TRUE(reply_button->GetEnabled());
 }
 
@@ -431,37 +434,29 @@
   EXPECT_TRUE(notification_view->IsManuallyExpandedOrCollapsed());
 }
 
-TEST_F(PhoneHubNotificationControllerTest, DoNotReshowPopupNotification) {
+TEST_F(PhoneHubNotificationControllerTest, DoNotShowOldNotification) {
+  // Subtract a few extra seconds as a preemptive measure against test flakiness
+  base::Time old_timestamp =
+      (base::Time::Now() - kMaxRecentNotificationAge) - base::Seconds(5);
   phonehub::Notification fake_notification(
       kPhoneHubNotificationId0,
       phonehub::Notification::AppMetadata(
           kAppName, kPackageName,
           /*icon=*/gfx::Image(), /*icon_color =*/absl::nullopt,
           /*icon_is_monochrome =*/true, kUserId),
-      base::Time::Now(), phonehub::Notification::Importance::kHigh,
+      old_timestamp, phonehub::Notification::Importance::kHigh,
       phonehub::Notification::Category::kConversation,
       {{phonehub::Notification::ActionType::kInlineReply, 0}},
       phonehub::Notification::InteractionBehavior::kNone, kTitle, kTextContent);
 
-  // Adding the notification for the first time shows a pop-up (MAX_PRIORITY).
+  // Adding an old notification does not show a pop-up (LOW_PRIORITY).
   notification_manager_->SetNotification(fake_notification);
   auto* cros_notification = FindNotification(kCrOSNotificationId0);
   ASSERT_TRUE(cros_notification);
-  EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority());
+  EXPECT_EQ(message_center::LOW_PRIORITY, cros_notification->priority());
 
-  feature_status_provider_->SetStatus(
-      phonehub::FeatureStatus::kEnabledButDisconnected);
-  feature_status_provider_->SetStatus(
-      phonehub::FeatureStatus::kEnabledAndConnecting);
-  feature_status_provider_->SetStatus(
-      phonehub::FeatureStatus::kUnavailableBluetoothOff);
-  feature_status_provider_->SetStatus(
-      phonehub::FeatureStatus::kLockOrSuspended);
-  feature_status_provider_->SetStatus(
-      phonehub::FeatureStatus::kEnabledAndConnected);
-
-  // Removing and readding the notification (e.g. across disconnects) should
-  // downgrade the priority so it doesn't pop-up again.
+  // Removing and readding the old notification (e.g. across disconnects) should
+  // not show a pop-up either.
   notification_manager_->RemoveNotification(kPhoneHubNotificationId0);
   ASSERT_FALSE(FindNotification(kCrOSNotificationId0));
   notification_manager_->SetNotification(fake_notification);
@@ -469,21 +464,9 @@
   ASSERT_TRUE(cros_notification);
   EXPECT_EQ(message_center::LOW_PRIORITY, cros_notification->priority());
 
-  // Disable the feature.
-  feature_status_provider_->SetStatus(phonehub::FeatureStatus::kDisabled);
-  notification_manager_->RemoveNotification(kPhoneHubNotificationId0);
-  ASSERT_FALSE(FindNotification(kCrOSNotificationId0));
-
-  // Reconnect and notification should be reshown as a pop-up.
-  feature_status_provider_->SetStatus(
-      phonehub::FeatureStatus::kEnabledAndConnected);
-  notification_manager_->SetNotification(fake_notification);
-  cros_notification = FindNotification(kCrOSNotificationId0);
-  ASSERT_TRUE(cros_notification);
-  EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority());
-
-  // Update the notification with some new text, but keep the notification ID
-  // the same.
+  // Update the notification with some new text and a recent timestamp, but keep
+  // the notification ID the same. Add a few extra seconds as a preemptive
+  // measure against test flakiness.
   phonehub::Notification modified_fake_notification(
       kPhoneHubNotificationId0,
       phonehub::Notification::AppMetadata(
@@ -495,13 +478,22 @@
       {{phonehub::Notification::ActionType::kInlineReply, 0}},
       phonehub::Notification::InteractionBehavior::kNone, kTitle, u"New text");
 
-  // Update the existingt notification; the priority should be MAX_PRIORITY, and
+  // Update the existing notification; the priority should be MAX_PRIORITY, and
   // renotify should be true.
   notification_manager_->SetNotification(modified_fake_notification);
   cros_notification = FindNotification(kCrOSNotificationId0);
   ASSERT_TRUE(cros_notification);
   EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority());
   EXPECT_TRUE(cros_notification->renotify());
+
+  // Removing and readding the same recent notification (e.g. across
+  // disconnects) should still show a pop-up.
+  notification_manager_->RemoveNotification(kPhoneHubNotificationId0);
+  ASSERT_FALSE(FindNotification(kCrOSNotificationId0));
+  notification_manager_->SetNotification(modified_fake_notification);
+  cros_notification = FindNotification(kCrOSNotificationId0);
+  ASSERT_TRUE(cros_notification);
+  EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority());
 }
 
 // Regression test for https://crbug.com/1165646.
diff --git a/ash/system/phonehub/phone_hub_tray.cc b/ash/system/phonehub/phone_hub_tray.cc
index 9be39daa..87af87a 100644
--- a/ash/system/phonehub/phone_hub_tray.cc
+++ b/ash/system/phonehub/phone_hub_tray.cc
@@ -62,9 +62,6 @@
   if (features::IsEcheCustomWidgetEnabled()) {
     auto eche_icon = std::make_unique<views::ImageButton>(base::BindRepeating(
         &PhoneHubTray::EcheIconActivated, weak_factory_.GetWeakPtr()));
-    // TODO(nayebi): Needs a different tooltip text.
-    eche_icon->SetTooltipText(
-        l10n_util::GetStringUTF16(IDS_ASH_PHONE_HUB_TRAY_ACCESSIBLE_NAME));
     eche_icon->SetImageVerticalAlignment(
         views::ImageButton::VerticalAlignment::ALIGN_MIDDLE);
     eche_icon->SetVisible(false);
diff --git a/ash/system/phonehub/phone_hub_ui_controller_unittest.cc b/ash/system/phonehub/phone_hub_ui_controller_unittest.cc
index cef3c67..a0abf0a 100644
--- a/ash/system/phonehub/phone_hub_ui_controller_unittest.cc
+++ b/ash/system/phonehub/phone_hub_ui_controller_unittest.cc
@@ -326,7 +326,7 @@
 TEST_F(PhoneHubUiControllerTest, HandleBubbleOpenedShouldCloseEcheBubble) {
   EcheTray* eche_tray =
       StatusAreaWidgetTestHelper::GetStatusAreaWidget()->eche_tray();
-  eche_tray->LoadBubble(GURL("http://google.com"), gfx::Image());
+  eche_tray->LoadBubble(GURL("http://google.com"), gfx::Image(), u"app 1");
   eche_tray->ShowBubble();
   EXPECT_TRUE(
       eche_tray->get_bubble_wrapper_for_test()->bubble_view()->GetVisible());
diff --git a/ash/system/time/calendar_view.cc b/ash/system/time/calendar_view.cc
index 77115e2..104d9505 100644
--- a/ash/system/time/calendar_view.cc
+++ b/ash/system/time/calendar_view.cc
@@ -454,11 +454,11 @@
   // Removes child views including month views and event list to remove their
   // dependency from `CalendarViewController`, since these views are destructed
   // after the controller.
-  content_view_->RemoveAllChildViews();
   if (event_list_view_) {
     RemoveChildViewT(event_list_view_);
     event_list_view_ = nullptr;
   }
+  content_view_->RemoveAllChildViews();
 }
 
 void CalendarView::CreateExtraTitleRowButtons() {
diff --git a/ash/system/tray/hover_highlight_view.h b/ash/system/tray/hover_highlight_view.h
index 00b0620..1a52fc5 100644
--- a/ash/system/tray/hover_highlight_view.h
+++ b/ash/system/tray/hover_highlight_view.h
@@ -25,7 +25,7 @@
 // A view that changes background color on hover, and triggers a callback in the
 // associated ViewClickListener on click. The view can also be forced to
 // maintain a fixed height.
-class HoverHighlightView : public ActionableView {
+class ASH_EXPORT HoverHighlightView : public ActionableView {
  public:
   enum class AccessibilityState {
     // The default accessibility view.
diff --git a/ash/webui/common/resources/keyboard_diagram.html b/ash/webui/common/resources/keyboard_diagram.html
index bb790653..d40dadc4 100644
--- a/ash/webui/common/resources/keyboard_diagram.html
+++ b/ash/webui/common/resources/keyboard_diagram.html
@@ -122,12 +122,28 @@
 
   /* Modifications for ISO */
 
+  #isoKey {
+    display: none;
+  }
+
+  [data-mech-layout='iso'] #isoKey {
+    display: block;
+  }
+
   [data-mech-layout='iso'] #leftShiftKey {
     grid-column: span 3;
   }
 
   /* Modifications for JIS */
 
+  .jis-only {
+    display: none;
+  }
+
+  [data-mech-layout='jis'] .jis-only {
+    display: block;
+  }
+
   /*
    * JIS crams in a few more keys, most notably an additional one on the number
    * row, so a 30-column grid makes more sense for it.
@@ -267,9 +283,8 @@
     <keyboard-key data-code="11"></keyboard-key>
     <keyboard-key data-code="12"></keyboard-key>
     <keyboard-key data-code="13"></keyboard-key>
-    <template is="dom-if" if="[[isEqual_(mechanicalLayout, 'jis')]]">
-      <keyboard-key id="jisYenKey" data-code="124"></keyboard-key>
-    </template>
+    <keyboard-key id="jisYenKey" class="jis-only" data-code="124">
+    </keyboard-key>
     <keyboard-key
         id="backspaceKey"
         class="right"
@@ -333,9 +348,12 @@
         data-code="42"
         aria-name="[[i18n('keyboardDiagramAriaNameShiftLeft')]]">
     </keyboard-key>
-    <template is="dom-if" if="[[isEqual_(mechanicalLayout, 'iso')]]">
-      <keyboard-key id="isoKey" bottom-left-glyph="&lt;" top-left-glyph="&gt;" data-code="86"></keyboard-key>
-    </template>
+    <keyboard-key
+        id="isoKey"
+        bottom-left-glyph="&lt;"
+        top-left-glyph="&gt;"
+        data-code="86">
+    </keyboard-key>
     <keyboard-key data-code="44"></keyboard-key>
     <keyboard-key data-code="45"></keyboard-key>
     <keyboard-key data-code="46"></keyboard-key>
@@ -346,9 +364,7 @@
     <keyboard-key data-code="51"></keyboard-key>
     <keyboard-key data-code="52"></keyboard-key>
     <keyboard-key data-code="53"></keyboard-key>
-    <template is="dom-if" if="[[isEqual_(mechanicalLayout, 'jis')]]">
-      <keyboard-key id="jisBackslashKey" data-code="89"></keyboard-key>
-    </template>
+    <keyboard-key id="jisBackslashKey" class="jis-only" data-code="89"></keyboard-key>
     <keyboard-key
         id="rightShiftKey"
         class="right"
@@ -375,13 +391,19 @@
       </keyboard-key>
     </template>
     <keyboard-key id="leftAltKey" class="left" main-glyph="alt" data-code="56"></keyboard-key>
-    <template is="dom-if" if="[[isEqual_(mechanicalLayout, 'jis')]]">
-      <keyboard-key id="jisAlphanumericKey" main-glyph="英数" data-code="94"></keyboard-key>
-    </template>
+    <keyboard-key
+        id="jisAlphanumericKey"
+        class="jis-only"
+        main-glyph="英数"
+        data-code="94">
+    </keyboard-key>
     <keyboard-key id="spacebar" main-glyph="" data-code="57"></keyboard-key>
-    <template is="dom-if" if="[[isEqual_(mechanicalLayout, 'jis')]]">
-      <keyboard-key id="jisKanaKey" main-glyph="かな" data-code="92"></keyboard-key>
-    </template>
+    <keyboard-key
+        id="jisKanaKey"
+        class="jis-only"
+        main-glyph="かな"
+        data-code="92">
+    </keyboard-key>
     <keyboard-key id="rightAltKey" main-glyph="alt" data-code="100"></keyboard-key>
     <keyboard-key id="rightCtrlKey" main-glyph="ctrl" data-code="97"></keyboard-key>
 
diff --git a/ash/webui/eche_app_ui/eche_tray_stream_status_observer.cc b/ash/webui/eche_app_ui/eche_tray_stream_status_observer.cc
index fc0fadb7..f5ac2e8 100644
--- a/ash/webui/eche_app_ui/eche_tray_stream_status_observer.cc
+++ b/ash/webui/eche_app_ui/eche_tray_stream_status_observer.cc
@@ -20,10 +20,12 @@
 
 namespace eche_app {
 
-void LaunchBubble(const GURL& url, const gfx::Image& icon) {
+void LaunchBubble(const GURL& url,
+                  const gfx::Image& icon,
+                  const std::u16string& visible_name) {
   auto* eche_tray = ash::GetEcheTray();
   DCHECK(eche_tray);
-  eche_tray->LoadBubble(url, icon);
+  eche_tray->LoadBubble(url, icon, visible_name);
 }
 
 void CloseBubble() {
diff --git a/ash/webui/eche_app_ui/eche_tray_stream_status_observer.h b/ash/webui/eche_app_ui/eche_tray_stream_status_observer.h
index b560b8b..6ed372f 100644
--- a/ash/webui/eche_app_ui/eche_tray_stream_status_observer.h
+++ b/ash/webui/eche_app_ui/eche_tray_stream_status_observer.h
@@ -20,7 +20,9 @@
 // It is called from chrome/browser/ash/eche_app/eche_app_manager_factory.cc.
 // Move all logic about Eche tray to here because we don't want to call
 // `GetEcheTray` everywhere.
-void LaunchBubble(const GURL& url, const gfx::Image& icon);
+void LaunchBubble(const GURL& url,
+                  const gfx::Image& icon,
+                  const std::u16string& visible_name);
 
 // It is called from chrome/browser/ash/eche_app/eche_app_manager_factory.cc.
 void CloseBubble();
diff --git a/ash/webui/eche_app_ui/eche_tray_stream_status_observer_unittest.cc b/ash/webui/eche_app_ui/eche_tray_stream_status_observer_unittest.cc
index 8f332ca..c01c449 100644
--- a/ash/webui/eche_app_ui/eche_tray_stream_status_observer_unittest.cc
+++ b/ash/webui/eche_app_ui/eche_tray_stream_status_observer_unittest.cc
@@ -70,7 +70,7 @@
 };
 
 TEST_F(EcheTrayStreamStatusObserverTest, LaunchBubble) {
-  LaunchBubble(GURL("http://google.com"), gfx::Image());
+  LaunchBubble(GURL("http://google.com"), gfx::Image(), u"app 1");
 
   // Wait for Eche Tray to load Eche Web to complete.
   base::RunLoop().RunUntilIdle();
@@ -95,7 +95,7 @@
   // The bubble should not be created if LaunchBubble be called before.
   EXPECT_FALSE(eche_tray()->get_bubble_wrapper_for_test());
 
-  LaunchBubble(GURL("http://google.com"), gfx::Image());
+  LaunchBubble(GURL("http://google.com"), gfx::Image(), u"app 1");
 
   // Wait for Eche Tray to load Eche Web to complete.
   base::RunLoop().RunUntilIdle();
@@ -113,7 +113,7 @@
 }
 
 TEST_F(EcheTrayStreamStatusObserverTest, OnStreamStatusChanged) {
-  LaunchBubble(GURL("http://google.com"), gfx::Image());
+  LaunchBubble(GURL("http://google.com"), gfx::Image(), u"app 1");
   OnStreamStatusChanged(mojom::StreamStatus::kStreamStatusStarted);
 
   // Wait for Eche Tray to load Eche Web to complete.
diff --git a/ash/webui/personalization_app/mojom/personalization_app.mojom b/ash/webui/personalization_app/mojom/personalization_app.mojom
index 6a7d426..bd05c57 100644
--- a/ash/webui/personalization_app/mojom/personalization_app.mojom
+++ b/ash/webui/personalization_app/mojom/personalization_app.mojom
@@ -73,8 +73,8 @@
     // Name of this collection to be displayed to the user.
     string name;
 
-    // The url for the preview image of this collection.
-    url.mojom.Url? preview;
+    // The preview image URLs of this collection.
+    array<url.mojom.Url> previews;
 };
 
 // Encapsulates metadata for a Google Photos album, which is itself displayed in
diff --git a/ash/webui/personalization_app/mojom/personalization_app_mojom_traits.cc b/ash/webui/personalization_app/mojom/personalization_app_mojom_traits.cc
index 6645b2ee3..019f0e3 100644
--- a/ash/webui/personalization_app/mojom/personalization_app_mojom_traits.cc
+++ b/ash/webui/personalization_app/mojom/personalization_app_mojom_traits.cc
@@ -179,10 +179,14 @@
   return collection.collection_name();
 }
 
-absl::optional<GURL> StructTraits<
+std::vector<GURL> StructTraits<
     ash::personalization_app::mojom::WallpaperCollectionDataView,
-    backdrop::Collection>::preview(const backdrop::Collection& collection) {
-  return GURL(collection.preview(0).image_url());
+    backdrop::Collection>::previews(const backdrop::Collection& collection) {
+  std::vector<GURL> previews;
+  for (const auto& image : collection.preview()) {
+    previews.push_back(GURL(image.image_url()));
+  }
+  return previews;
 }
 
 // Default to false as we don't ever need to convert back to
diff --git a/ash/webui/personalization_app/mojom/personalization_app_mojom_traits.h b/ash/webui/personalization_app/mojom/personalization_app_mojom_traits.h
index ac3a669..5a08988 100644
--- a/ash/webui/personalization_app/mojom/personalization_app_mojom_traits.h
+++ b/ash/webui/personalization_app/mojom/personalization_app_mojom_traits.h
@@ -57,7 +57,7 @@
     backdrop::Collection> {
   static const std::string& id(const backdrop::Collection& collection);
   static const std::string& name(const backdrop::Collection& collection);
-  static absl::optional<GURL> preview(const backdrop::Collection& collection);
+  static std::vector<GURL> previews(const backdrop::Collection& collection);
 
   static bool Read(
       ash::personalization_app::mojom::WallpaperCollectionDataView data,
diff --git a/ash/webui/personalization_app/resources/common/styles.html b/ash/webui/personalization_app/resources/common/styles.html
index 388c048..196633e 100644
--- a/ash/webui/personalization_app/resources/common/styles.html
+++ b/ash/webui/personalization_app/resources/common/styles.html
@@ -114,6 +114,14 @@
       object-fit: cover;
       width: 100%;
     }
+    .photo-images-container img.left {
+      clip-path: inset(0 50% 0 0);
+      position: absolute;
+    }
+    .photo-images-container img.right {
+      clip-path: inset(0 0 0 50%);
+      position: absolute;
+    }
     @keyframes scale-up {
       from {
         transform: scale(0);
@@ -262,5 +270,11 @@
       width: 33%;
       height: 20px;
     }
+
+    .ambient-subpage-element-title {
+      color: var(--cros-text-color-primary);
+      font: var(--personalization-app-label-font);
+      margin: 34px 8px 16px 8px;
+    }
   </style>
 </template>
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.html b/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.html
index 7577600..3fcdf8f 100644
--- a/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.html
+++ b/ash/webui/personalization_app/resources/trusted/ambient/ambient_preview_element.html
@@ -52,7 +52,8 @@
     display: block;
   }
 
-  :host([main-page]) #imageContainer {
+  :host([main-page]) #imageContainer,
+  :host([main-page]) #imagePlaceholder {
     display: flex;
     height: 100%;
     justify-self: center;
@@ -99,12 +100,13 @@
     opacity: var(--cros-disabled-opacity);
   }
 
-  :host(:not([main-page])) #collageContainer {
+  :host(:not([main-page])) #collageContainer,
+  :host(:not([main-page])) #collagePlaceholder {
     display: none;
   }
 
-  :host([main-page]) #collageContainer {
-    border: 1px solid rgba(0, 0, 0, 0.08);
+  :host([main-page]) #collageContainer,
+  :host([main-page]) #collagePlaceholder {
     border-radius: 12px;
     display: grid;
     gap: 2px;
@@ -112,6 +114,10 @@
     overflow: hidden;
   }
 
+  :host([main-page]) #collageContainer {
+    border: 1px solid rgba(0, 0, 0, 0.08);
+  }
+
   #collageContainer {
     grid-template-columns: repeat(2, minmax(0,1fr));
     grid-template-rows: repeat(2, minmax(0,1fr));
@@ -143,6 +149,7 @@
       <div class="placeholder"></div>
       <div class="placeholder"></div>
     </div>
+    <div id="collagePlaceholder" class="placeholder"></div>
   </template>
   <template is="dom-if" if="[[!loading_]]">
     <template is="dom-if" if="[[!ambientModeEnabled_]]">
@@ -157,14 +164,8 @@
       </div>
     </template>
     <template is="dom-if" if="[[ambientModeEnabled_]]">
-      <template is="dom-if" if="[[!previewAlbums_]]">
-        <div id="imagePlaceholder" class="placeholder"></div>
-        <div id="textPlaceholder" class="preview-text-placeholder album-info-mainpage album-info-subpage">
-          <div class="placeholder currently-set-text"></div>
-          <div class="placeholder"></div>
-          <div class="placeholder"></div>
-        </div>
-      </template>
+      <!-- TODO(b/226235802) - Add failed/error state when no previewAlbums available.
+           Currently, we show blank containers -->
       <template is="dom-if" if="[[previewAlbums_]]">
         <div id="imageContainer" class="preview-image-container" aria-hidden="true">
           <img class="preview-image" is="cr-auto-img"
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/ambient_subpage_element.html b/ash/webui/personalization_app/resources/trusted/ambient/ambient_subpage_element.html
index 707042d..c46510e 100644
--- a/ash/webui/personalization_app/resources/trusted/ambient/ambient_subpage_element.html
+++ b/ash/webui/personalization_app/resources/trusted/ambient/ambient_subpage_element.html
@@ -1,10 +1,9 @@
-<style>
+<style include="common-style">
   #mainSettings {
     display: grid;
     grid-template-areas:
       '. . toggles   . .'
       '. . zeroState . .'
-      '. . spinner   . .'
       '. . preview   . .'
       '. . animation . .'
       '. . sources   . .'
@@ -19,26 +18,21 @@
   ambient-zero-state {
     grid-area: zeroState;
   }
-  paper-spinner-lite {
-    grid-area: spinner;
-    height: 28px;
-    margin: 100px auto;
-    width: 28px;
-  }
   ambient-preview {
     grid-area: preview;
     margin: 20px 8px 0 8px;
   }
-  animation-theme-list {
+  animation-theme-list,
+  #animationThemePlaceholder {
     grid-area: animation;
   }
-  topic-source-list {
+  topic-source-list,
+  #topicSourcePlaceholder {
     grid-area: sources;
-    margin: 0 8px;
   }
-  ambient-weather-unit {
+  ambient-weather-unit,
+  #weatherUnitPlaceholder {
     grid-area: weather;
-    margin: 0 8px 48px 8px;
   }
   #albumsSubpage {
     display: grid;
@@ -52,6 +46,73 @@
   albums-subpage {
     grid-area: albums-subpage;
   }
+  iron-list {
+    height: 100%;
+    overflow: hidden;
+    width: 100%;
+  }
+  .animation-placeholder-container {
+    box-sizing: border-box;
+    overflow: hidden;
+    padding: calc(var(--personalization-app-grid-item-spacing) / 2);
+    /* Subtract 0.34px to fix subpixel rounding issues with iron-list. This
+     * ensures all grid items in a row add up to at least 1px smaller than the
+     * parent width. */
+    width: calc(100% / 3 - 0.34px);
+  }
+  @media(min-width: 720px) {
+    .animation-placeholder-container {
+      /* Subtract 0.25px to fix subpixel rounding issues with iron-list. This
+       * ensures all grid items in a row add up to at least 1px smaller than the
+       * parent width. */
+      width: calc(100% / 4 - 0.25px) !important;
+    }
+  }
+  .animation-item-placeholder {
+    align-items: center;
+    border-radius: var(--personalization-app-grid-item-border-radius);
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+    height: 156px;
+    justify-content: center;
+    overflow: hidden;
+    position: relative;
+    width: 100%;
+  }
+  .animation-item-title-placeholder {
+    margin-top: 8px;
+  }
+  div[class^='ambient-text-placeholder'] {
+    align-items: flex-start;
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    overflow: hidden;
+    padding-inline: var(--cr-section-padding) var(--cr-icon-ripple-padding); 
+    width: 100%;
+  }
+  #topicSourceTextPlaceholder {
+    height: 64px;
+  }
+  #weatherUnitTextPlaceholder {
+    height: 48px;
+  }
+  .ambient-text-placeholder-0 {
+    border-bottom: 1px solid var(--cros-separator-color);
+  }
+  div[class^='ambient-text-placeholder'] > * + * {
+    margin-top: 8px;
+  }
+  .ambient-primary-text-placeholder {
+    height: 20px;
+    width: 75%;
+  }
+  .ambient-secondary-text-placeholder {
+    height: 20px;
+    width: 50%;
+  }
 </style>
 <div id="container">
   <template is="dom-if" if="[[shouldShowMainSettings_(path)]]">
@@ -60,13 +121,49 @@
           on-click="onClickAmbientModeButton_" on-change="onToggleStateChanged_">
       </toggle-row>
       <template is="dom-if" if="[[ambientModeEnabled_]]">
+        <ambient-preview></ambient-preview>
         <template is="dom-if" if="[[loadingSettings_]]">
-          <!-- TODO(b/217311018): Add loading state -->
-          <paper-spinner-lite active></paper-spinner-lite>
+          <div id="animationThemePlaceholder">
+            <h3 id="animationTitle" class="ambient-subpage-element-title" aria-hidden="true">
+              $i18n{ambientModeAnimationTitle}
+            </h3>
+            <iron-list items="[[getPlaceholders_(3)]]" grid>
+              <template>
+                <div class="animation-placeholder-container">
+                  <div class="animation-item-placeholder placeholder"></div>
+                  <div class="animation-item-title-placeholder 
+                      ambient-primary-text-placeholder placeholder"></div>
+                </div>
+              </template>
+            </iron-list>
+          </div>
+          <div id="topicSourcePlaceholder">
+            <h3 id="topicSourceTitle" class="ambient-subpage-element-title" aria-hidden="true">
+              $i18n{ambientModeTopicSourceTitle}
+            </h3>
+            <iron-list items="[[getPlaceholders_(2)]]" grid>
+              <template>
+                  <div id="topicSourceTextPlaceholder" class$="{{getClassContainer_(index)}}">
+                    <div class="ambient-primary-text-placeholder placeholder"></div>
+                    <div class="ambient-secondary-text-placeholder placeholder"></div>
+                  </div>
+              </template>
+            </iron-list>
+          </div>
+          <div id="weatherUnitPlaceholder">
+            <h3 id="weatherTitle" class="ambient-subpage-element-title" aria-hidden="true">
+              $i18n{ambientModeWeatherTitle}
+            </h3>
+            <iron-list items="[[getPlaceholders_(2)]]" grid>
+              <template>
+                <div id="weatherUnitTextPlaceholder" class$="{{getClassContainer_(index)}}">
+                  <div class="ambient-secondary-text-placeholder placeholder"></div>
+                </div>
+              </template>
+            </iron-list>
+          </div>
         </template>
-
         <template is="dom-if" if="[[!loadingSettings_]]">
-          <ambient-preview></ambient-preview>
           <animation-theme-list selected-animation-theme="[[animationTheme_]]"
               disabled$="[[disabled_]]">
           </animation-theme-list>
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/ambient_subpage_element.ts b/ash/webui/personalization_app/resources/trusted/ambient/ambient_subpage_element.ts
index 67de828..8518eea 100644
--- a/ash/webui/personalization_app/resources/trusted/ambient/ambient_subpage_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/ambient/ambient_subpage_element.ts
@@ -7,7 +7,7 @@
  * the ambient mode settings.
  */
 
-import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
+import '../../common/styles.js';
 import './albums_subpage_element.js';
 import './ambient_weather_element.js';
 import './ambient_preview_element.js';
@@ -18,6 +18,7 @@
 import {AmbientModeAlbum, AnimationTheme, TemperatureUnit, TopicSource} from '../personalization_app.mojom-webui.js';
 import {Paths} from '../personalization_router_element.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
+import {getZerosArray} from '../utils.js';
 
 import {setAmbientModeEnabled} from './ambient_controller.js';
 import {getAmbientProvider} from './ambient_interface_provider.js';
@@ -147,6 +148,14 @@
   private computeDisabled_(): boolean {
     return this.ambientModeEnabled_ !== null && !this.ambientModeEnabled_;
   }
+
+  private getPlaceholders_(x: number): number[] {
+    return getZerosArray(x);
+  }
+
+  private getClassContainer_(x: number): string {
+    return `ambient-text-placeholder-${x}`;
+  }
 }
 
 customElements.define(AmbientSubpage.is, AmbientSubpage);
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/ambient_weather_element.html b/ash/webui/personalization_app/resources/trusted/ambient/ambient_weather_element.html
index 66f4dcc..7ba3391 100644
--- a/ash/webui/personalization_app/resources/trusted/ambient/ambient_weather_element.html
+++ b/ash/webui/personalization_app/resources/trusted/ambient/ambient_weather_element.html
@@ -1,10 +1,4 @@
-<style>
-  #weatherTitle {
-    color: var(--cros-text-color-primary);
-    font: var(--personalization-app-label-font);
-    margin-bottom: 16px;
-    margin-top: 34px;
-  }
+<style include="common-style">
   cr-radio-group {
     width: 100%;
   }
@@ -17,7 +11,7 @@
   }
 </style>
 <div id="weatherDiv">
-  <h3 id="weatherTitle" aria-hidden="true">
+  <h3 class="ambient-subpage-element-title" aria-hidden="true">
     $i18n{ambientModeWeatherTitle}
   </h3>
   <div class="weather-unit-list">
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/ambient_weather_element.ts b/ash/webui/personalization_app/resources/trusted/ambient/ambient_weather_element.ts
index 18d17ee..c9e54c9 100644
--- a/ash/webui/personalization_app/resources/trusted/ambient/ambient_weather_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/ambient/ambient_weather_element.ts
@@ -7,6 +7,7 @@
  * behaviors similar to a radio button group, e.g. single selection.
  */
 
+import '../../common/styles.js';
 import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.m.js';
 import 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.m.js';
 import 'chrome://resources/cr_elements/shared_style_css.m.js';
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/animation_theme_list_element.html b/ash/webui/personalization_app/resources/trusted/ambient/animation_theme_list_element.html
index c9c8feb..812e02e 100644
--- a/ash/webui/personalization_app/resources/trusted/ambient/animation_theme_list_element.html
+++ b/ash/webui/personalization_app/resources/trusted/ambient/animation_theme_list_element.html
@@ -1,9 +1,4 @@
-<style>
-  #animationTitle {
-    color: var(--cros-text-color-primary);
-    font: var(--personalization-app-label-font);
-    margin: 34px 8px 16px 8px;
-  }
+<style include="common-style">
   #animationThemeList {
     display: flex;
     flex-direction: row;
@@ -14,7 +9,7 @@
   }
 </style>
 
-<h3 id="animationTitle" aria-hidden="true">
+<h3 class="ambient-subpage-element-title" aria-hidden="true">
   $i18n{ambientModeAnimationTitle}
 </h3>
 <iron-list id="grid" items="[[animationThemes]]" as="theme" grid>
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/animation_theme_list_element.ts b/ash/webui/personalization_app/resources/trusted/ambient/animation_theme_list_element.ts
index ee1fbd4..1832812e 100644
--- a/ash/webui/personalization_app/resources/trusted/ambient/animation_theme_list_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/ambient/animation_theme_list_element.ts
@@ -6,6 +6,7 @@
  * @fileoverview The element for displaying a list of animation themes.
  */
 import './animation_theme_item_element.js';
+import '../../common/styles.js';
 
 import {AnimationTheme} from '../personalization_app.mojom-webui.js';
 import {WithPersonalizationStore} from '../personalization_store.js';
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/topic_source_list_element.html b/ash/webui/personalization_app/resources/trusted/ambient/topic_source_list_element.html
index 501f139..37f2393 100644
--- a/ash/webui/personalization_app/resources/trusted/ambient/topic_source_list_element.html
+++ b/ash/webui/personalization_app/resources/trusted/ambient/topic_source_list_element.html
@@ -1,11 +1,4 @@
-<style>
-  #topicSourceTitle {
-    color: var(--cros-text-color-primary);
-    font: var(--personalization-app-label-font);
-    margin-bottom: 16px;
-    margin-top: 34px;
-  }
-
+<style include="common-style">
   topic-source-item {
     align-items: center;
     height: 64px;
@@ -20,7 +13,7 @@
   }
 </style>
 
-<h3 id="topicSourceTitle" aria-hidden="true">
+<h3 class="ambient-subpage-element-title" aria-hidden="true">
   $i18n{ambientModeTopicSourceTitle}
 </h3>
 
diff --git a/ash/webui/personalization_app/resources/trusted/ambient/topic_source_list_element.ts b/ash/webui/personalization_app/resources/trusted/ambient/topic_source_list_element.ts
index f1cd191..78841d2 100644
--- a/ash/webui/personalization_app/resources/trusted/ambient/topic_source_list_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/ambient/topic_source_list_element.ts
@@ -7,6 +7,7 @@
  * behaviors similar to a radio button group, e.g. single selection.
  */
 
+import '../../common/styles.js';
 import './topic_source_item_element.js';
 import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
 
diff --git a/ash/webui/personalization_app/resources/trusted/utils.ts b/ash/webui/personalization_app/resources/trusted/utils.ts
index 13d313d6..8f1c95f4 100644
--- a/ash/webui/personalization_app/resources/trusted/utils.ts
+++ b/ash/webui/personalization_app/resources/trusted/utils.ts
@@ -123,3 +123,10 @@
       return '';
   }
 }
+
+/**
+ * Returns a x-length dummy array of zeros (0s)
+ */
+export function getZerosArray(x: number): number[] {
+  return new Array(x).fill(0);
+}
diff --git a/ash/webui/personalization_app/resources/untrusted/collections_grid.html b/ash/webui/personalization_app/resources/untrusted/collections_grid.html
index 2ca0b6d..4fb3f81 100644
--- a/ash/webui/personalization_app/resources/untrusted/collections_grid.html
+++ b/ash/webui/personalization_app/resources/untrusted/collections_grid.html
@@ -127,6 +127,7 @@
           <div class$="[[getClassForImagesContainer_(item)]]">
             <template is="dom-repeat" items="[[item.preview]]" as="preview">
               <img is="cr-auto-img" auto-src="[[preview.url]]"
+                  class$="[[getClassForImg_(index, item)]]"
                   aria-hidden="true" on-load="onImgLoad_" on-error="onImgLoad_"
                   with-cookies="[[isGooglePhotosTile_(item)]]" clear-src>
             </template>
diff --git a/ash/webui/personalization_app/resources/untrusted/collections_grid.ts b/ash/webui/personalization_app/resources/untrusted/collections_grid.ts
index ce8b17c..1e6934d 100644
--- a/ash/webui/personalization_app/resources/untrusted/collections_grid.ts
+++ b/ash/webui/personalization_app/resources/untrusted/collections_grid.ts
@@ -12,7 +12,7 @@
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
 
 import {Events, EventType, kMaximumGooglePhotosPreviews, kMaximumLocalImagePreviews} from '../common/constants.js';
-import {getCountText, getLoadingPlaceholderAnimationDelay, getNumberOfGridItemsPerRow, isNullOrArray, isNullOrNumber, isSelectionEvent} from '../common/utils.js';
+import {getCountText, getLoadingPlaceholderAnimationDelay, getNumberOfGridItemsPerRow, isNonEmptyArray, isNullOrArray, isNullOrNumber, isSelectionEvent} from '../common/utils.js';
 import {WallpaperCollection} from '../trusted/personalization_app.mojom-webui.js';
 import {selectCollection, selectGooglePhotosCollection, selectLocalCollection, validateReceivedData} from '../untrusted/iframe_api.js';
 
@@ -31,7 +31,9 @@
 
 enum TileType {
   LOADING = 'loading',
-  IMAGE = 'image',
+  IMAGE_GOOGLE_PHOTOS = 'image_google_photos',
+  IMAGE_LOCAL = 'image_local',
+  IMAGE_ONLINE = 'image_online',
   FAILURE = 'failure',
 }
 
@@ -55,7 +57,7 @@
  * WallpaperCollection.
  */
 type ImageTile = {
-  type: TileType.IMAGE,
+  type: TileType.IMAGE_GOOGLE_PHOTOS|TileType.IMAGE_LOCAL|TileType.IMAGE_ONLINE,
   id: string,
   name: string,
   count: string,
@@ -80,7 +82,7 @@
     preview: Array.isArray(googlePhotos) ?
         googlePhotos.slice(0, kMaximumGooglePhotosPreviews) :
         [],
-    type: TileType.IMAGE,
+    type: TileType.IMAGE_GOOGLE_PHOTOS,
   };
 }
 
@@ -133,7 +135,7 @@
     count: getCountText(
         Array.isArray(localImages) ? localImages.length - failureCount : 0),
     preview: imagesToDisplay,
-    type: TileType.IMAGE,
+    type: TileType.IMAGE_LOCAL,
   };
 }
 
@@ -236,6 +238,9 @@
       this.pop('tiles_');
     }
 
+    const isDarkLightModeEnabled =
+        loadTimeData.getBoolean('isDarkLightModeEnabled');
+
     collections.forEach((collection, i) => {
       const index = i + offset;
       const tile = this.tiles_[index];
@@ -245,7 +250,7 @@
           id: collection.id,
           name: collection.name,
           count: '',
-          preview: [collection.preview],
+          preview: [],
           type: TileType.FAILURE,
         });
         return;
@@ -257,8 +262,13 @@
           id: collection.id,
           name: collection.name,
           count: getCountText(imageCounts[collection.id]),
-          preview: [collection.preview],
-          type: TileType.IMAGE,
+          // Return all the previews in D/L mode to display the split view.
+          // Otherwise, only the first preview is needed.
+          preview: isNonEmptyArray(collection.previews) ?
+              isDarkLightModeEnabled ? collection.previews :
+                                       [collection.previews[0]] :
+              [],
+          type: TileType.IMAGE_ONLINE,
         });
       }
     });
@@ -361,12 +371,31 @@
   }
 
   private getClassForImagesContainer_(tile: ImageTile): string {
+    if (tile.type === TileType.IMAGE_ONLINE) {
+      // Only apply base class for online collections.
+      return 'photo-images-container';
+    }
     const numImages =
         !!tile && Array.isArray(tile.preview) ? tile.preview.length : 0;
     return `photo-images-container photo-images-container-${
         Math.min(numImages, kMaximumLocalImagePreviews)}`;
   }
 
+  /** Apply custom class for <img> to show a split view. */
+  private getClassForImg_(index: number, tile: ImageTile): string {
+    if (tile.type !== TileType.IMAGE_ONLINE || tile.preview.length < 2) {
+      return '';
+    }
+    switch (index) {
+      case 0:
+        return 'left';
+      case 1:
+        return 'right';
+      default:
+        return '';
+    }
+  }
+
   getClassForEmptyTile_(tile: ImageTile): string {
     return `photo-inner-container ${
         (this.isGooglePhotosTile_(tile) ? 'google-photos-empty' :
@@ -415,17 +444,24 @@
     return !!item && item.type === TileType.FAILURE;
   }
 
+  private isTileTypeImage_(item: Tile|null): item is ImageTile {
+    return !!item &&
+        (item.type === TileType.IMAGE_GOOGLE_PHOTOS ||
+         item.type === TileType.IMAGE_LOCAL ||
+         item.type === TileType.IMAGE_ONLINE);
+  }
+
   private isEmptyTile_(item: Tile|null): item is ImageTile {
-    return !!item && item.type === TileType.IMAGE && item.preview.length === 0;
+    return this.isTileTypeImage_(item) && item.preview.length === 0;
   }
 
   private isGooglePhotosTile_(item: Tile|null): item is ImageTile|FailureTile {
-    return !!item && (item.type !== TileType.LOADING) &&
+    return !!item && (item.type === TileType.IMAGE_GOOGLE_PHOTOS) &&
         (item.id === kGooglePhotosCollectionId);
   }
 
   private isImageTile_(item: Tile|null): item is ImageTile {
-    return !!item && item.type === TileType.IMAGE && !this.isEmptyTile_(item);
+    return this.isTileTypeImage_(item) && !this.isEmptyTile_(item);
   }
 
   private isSelectableTile_(item: Tile|null): item is ImageTile|FailureTile {
diff --git a/ash/webui/personalization_app/resources/untrusted/images_grid.html b/ash/webui/personalization_app/resources/untrusted/images_grid.html
index c977b38..83688e31 100644
--- a/ash/webui/personalization_app/resources/untrusted/images_grid.html
+++ b/ash/webui/personalization_app/resources/untrusted/images_grid.html
@@ -2,14 +2,6 @@
   :host {
     margin: 12px 0;
   }
-  .photo-images-container img.left {
-    clip-path: inset(0 50% 0 0);
-    position: absolute;
-  }
-  .photo-images-container img.right {
-    clip-path: inset(0 0 0 50%);
-    position: absolute;
-  }
 </style>
 <iron-list grid items="[[tiles_]]" role="listbox"
     aria-setsize$="[[tiles_.length]]">
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 4a2981d..3a91f16 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
@@ -34,6 +34,21 @@
     color: var(--cros-link-color);
     text-decoration: none;
   }
+
+  #qrCodeCanvas {
+      border: 1px solid;
+      border-color: var(--google-grey-200);
+      border-radius: 8px;
+      width: 268px;
+    }
+
+  #qrCodeWrapper {
+    align-items: center;
+    display: flex;
+    height: 100%;
+    justify-content: center;
+    width: 100%;
+  }
 </style>
 
 <base-page>
@@ -54,7 +69,9 @@
     </div>
   </div>
   <div slot="right-pane">
-    <canvas id="qrCodeCanvas" width="[[canvasSize_]]" height="[[canvasSize_]]">
+    <div id="qrCodeWrapper">
+      <canvas id="qrCodeCanvas" width="[[canvasSize_]]" height="[[canvasSize_]]">
+    </div>
     </canvas>
   </div>
 </base-page>
diff --git a/ash/webui/shimless_rma/resources/repair_component_chip.html b/ash/webui/shimless_rma/resources/repair_component_chip.html
index 3f748fe..a17f59b 100644
--- a/ash/webui/shimless_rma/resources/repair_component_chip.html
+++ b/ash/webui/shimless_rma/resources/repair_component_chip.html
@@ -23,24 +23,36 @@
     --vertical-padding: 24px;
     border-radius: 8px;
     box-shadow: var(--cros-elevation-1-shadow);
-    font-family: var(--shimless-component-font-family);
-    font-size: var(--shimless-component-font-size);
-    font-weight: var(--shimless-medium-font-weight);
-    height: calc((2 * var(--vertical-padding)) + 
-        (2 * var(--shimless-component-line-height)));
-    line-height: var(--shimless-component-line-height);
+    height: calc((2 * var(--vertical-padding)) +
+        var(--shimless-component-line-height) +
+        var(--shimless-component-description-line-height));
     padding: 0;
     width: 100%;
   }
 
   #labelDiv {
-    color: var(--shimless-component-text-color);
     flex-basis: 155px;
     inset-inline-start: 0;
     padding-inline-start: 24px;
     position: absolute;
   }
 
+  #componentName {
+    color: var(--shimless-component-text-color);
+    font-family: var(--shimless-component-font-family);
+    font-size: var(--shimless-component-font-size);
+    font-weight: var(--shimless-medium-font-weight);
+    line-height: var(--shimless-component-line-height);
+  }
+
+  #componentIdentifier {
+    color: var(--shimless-component-description-text-color);
+    font-family: var(--shimless-component-description-font-family);
+    font-size: var(--shimless-component-description-font-size);
+    font-weight: var(--shimless-regular-font-weight);
+    line-height: var(--shimless-component-description-line-height);
+  }
+
   :host([checked]) #labelDiv {
     color: var(--google-blue-700);
   }
diff --git a/ash/webui/shimless_rma/resources/shimless_rma_fonts_css.html b/ash/webui/shimless_rma/resources/shimless_rma_fonts_css.html
index a70e324..4b62d3f 100644
--- a/ash/webui/shimless_rma/resources/shimless_rma_fonts_css.html
+++ b/ash/webui/shimless_rma/resources/shimless_rma_fonts_css.html
@@ -4,6 +4,7 @@
       --shimless-title-font-family: "Google Sans", Roboto, sans-serif;
       --shimless-instructions-font-family: Roboto, sans-serif;
       --shimless-component-font-family: Roboto, sans-serif;
+      --shimless-component-description-font-family: Roboto, sans-serif;
       --shimless-hint-font-family: Roboto, sans-serif;
       --shimless-warning-font-family: Roboto, sans-serif;
       --shimless-button-label-font-family: "Google Sans", Roboto, sans-serif;
@@ -13,6 +14,7 @@
 
       --shimless-title-font-size: 28px;
       --shimless-component-font-size: 14px;
+      --shimless-component-description-font-size: 13px;
       --shimless-instructions-font-size: 14px;
       --shimless-hint-font-size: 10px;
       --shimless-warning-font-size: 12px;
@@ -24,6 +26,7 @@
       --shimless-title-line-height: 36px;
       --shimless-instructions-line-height: 20px;
       --shimless-component-line-height: 20px;
+      --shimless-component-description-line-height: 20px;
       --shimless-hint-line-height: 10px;
       --shimless-warning-line-height: 18px;
       --shimless-button-label-line-height: 24px;
@@ -37,6 +40,7 @@
       --shimless-title-text-color: var(--cros-text-color-primary);
       --shimless-instructions-text-color: var(--cros-text-color-secondary);
       --shimless-component-text-color: var(--cros-text-color-secondary);
+      --shimless-component-description-text-color: var(--cros-text-color-secondary);
       --shimless-hint-text-color: var(--google-grey-600);
       --shimless-warning-text-color: var(--cros-text-color-secondary);
       --shimless-button-label-text-color: var(--cros-text-color-primary);
diff --git a/ash/wm/desks/templates/desks_templates_grid_view.cc b/ash/wm/desks/templates/desks_templates_grid_view.cc
index d7c5231..2640532 100644
--- a/ash/wm/desks/templates/desks_templates_grid_view.cc
+++ b/ash/wm/desks/templates/desks_templates_grid_view.cc
@@ -166,7 +166,8 @@
 
 void DesksTemplatesGridView::PopulateGridUI(
     const std::vector<DeskTemplate*>& desk_templates,
-    const gfx::Rect& grid_bounds) {
+    const gfx::Rect& grid_bounds,
+    const base::GUID& last_saved_template_uuid) {
   DCHECK(grid_items_.empty());
 
   // TODO(richui|sammiequon): See if this can be removed as this function should
@@ -179,7 +180,8 @@
 
   AddOrUpdateTemplates(std::vector<const DeskTemplate*>(desk_templates.begin(),
                                                         desk_templates.end()),
-                       /*initializing_grid_view=*/true);
+                       /*initializing_grid_view=*/true,
+                       last_saved_template_uuid);
 
   if (!feedback_button_) {
     feedback_button_ = AddChildView(std::make_unique<PillButton>(
@@ -196,9 +198,52 @@
   GetWidget()->SetBounds(grid_bounds);
 }
 
+void DesksTemplatesGridView::SortTemplateGridItems(
+    const base::GUID& last_saved_template_uuid) {
+  // Sort the `grid_items_` into alphabetical order based on template name.
+  // Note that this doesn't update the order of the child views, but just sorts
+  // the vector. `Layout` is responsible for placing the views in the correct
+  // locations in the grid.
+  UErrorCode error_code = U_ZERO_ERROR;
+  std::unique_ptr<icu::Collator> collator(
+      icu::Collator::createInstance(error_code));  // Use current ICU locale.
+  DCHECK(U_SUCCESS(error_code));
+  // If there is a newly saved template, move that template to the front of the
+  // grid, and sort the rest of the templates after it.
+  std::sort(
+      grid_items_.begin(), grid_items_.end(),
+      [&collator, last_saved_template_uuid](const DesksTemplatesItemView* a,
+                                            const DesksTemplatesItemView* b) {
+        if (last_saved_template_uuid.is_valid() &&
+            a->uuid() == last_saved_template_uuid) {
+          return true;
+        }
+        if (last_saved_template_uuid.is_valid() &&
+            b->uuid() == last_saved_template_uuid) {
+          return false;
+        }
+        return base::i18n::CompareString16WithCollator(
+                   *collator, a->name_view()->GetAccessibleName(),
+                   b->name_view()->GetAccessibleName()) < 0;
+      });
+
+  // A11y traverses views based on the order of the children, so we need to
+  // manually reorder the child views to match the order that they are
+  // displayed, which is the alphabetically sorted `grid_items_` order. If
+  // there was a newly saved template, the first template in the grid will
+  // be the new template, while the rest will be sorted alphabetically.
+  for (size_t i = 0; i < grid_items_.size(); i++)
+    ReorderChildView(grid_items_[i], i);
+
+  if (bounds_animator_.IsAnimating())
+    bounds_animator_.Cancel();
+  Layout();
+}
+
 void DesksTemplatesGridView::AddOrUpdateTemplates(
     const std::vector<const DeskTemplate*>& entries,
-    bool initializing_grid_view) {
+    bool initializing_grid_view,
+    const base::GUID& last_saved_template_uuid) {
   std::vector<DesksTemplatesItemView*> new_grid_items;
 
   for (const DeskTemplate* entry : entries) {
@@ -218,32 +263,12 @@
     }
   }
 
-  // Sort the `grid_items_` into alphabetical order based on template name.
-  // Note that this doesn't update the order of the child views, but just sorts
-  // the vector. `Layout` is responsible for placing the views in the correct
-  // locations in the grid.
-  UErrorCode error_code = U_ZERO_ERROR;
-  std::unique_ptr<icu::Collator> collator(
-      icu::Collator::createInstance(error_code));  // Use current ICU locale.
-  DCHECK(U_SUCCESS(error_code));
+  // Sort the `grid_items_` into alphabetical order based on template name. If a
+  // given uuid is valid, it'll push that template item to the front of the grid
+  // and sort the remaining templates after it.
+  SortTemplateGridItems(last_saved_template_uuid);
 
-  std::sort(grid_items_.begin(), grid_items_.end(),
-            [&collator](const DesksTemplatesItemView* a,
-                        const DesksTemplatesItemView* b) {
-              return base::i18n::CompareString16WithCollator(
-                         *collator, a->name_view()->GetAccessibleName(),
-                         b->name_view()->GetAccessibleName()) < 0;
-            });
-
-  // A11y traverses views based on the order of the children, so we need to
-  // manually reorder the child views to match the order that they are
-  // displayed, which is the alphabetically sorted `grid_items_` order.
-  for (size_t i = 0; i < grid_items_.size(); i++)
-    ReorderChildView(grid_items_[i], i);
-
-  if (initializing_grid_view) {
-    Layout();
-  } else {
+  if (!initializing_grid_view) {
     AnimateGridItems(new_grid_items);
     NotifyAccessibilityEvent(ax::mojom::Event::kTreeChanged, true);
   }
diff --git a/ash/wm/desks/templates/desks_templates_grid_view.h b/ash/wm/desks/templates/desks_templates_grid_view.h
index 606d7b5..f7b3abe 100644
--- a/ash/wm/desks/templates/desks_templates_grid_view.h
+++ b/ash/wm/desks/templates/desks_templates_grid_view.h
@@ -43,14 +43,19 @@
   // Updates the UI by creating a grid layout and populating the grid with the
   // provided list of desk templates.
   void PopulateGridUI(const std::vector<DeskTemplate*>& desk_templates,
-                      const gfx::Rect& grid_bounds);
+                      const gfx::Rect& grid_bounds,
+                      const base::GUID& last_saved_template_uuid);
+
+  // Updates `grid_items_` to ensure the templates grid is sorted.
+  void SortTemplateGridItems(const base::GUID& last_saved_template_uuid);
 
   // Updates existing templates and adds new templates to the grid. Also sorts
   // `grid_items_` in alphabetical order. This will animate the `grid_items_` to
   // their final positions if `initializing_grid_view` is false. Currently only
   // allows a maximum of 6 templates to be shown in the grid.
   void AddOrUpdateTemplates(const std::vector<const DeskTemplate*>& entries,
-                            bool initializing_grid_view);
+                            bool initializing_grid_view,
+                            const base::GUID& last_saved_template_uuid);
 
   // Removes templates from the grid by UUID. Will trigger an animation to
   // shuffle `grid_items_` to their final positions.
diff --git a/ash/wm/desks/templates/desks_templates_item_view.cc b/ash/wm/desks/templates/desks_templates_item_view.cc
index b53c96d8..c22f33d 100644
--- a/ash/wm/desks/templates/desks_templates_item_view.cc
+++ b/ash/wm/desks/templates/desks_templates_item_view.cc
@@ -427,6 +427,18 @@
   if (!should_commit_name_changes_ || user_entered_name.empty() ||
       desk_template_->template_name() == user_entered_name) {
     OnTemplateNameChanged(desk_template_->template_name());
+    // Saving a desk template always puts it in the top left corner of the desk
+    // templates grid. This may mean that the grid is no longer sorted
+    // alphabetically by template name. Ensure that the grid is sorted.
+    for (auto& overview_grid : overview_session->grid_list()) {
+      if (views::Widget* grid_widget =
+              overview_grid->desks_templates_grid_widget()) {
+        auto* grid_view = static_cast<DesksTemplatesGridView*>(
+            grid_widget->GetContentsView());
+        grid_view->SortTemplateGridItems(
+            /*last_saved_template_uuid=*/base::GUID());
+      }
+    }
     return;
   }
 
diff --git a/ash/wm/desks/templates/desks_templates_presenter.cc b/ash/wm/desks/templates/desks_templates_presenter.cc
index eca25cb3..fb02235 100644
--- a/ash/wm/desks/templates/desks_templates_presenter.cc
+++ b/ash/wm/desks/templates/desks_templates_presenter.cc
@@ -246,11 +246,13 @@
       auto* grid_view =
           static_cast<DesksTemplatesGridView*>(grid_widget->GetContentsView());
       grid_view->PopulateGridUI(entries,
-                                overview_grid->GetGridEffectiveBounds());
+                                overview_grid->GetGridEffectiveBounds(),
+                                /*last_saved_template_uuid=*/item_to_focus);
       DesksTemplatesItemView* item_view =
           grid_view->GetItemForUUID(item_to_focus);
       if (!item_view)
         continue;
+
       item_view->MaybeRemoveNameNumber();
       if (grid_widget->GetNativeWindow()->GetRootWindow() == root_window)
         item_view->name_view()->RequestFocus();
@@ -382,7 +384,8 @@
     if (views::Widget* grid_widget =
             overview_grid->desks_templates_grid_widget()) {
       static_cast<DesksTemplatesGridView*>(grid_widget->GetContentsView())
-          ->AddOrUpdateTemplates(new_entries, /*initializing_grid_view=*/false);
+          ->AddOrUpdateTemplates(new_entries, /*initializing_grid_view=*/false,
+                                 /*last_saved_template_uuid=*/base::GUID());
     }
   }
 
diff --git a/ash/wm/desks/templates/desks_templates_unittest.cc b/ash/wm/desks/templates/desks_templates_unittest.cc
index a59674f..4fb3a2b 100644
--- a/ash/wm/desks/templates/desks_templates_unittest.cc
+++ b/ash/wm/desks/templates/desks_templates_unittest.cc
@@ -3141,7 +3141,7 @@
   WaitForDesksTemplatesUI();
   // Newly created template name_view.
   DesksTemplatesNameView* name_view =
-      GetItemViewFromTemplatesGrid(1)->name_view();
+      GetItemViewFromTemplatesGrid(0)->name_view();
   EXPECT_TRUE(name_view->HasFocus());
   OverviewGrid* overview_grid = GetOverviewGridList()[0].get();
   DeskNameView* desk_name_view =
@@ -3152,10 +3152,10 @@
   EXPECT_EQ(u"Desk 1", name_view->GetText());
   // The new template name still have name nudge to maintain it's uniqueness.
   EXPECT_EQ(u"Desk 1 (1)",
-            GetItemViewFromTemplatesGrid(1)->desk_template()->template_name());
+            GetItemViewFromTemplatesGrid(0)->desk_template()->template_name());
 
   // Set template 1 under new name.
-  GetItemViewFromTemplatesGrid(0)->desk_template()->set_template_name(
+  GetItemViewFromTemplatesGrid(1)->desk_template()->set_template_name(
       u"Desk 2");
   // Save template 2 under new name and confirm, this will trigger replace
   // dialog.
@@ -3190,9 +3190,55 @@
   // Expect that the entire text of the new template is selected.
   EXPECT_EQ(u"Desk 1", GetItemViewFromTemplatesGrid(0)->name_view()->GetText());
   EXPECT_EQ(u"Desk 1", GetItemViewFromTemplatesGrid(1)->name_view()->GetText());
-  EXPECT_TRUE(GetItemViewFromTemplatesGrid(1)->name_view()->HasFocus());
+  EXPECT_TRUE(GetItemViewFromTemplatesGrid(0)->name_view()->HasFocus());
   EXPECT_EQ(u"Desk 1",
-            GetItemViewFromTemplatesGrid(1)->name_view()->GetSelectedText());
+            GetItemViewFromTemplatesGrid(0)->name_view()->GetSelectedText());
+}
+
+// Tests that a newly saved template will always show up on the top left corner
+// regardless of its name and verify that it goes to its alphabetical order
+// once the name is confirmed.
+TEST_F(DesksTemplatesTest, NoSortBeforeNameConfirmed) {
+  // Create a window to enable the save as template button.
+  auto test_window = CreateAppWindow();
+
+  // Add an entry with a low lexiconic value for the template name to test that
+  // the new saved template is always preceding this one.
+  AddEntry(base::GUID::GenerateRandomV4(), "aaaa", base::Time::Now());
+
+  // Enter overview and save the same desk again.
+  ToggleOverview();
+  WaitForDesksTemplatesUI();
+  // The `save_desk_as_template_widget` is visible when at least one window is
+  // open.
+  views::Widget* save_desk_as_template_widget =
+      GetSaveDeskAsTemplateButtonForRoot(Shell::GetPrimaryRootWindow());
+  ASSERT_TRUE(save_desk_as_template_widget);
+  EXPECT_TRUE(save_desk_as_template_widget->GetContentsView()->GetVisible());
+
+  // Click on `save_desk_as_template_widget` button. The newly saved template
+  // should be in the front, even though its name is not in alphabetical order.
+  ClickOnView(save_desk_as_template_widget->GetContentsView());
+  ASSERT_EQ(2ul, GetAllEntries().size());
+  WaitForDesksTemplatesUI();
+
+  // Newly created template name_view.
+  DesksTemplatesNameView* name_view =
+      GetItemViewFromTemplatesGrid(0)->name_view();
+  EXPECT_TRUE(name_view->HasFocus());
+  ASSERT_EQ(u"Desk 1", DesksController::Get()->active_desk()->name());
+  EXPECT_EQ(u"Desk 1", name_view->GetText());
+
+  // Change the saved template name and save it.
+  SendKey(ui::VKEY_Z);
+  SendKey(ui::VKEY_Z);
+  SendKey(ui::VKEY_RETURN);
+  WaitForDesksTemplatesUI();
+
+  // Check that the name is saved and it's moved to its proper alphabetical
+  // order. This should be the second entry in the templates grid.
+  name_view = GetItemViewFromTemplatesGrid(1)->name_view();
+  EXPECT_EQ(u"zz", name_view->GetText());
 }
 
 TEST_F(DesksTemplatesTest, NudgeOnTheCorrectDisplay) {
diff --git a/ash/wm/float/float_controller.cc b/ash/wm/float/float_controller.cc
index 3b14ebbc..7e37407a 100644
--- a/ash/wm/float/float_controller.cc
+++ b/ash/wm/float/float_controller.cc
@@ -17,7 +17,7 @@
 FloatController::~FloatController() = default;
 
 void FloatController::ToggleFloatCurrentWindow(aura::Window* window) {
-  DCHECK(features::IsWindowControlMenuEnabled());
+  DCHECK(features::IsFloatWindowEnabled());
   // If try to float the same window again, will toggle unfloat.
   // Since only one floating window is allowed, reset other floating window.
   if (window == ResetFloatedWindow())
diff --git a/ash/wm/float/float_controller_unittest.cc b/ash/wm/float/float_controller_unittest.cc
index 13c26c3c..cec9383 100644
--- a/ash/wm/float/float_controller_unittest.cc
+++ b/ash/wm/float/float_controller_unittest.cc
@@ -24,7 +24,7 @@
 
   void SetUp() override {
     // Ensure float feature is enabled.
-    scoped_feature_list_.InitAndEnableFeature(features::kWindowControlMenu);
+    scoped_feature_list_.InitAndEnableFeature(features::kFloatWindow);
     AshTestBase::SetUp();
   }
 
diff --git a/ash/wm/mru_window_tracker.cc b/ash/wm/mru_window_tracker.cc
index e38982d..a5052e7 100644
--- a/ash/wm/mru_window_tracker.cc
+++ b/ash/wm/mru_window_tracker.cc
@@ -22,7 +22,6 @@
 #include "base/containers/cxx20_erase.h"
 #include "components/app_restore/window_properties.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/wm/core/window_util.h"
 #include "ui/wm/public/activation_client.h"
@@ -212,13 +211,10 @@
 // MruWindowTracker, public:
 
 MruWindowTracker::MruWindowTracker() {
-  aura::Env::GetInstance()->AddObserver(this);
-
   Shell::Get()->activation_client()->AddObserver(this);
 }
 
 MruWindowTracker::~MruWindowTracker() {
-  aura::Env::GetInstance()->RemoveObserver(this);
   Shell::Get()->activation_client()->RemoveObserver(this);
   for (auto* window : mru_windows_)
     window->RemoveObserver(this);
@@ -276,6 +272,28 @@
   }
 }
 
+void MruWindowTracker::OnWindowAlteredByWindowRestore(aura::Window* window) {
+  int32_t* activation_index =
+      window->GetProperty(app_restore::kActivationIndexKey);
+  DCHECK(activation_index);
+
+  // A window may shift desks and get restacked but already be created. In this
+  // case remove it from `mru_windows_` and reinsert it at the correct location.
+  // If nothing was erased, this is a window not currently observed so we want
+  // to observe it as windows created from window restore aren't activated on
+  // creation.
+  size_t num_erased = base::Erase(mru_windows_, window);
+  if (num_erased == 0u)
+    window->AddObserver(this);
+
+  // When windows are restored from a window restore feature, they are restored
+  // inactive so we have to manually insert them into the window tracker and
+  // restore their MRU order.
+  mru_windows_.insert(
+      WindowRestoreController::GetWindowToInsertBefore(window, mru_windows_),
+      window);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // MruWindowTracker, private:
 
@@ -313,19 +331,4 @@
   window->RemoveObserver(this);
 }
 
-void MruWindowTracker::OnWindowInitialized(aura::Window* window) {
-  int32_t* activation_index =
-      window->GetProperty(app_restore::kActivationIndexKey);
-  if (!activation_index)
-    return;
-
-  // When windows are restored from Full Restore, they are restored inactive
-  // so we have to manually insert them into the window tracker and restore
-  // their MRU order.
-  window->AddObserver(this);
-  mru_windows_.insert(
-      WindowRestoreController::GetWindowToInsertBefore(window, mru_windows_),
-      window);
-}
-
 }  // namespace ash
diff --git a/ash/wm/mru_window_tracker.h b/ash/wm/mru_window_tracker.h
index 4103ecb4..073aa58 100644
--- a/ash/wm/mru_window_tracker.h
+++ b/ash/wm/mru_window_tracker.h
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "ash/ash_export.h"
-#include "ui/aura/env_observer.h"
 #include "ui/aura/window_observer.h"
 #include "ui/wm/public/activation_change_observer.h"
 
@@ -34,9 +33,8 @@
 
 // Maintains a most recently used list of windows. This is used for window
 // cycling using Alt+Tab and overview mode.
-class ASH_EXPORT MruWindowTracker : public ::wm::ActivationChangeObserver,
-                                    public aura::WindowObserver,
-                                    public aura::EnvObserver {
+class ASH_EXPORT MruWindowTracker : public wm::ActivationChangeObserver,
+                                    public aura::WindowObserver {
  public:
   using WindowList = std::vector<aura::Window*>;
 
@@ -95,13 +93,18 @@
   // used window across all desks.
   void OnWindowMovedOutFromRemovingDesk(aura::Window* window);
 
+  // Called when a window is moved to another desk or created by a window
+  // restore feature. This function should be only called by
+  // `WindowRestoreController`.
+  void OnWindowAlteredByWindowRestore(aura::Window* window);
+
   const std::vector<aura::Window*>& GetMruWindowsForTesting() {
     return mru_windows_;
   }
 
  private:
-  // Updates the mru_windows_ list to insert/move |active_window| at/to the
-  // front.
+  // Updates the `mru_windows_` list to insert/move `active_window` at/to the
+  // back.
   void SetActiveWindow(aura::Window* active_window);
 
   // wm::ActivationChangeObserver:
@@ -112,11 +115,10 @@
   // aura::WindowObserver:
   void OnWindowDestroyed(aura::Window* window) override;
 
-  // EnvObserver:
-  void OnWindowInitialized(aura::Window* window) override;
-
   // List of windows that have been activated in containers that we cycle
-  // through, sorted such that the most recently used window comes last.
+  // through, sorted such that the most recently used window comes last. Note
+  // that this ordering differs from the lists returned by the
+  // `Build*Window*List` functions, which are reversed.
   std::vector<aura::Window*> mru_windows_;
 
   bool ignore_window_activations_ = false;
diff --git a/ash/wm/mru_window_tracker_unittest.cc b/ash/wm/mru_window_tracker_unittest.cc
index 77cfd3f..e4206bb 100644
--- a/ash/wm/mru_window_tracker_unittest.cc
+++ b/ash/wm/mru_window_tracker_unittest.cc
@@ -8,9 +8,12 @@
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/wm/window_restore/window_restore_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "components/app_restore/window_properties.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/ui_base_types.h"
@@ -28,13 +31,19 @@
 
   ~MruWindowTrackerTest() override = default;
 
-  std::unique_ptr<aura::Window> CreateTestWindow() {
-    return AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
-  }
-
   MruWindowTracker* mru_window_tracker() {
     return Shell::Get()->mru_window_tracker();
   }
+
+  // Simulates restoring a window through window restore with the
+  // `app_restore::kActivationIndexKey`.
+  std::unique_ptr<aura::Window> CreateTestWindowRestoredWindow(
+      int activation_index) {
+    auto window = CreateTestWindow();
+    window->SetProperty(app_restore::kActivationIndexKey, activation_index);
+    WindowRestoreController::Get()->StackWindow(window.get());
+    return window;
+  }
 };
 
 // Basic test that the activation order is tracked.
@@ -69,10 +78,70 @@
   EXPECT_EQ(1, std::count(window_list.begin(), window_list.end(), w1.get()));
 }
 
+// Tests whether MRU order is properly restored for the window restore features.
+TEST_F(MruWindowTrackerTest, RestoreMruOrder) {
+  // Simulate restoring window restored windows out-of-order. Start with `w5`,
+  // which has an activation index of 5. The lower
+  // `app_restore::kActivationIndexKey` is, the more recently it was used. Also
+  // the most recently used window is at the end of
+  // `MruWindowTracker::mru_windows_`.
+  auto w5 = CreateTestWindowRestoredWindow(/*activation_index=*/5);
+  EXPECT_THAT(mru_window_tracker()->GetMruWindowsForTesting(),
+              testing::ElementsAre(w5.get()));
+
+  // Simulate restoring `w2`.
+  auto w2 = CreateTestWindowRestoredWindow(/*activation_index=*/2);
+  EXPECT_THAT(mru_window_tracker()->GetMruWindowsForTesting(),
+              testing::ElementsAre(w5.get(), w2.get()));
+
+  // Simulate restoring `w3`.
+  auto w3 = CreateTestWindowRestoredWindow(/*activation_index=*/3);
+  EXPECT_THAT(mru_window_tracker()->GetMruWindowsForTesting(),
+              testing::ElementsAre(w5.get(), w3.get(), w2.get()));
+
+  // Simulate a user creating a window while Full Restore is ongoing.
+  auto user_created_window = CreateTestWindow();
+  wm::ActivateWindow(user_created_window.get());
+  EXPECT_THAT(mru_window_tracker()->GetMruWindowsForTesting(),
+              testing::ElementsAre(w5.get(), w3.get(), w2.get(),
+                                   user_created_window.get()));
+
+  // Simulate restoring `w4`.
+  auto w4 = CreateTestWindowRestoredWindow(/*activation_index=*/4);
+  EXPECT_THAT(mru_window_tracker()->GetMruWindowsForTesting(),
+              testing::ElementsAre(w5.get(), w4.get(), w3.get(), w2.get(),
+                                   user_created_window.get()));
+
+  // Simulate restoring `w1`.
+  auto w1 = CreateTestWindowRestoredWindow(/*activation_index=*/1);
+  EXPECT_THAT(mru_window_tracker()->GetMruWindowsForTesting(),
+              testing::ElementsAre(w5.get(), w4.get(), w3.get(), w2.get(),
+                                   w1.get(), user_created_window.get()));
+}
+
+// Tests that window restore'd windows are included in the MRU window list. See
+// https://crbug.com/1229260.
+TEST_F(MruWindowTrackerTest, WindowRestoredWindowsInMruWindowList) {
+  // Create an `aura::Window` using `CreateTestWindow()` so that the window is
+  // parented to something. Then set its
+  // `app_restore::kLaunchedFromFullRestoreKey` to simulate it being window
+  // restore'd.
+  std::unique_ptr<aura::Window> w1(CreateTestWindow());
+  w1->SetProperty(app_restore::kLaunchedFromFullRestoreKey, true);
+
+  // Build the MRU window list. `w1` should be included despite not being
+  // activatable.
+  EXPECT_THAT(mru_window_tracker()->BuildMruWindowList(kAllDesks),
+              testing::ElementsAre(w1.get()));
+}
+
 class MruWindowTrackerOrderTest : public MruWindowTrackerTest,
                                   public ::testing::WithParamInterface<bool> {
  public:
   MruWindowTrackerOrderTest() {}
+  MruWindowTrackerOrderTest(const MruWindowTrackerOrderTest&) = delete;
+  MruWindowTrackerOrderTest& operator=(const MruWindowTrackerOrderTest&) =
+      delete;
   ~MruWindowTrackerOrderTest() override = default;
 
   MruWindowTracker::WindowList BuildMruWindowList() const {
@@ -151,92 +220,6 @@
   EXPECT_EQ(iter, window_list.end());
 }
 
-// A test class for testing the Full Restore feature.
-class MruWindowTrackerFullRestoreTest : public MruWindowTrackerTest {
- public:
-  MruWindowTrackerFullRestoreTest() = default;
-  MruWindowTrackerFullRestoreTest(const MruWindowTrackerFullRestoreTest&) =
-      delete;
-  MruWindowTrackerFullRestoreTest& operator=(
-      const MruWindowTrackerFullRestoreTest&) = delete;
-  ~MruWindowTrackerFullRestoreTest() override = default;
-
-  // MruWindowTrackerTest:
-  void SetUp() override { MruWindowTrackerTest::SetUp(); }
-
-  // Simulates restoring a window using Full Restore by init'ing a window with
-  // the `app_restore::kActivationIndexKey`.
-  std::unique_ptr<aura::Window> CreateTestFullRestoredWindow(
-      int activation_index) {
-    auto window = std::make_unique<aura::Window>(
-        nullptr, aura::client::WINDOW_TYPE_NORMAL);
-    window->SetProperty(app_restore::kActivationIndexKey, activation_index);
-    window->Init(ui::LAYER_NOT_DRAWN);
-    return window;
-  }
-
-  void VerifyMruWindowsOrder(
-      const MruWindowTracker::WindowList& expected_list) {
-    auto actual_list = mru_window_tracker()->GetMruWindowsForTesting();
-    ASSERT_EQ(expected_list.size(), actual_list.size());
-    for (size_t i = 0; i < expected_list.size(); ++i)
-      EXPECT_EQ(expected_list[i], actual_list[i]);
-  }
-};
-
-// Tests whether MRU order is properly restored for the Full Restore feature.
-TEST_F(MruWindowTrackerFullRestoreTest, RestoreMruOrder) {
-  // Simulate restoring Full Restored windows out-of-order. Start with `w5`,
-  // which has an activation index of 5. The lower
-  // `app_restore::kActivationIndexKey` is, the more recently it was used. Also
-  // the most recently used window is at the end of
-  // `MruWindowTracker::mru_windows_`.
-  auto w5 = CreateTestFullRestoredWindow(/*activation_index=*/5);
-  VerifyMruWindowsOrder({w5.get()});
-
-  // Simulate restoring `w2`.
-  auto w2 = CreateTestFullRestoredWindow(/*activation_index=*/2);
-  VerifyMruWindowsOrder({w5.get(), w2.get()});
-
-  // Simulate restoring `w3`.
-  auto w3 = CreateTestFullRestoredWindow(/*activation_index=*/3);
-  VerifyMruWindowsOrder({w5.get(), w3.get(), w2.get()});
-
-  // Simulate a user creating a window while Full Restore is ongoing.
-  auto user_created_window = CreateTestWindow();
-  wm::ActivateWindow(user_created_window.get());
-  VerifyMruWindowsOrder(
-      {w5.get(), w3.get(), w2.get(), user_created_window.get()});
-
-  // Simulate restoring `w4`.
-  auto w4 = CreateTestFullRestoredWindow(/*activation_index=*/4);
-  VerifyMruWindowsOrder(
-      {w5.get(), w4.get(), w3.get(), w2.get(), user_created_window.get()});
-
-  // Simulate restoring `w1`.
-  auto w1 = CreateTestFullRestoredWindow(/*activation_index=*/1);
-  VerifyMruWindowsOrder({w5.get(), w4.get(), w3.get(), w2.get(), w1.get(),
-                         user_created_window.get()});
-}
-
-// Tests that Full Restore'd windows are included in the MRU window list. See
-// crbug.com/1229260.
-TEST_F(MruWindowTrackerFullRestoreTest, FullRestoredWindowsInMRUWindowList) {
-  // Create an `aura::Window` using `CreateTestWindow()` so that the window is
-  // parented to something. Then set its
-  // `app_restore::kLaunchedFromFullRestoreKey` to simulate it being Full
-  // Restore'd.
-  std::unique_ptr<aura::Window> w1(CreateTestWindow());
-  w1->SetProperty(app_restore::kLaunchedFromFullRestoreKey, true);
-
-  // Build the MRU window list. `w1` should be included despite not being
-  // activatable.
-  MruWindowTracker::WindowList window_list =
-      mru_window_tracker()->BuildMruWindowList(kAllDesks);
-  EXPECT_EQ(1u, window_list.size());
-  EXPECT_EQ(w1.get(), window_list[0]);
-}
-
 INSTANTIATE_TEST_SUITE_P(MruWindowTrackerOrder,
                          MruWindowTrackerOrderTest,
                          /*use ignore modal=*/::testing::Bool());
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index c8b67ef..5895e27 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -696,9 +696,10 @@
 void OverviewGrid::AddItemInMruOrder(aura::Window* window,
                                      bool reposition,
                                      bool animate,
-                                     bool restack) {
+                                     bool restack,
+                                     bool use_spawn_animation) {
   AddItem(window, reposition, animate, /*ignored_items=*/{},
-          FindInsertionIndex(window), /*use_spawn_animation=*/false, restack);
+          FindInsertionIndex(window), use_spawn_animation, restack);
 }
 
 void OverviewGrid::RemoveItem(OverviewItem* overview_item,
@@ -2391,7 +2392,8 @@
   }
 
   overview_session_->AddItemInMruOrder(dragged_window, /*reposition=*/false,
-                                       /*animate=*/false, /*restack=*/true);
+                                       /*animate=*/false, /*restack=*/true,
+                                       /*use_spawn_animation=*/false);
 }
 
 gfx::Rect OverviewGrid::GetDesksWidgetBounds() const {
diff --git a/ash/wm/overview/overview_grid.h b/ash/wm/overview/overview_grid.h
index c161a0187..ab6cedc 100644
--- a/ash/wm/overview/overview_grid.h
+++ b/ash/wm/overview/overview_grid.h
@@ -132,7 +132,8 @@
   void AddItemInMruOrder(aura::Window* window,
                          bool reposition,
                          bool animate,
-                         bool restack);
+                         bool restack,
+                         bool use_spawn_animation);
 
   // Removes |overview_item| from the grid. |overview_item| cannot already be
   // absent from the grid. If |item_destroying| is true, we may want to notify
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index c9ae1fda..9962890 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -176,8 +176,11 @@
 
   hide_overview_windows_ = std::make_unique<ScopedOverviewHideWindows>(
       std::move(hide_windows), /*force_hidden=*/false);
-  if (active_window_before_overview_)
-    active_window_before_overview_->AddObserver(this);
+
+  if (active_window_before_overview_) {
+    active_window_before_overview_observation_.Observe(
+        active_window_before_overview_);
+  }
 
   // Create this before the desks bar widget.
   if (desks_templates_util::AreDesksTemplatesEnabled() &&
@@ -528,13 +531,15 @@
 void OverviewSession::AddItemInMruOrder(aura::Window* window,
                                         bool reposition,
                                         bool animate,
-                                        bool restack) {
+                                        bool restack,
+                                        bool use_spawn_animation) {
   // Early exit if a grid already contains |window|.
   OverviewGrid* grid = GetGridWithRootWindow(window->GetRootWindow());
   if (!grid || grid->GetOverviewItemContaining(window))
     return;
 
-  grid->AddItemInMruOrder(window, reposition, animate, restack);
+  grid->AddItemInMruOrder(window, reposition, animate, restack,
+                          use_spawn_animation);
   OnItemAdded(window);
 }
 
@@ -546,7 +551,7 @@
                                  bool item_destroying,
                                  bool reposition) {
   if (overview_item->GetWindow() == active_window_before_overview_) {
-    active_window_before_overview_->RemoveObserver(this);
+    active_window_before_overview_observation_.Reset();
     active_window_before_overview_ = nullptr;
   }
 
@@ -946,8 +951,7 @@
     base::AutoReset<bool> restoring_focus(&ignore_activations_, true);
     wm::ActivateWindow(active_window_before_overview_);
   }
-
-  active_window_before_overview_->RemoveObserver(this);
+  active_window_before_overview_observation_.Reset();
   active_window_before_overview_ = nullptr;
 }
 
@@ -1170,7 +1174,7 @@
 
 void OverviewSession::OnWindowDestroying(aura::Window* window) {
   DCHECK_EQ(active_window_before_overview_, window);
-  active_window_before_overview_->RemoveObserver(this);
+  active_window_before_overview_observation_.Reset();
   active_window_before_overview_ = nullptr;
 }
 
@@ -1190,7 +1194,14 @@
     return;
   }
 
-  AppendItem(new_window, /*reposition=*/true, /*animate*/ true);
+  AddItemInMruOrder(new_window, /*reposition=*/true, /*animate=*/true,
+                    /*restack=*/false, /*use_spawn_animation=*/true);
+
+  // If a window is added from desk templates, we no longer want to go back to
+  // the previous active window we had before entering overview, otherwise we
+  // may activate a window and break the stacking order that the saved desk had.
+  active_window_before_overview_observation_.Reset();
+  active_window_before_overview_ = nullptr;
 }
 
 void OverviewSession::OnKeyEvent(ui::KeyEvent* event) {
@@ -1464,8 +1475,7 @@
 
 void OverviewSession::RemoveAllObservers() {
   display_observer_.reset();
-  if (active_window_before_overview_)
-    active_window_before_overview_->RemoveObserver(this);
+  active_window_before_overview_observation_.Reset();
   active_window_before_overview_ = nullptr;
 }
 
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index 67f400e..7a33a41a 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -143,7 +143,8 @@
   void AddItemInMruOrder(aura::Window* window,
                          bool reposition,
                          bool animate,
-                         bool restack);
+                         bool restack,
+                         bool use_spawn_animation);
 
   // Removes |overview_item| from the corresponding grid.
   void RemoveItem(OverviewItem* overview_item);
@@ -501,6 +502,9 @@
 
   base::ScopedObservation<DesksController, DesksController::Observer>
       desks_controller_observation_{this};
+
+  base::ScopedObservation<aura::Window, aura::WindowObserver>
+      active_window_before_overview_observation_{this};
 };
 
 }  // namespace ash
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index ed31c5c..77a4725 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -188,7 +188,8 @@
       // will soon handle them both anyway.
       OverviewSession* session = overview_controller->overview_session();
       session->AddItemInMruOrder(window, /*reposition=*/false,
-                                 /*animate=*/false, /*restack=*/false);
+                                 /*animate=*/false, /*restack=*/false,
+                                 /*use_spawn_animation=*/false);
       OverviewItem* item = session->GetOverviewItemForWindow(window);
       DCHECK(item);
       item->SetBounds(target_item_bounds_, OVERVIEW_ANIMATION_NONE);
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index f3e9d1834..10507ca8 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -2575,7 +2575,8 @@
   if (!window || !GetOverviewSession())
     return;
   GetOverviewSession()->AddItemInMruOrder(window, /*reposition=*/true, animate,
-                                          /*restack=*/true);
+                                          /*restack=*/true,
+                                          /*use_spawn_animation=*/false);
 }
 
 void SplitViewController::FinishWindowResizing(aura::Window* window) {
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
index d2022b6..b8300f3e 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
@@ -328,7 +328,8 @@
           ->overview_controller()
           ->overview_session()
           ->AddItemInMruOrder(dragged_window_, /*reposition=*/true,
-                              /*animate=*/false, /*restack=*/true);
+                              /*animate=*/false, /*restack=*/true,
+                              /*use_spawn_animation=*/false);
     }
     StartFling(event);
   }
diff --git a/ash/wm/window_resizer.cc b/ash/wm/window_resizer.cc
index ad6bef40a..b27f2604 100644
--- a/ash/wm/window_resizer.cc
+++ b/ash/wm/window_resizer.cc
@@ -4,6 +4,7 @@
 
 #include "ash/wm/window_resizer.h"
 
+#include "ash/public/cpp/presentation_time_recorder.h"
 #include "ash/wm/window_positioning_utils.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
@@ -84,9 +85,6 @@
 
 WindowResizer::WindowResizer(WindowState* window_state)
     : window_state_(window_state) {
-  recorder_ = PresentationTimeRecorder::CreateCompositorRecorder(
-      GetTarget(), "Ash.InteractiveWindowResize.TimeToPresent",
-      "Ash.InteractiveWindowResize.TimeToPresent.MaxLatency");
   DCHECK(window_state_->drag_details());
 }
 
@@ -262,8 +260,14 @@
 void WindowResizer::SetBoundsDuringResize(const gfx::Rect& bounds) {
   aura::Window* window = GetTarget();
   DCHECK(window);
+
   auto ptr = weak_ptr_factory_.GetWeakPtr();
-  const gfx::Rect original_bounds = window->bounds();
+  const gfx::Size original_size = window->bounds().size();
+
+  // Prepare to record presentation time (e.g. tracking Configure).
+  if (recorder_)
+    recorder_->PrepareToRecord();
+
   window->SetBounds(bounds);
 
   // Resizer can be destroyed when a window is attached during tab dragging.
@@ -271,9 +275,19 @@
   if (!ptr)
     return;
 
-  if (bounds.size() == original_bounds.size())
+  // Using `window->bounds()` instead of `bounds` to check size change because
+  // whether "window->SetBounds()" could reject a bounds change. And when that
+  // happens, there might be no new frames presented on screen.
+  if (window->bounds().size() == original_size)
     return;
-  recorder_->RequestNext();
+
+  if (recorder_)
+    recorder_->RequestNext();
+}
+
+void WindowResizer::SetPresentationTimeRecorder(
+    std::unique_ptr<PresentationTimeRecorder> recorder) {
+  recorder_ = std::move(recorder);
 }
 
 void WindowResizer::AdjustDeltaForTouchResize(int* delta_x, int* delta_y) {
diff --git a/ash/wm/window_resizer.h b/ash/wm/window_resizer.h
index a39a2a87..34fc21c33 100644
--- a/ash/wm/window_resizer.h
+++ b/ash/wm/window_resizer.h
@@ -90,6 +90,9 @@
   // should not be called as the result of a revert.
   void SetBoundsDuringResize(const gfx::Rect& bounds);
 
+  void SetPresentationTimeRecorder(
+      std::unique_ptr<PresentationTimeRecorder> recorder);
+
   // WindowState of the drag target.
   WindowState* window_state_;
 
diff --git a/ash/wm/window_restore/window_restore_controller.cc b/ash/wm/window_restore/window_restore_controller.cc
index 7b67744..ce73d40b 100644
--- a/ash/wm/window_restore/window_restore_controller.cc
+++ b/ash/wm/window_restore/window_restore_controller.cc
@@ -448,10 +448,11 @@
   if (!activation_index)
     return;
 
+  Shell::Get()->mru_window_tracker()->OnWindowAlteredByWindowRestore(window);
+
   // Stack the window.
   auto siblings = window->parent()->children();
-  auto insertion_point =
-      WindowRestoreController::GetWindowToInsertBefore(window, siblings);
+  auto insertion_point = GetWindowToInsertBefore(window, siblings);
   if (insertion_point != siblings.end())
     window->parent()->StackChildBelow(window, *insertion_point);
 }
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index 4e97694..274cc59 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -1115,7 +1115,18 @@
   if (!parent_local_bounds.Intersects(restore_bounds_for_gesture_))
     restore_bounds_for_gesture_.AdjustToFit(parent_local_bounds);
 
-  window_state->OnDragStarted(details().window_component);
+  std::unique_ptr<ash::PresentationTimeRecorder> recorder =
+      window_state->OnDragStarted(details().window_component);
+  if (recorder) {
+    SetPresentationTimeRecorder(std::move(recorder));
+  } else {
+    // Default to use compositor based recorder.
+    SetPresentationTimeRecorder(
+        PresentationTimeRecorder::CreateCompositorRecorder(
+            GetTarget(), "Ash.InteractiveWindowResize.TimeToPresent",
+            "Ash.InteractiveWindowResize.TimeToPresent.MaxLatency"));
+  }
+
   StartDragForAttachedWindows();
 
   if (window_util::IsDraggingTabs(window_state->window())) {
diff --git a/base/android/java/src/org/chromium/base/ContextUtils.java b/base/android/java/src/org/chromium/base/ContextUtils.java
index bb7d60f3..51aaedd 100644
--- a/base/android/java/src/org/chromium/base/ContextUtils.java
+++ b/base/android/java/src/org/chromium/base/ContextUtils.java
@@ -34,6 +34,8 @@
     private static final String TAG = "ContextUtils";
     private static Context sApplicationContext;
 
+    private static boolean sSdkSandboxProcess;
+
     /**
      * Flag for {@link Context#registerReceiver}: The receiver can receive broadcasts from other
      * Apps. Has the same behavior as marking a statically registered receiver with "exported=true".
@@ -156,6 +158,23 @@
         return Process.isIsolated();
     }
 
+    /**
+     * Set current process as SdkSandbox process or not.
+     *
+     * TODO: This method shall be removed once Android Sdk is in, refer to isSdkSandboxProcess().
+     */
+    public static void setSdkSandboxProcess(boolean sdkSandboxProcess) {
+        sSdkSandboxProcess = sdkSandboxProcess;
+    }
+
+    /**
+     * @return if current process is SdkSandbox process.
+     */
+    public static boolean isSdkSandboxProcess() {
+        // TODO: Call android.os.Process.isSdkSandbox() directly once Android Sdk is in.
+        return sSdkSandboxProcess;
+    }
+
     /** @return The name of the current process. E.g. "org.chromium.chrome:privileged_process0". */
     public static String getProcessName() {
         return ApiCompatibilityUtils.getProcessName();
diff --git a/base/fuchsia/file_utils.cc b/base/fuchsia/file_utils.cc
index 3892c580..fab29dfb 100644
--- a/base/fuchsia/file_utils.cc
+++ b/base/fuchsia/file_utils.cc
@@ -17,14 +17,13 @@
 #include "base/fuchsia/fuchsia_logging.h"
 namespace base {
 
-const char kPersistedDataDirectoryPath[] = "/data";
-const char kPersistedCacheDirectoryPath[] = "/cache";
-const char kServiceDirectoryPath[] = "/svc";
-const char kPackageRootDirectoryPath[] = "/pkg";
+namespace {
 
-fidl::InterfaceHandle<::fuchsia::io::Directory> OpenDirectoryHandle(
-    const base::FilePath& path) {
-  ScopedFD fd(open(path.value().c_str(), O_DIRECTORY | O_RDONLY));
+fidl::InterfaceHandle<::fuchsia::io::Directory> OpenDirectoryHandleInternal(
+    const base::FilePath& path,
+    bool read_only) {
+  ScopedFD fd(open(path.value().c_str(),
+                   O_DIRECTORY | (read_only ? O_RDONLY : O_RDWR)));
   if (!fd.is_valid()) {
     DPLOG(ERROR) << "Failed to open " << path;
     return fidl::InterfaceHandle<::fuchsia::io::Directory>();
@@ -43,4 +42,21 @@
   return fidl::InterfaceHandle<::fuchsia::io::Directory>(std::move(channel));
 }
 
+}  // namespace
+
+const char kPersistedDataDirectoryPath[] = "/data";
+const char kPersistedCacheDirectoryPath[] = "/cache";
+const char kServiceDirectoryPath[] = "/svc";
+const char kPackageRootDirectoryPath[] = "/pkg";
+
+fidl::InterfaceHandle<::fuchsia::io::Directory> OpenDirectoryHandle(
+    const base::FilePath& path) {
+  return OpenDirectoryHandleInternal(path, true);
+}
+
+fidl::InterfaceHandle<::fuchsia::io::Directory> OpenWritableDirectoryHandle(
+    const base::FilePath& path) {
+  return OpenDirectoryHandleInternal(path, false);
+}
+
 }  // namespace base
diff --git a/base/fuchsia/file_utils.h b/base/fuchsia/file_utils.h
index 9300430d..783a678 100644
--- a/base/fuchsia/file_utils.h
+++ b/base/fuchsia/file_utils.h
@@ -24,11 +24,16 @@
 // Package root directory, i.e. /pkg .
 BASE_EXPORT extern const char kPackageRootDirectoryPath[];
 
-// Returns fuchsia.io.Directory for the specified |path| or null InterfaceHandle
-// if the path doesn't exist or it's not a directory.
+// Returns a read-only fuchsia.io.Directory for the specified |path|, or an
+// invalid InterfaceHandle if the path doesn't exist or it's not a directory.
 BASE_EXPORT fidl::InterfaceHandle<::fuchsia::io::Directory> OpenDirectoryHandle(
     const base::FilePath& path);
 
+// Returns a write-capable fuchsia.io.Directory for the specified |path| or
+// an invalid InterfaceHandle if the path doesn't exist or it's not a directory.
+BASE_EXPORT fidl::InterfaceHandle<::fuchsia::io::Directory>
+OpenWritableDirectoryHandle(const base::FilePath& path);
+
 }  // namespace base
 
 #endif  // BASE_FUCHSIA_FILE_UTILS_H_
diff --git a/base/memory/raw_ptr.h b/base/memory/raw_ptr.h
index 80ab0a7f6..321329d 100644
--- a/base/memory/raw_ptr.h
+++ b/base/memory/raw_ptr.h
@@ -140,7 +140,12 @@
 constexpr int kValidAddressBits = 48;
 constexpr uintptr_t kAddressMask = (1ull << kValidAddressBits) - 1;
 constexpr int kTagBits = sizeof(uintptr_t) * 8 - kValidAddressBits;
-constexpr uintptr_t kTagMask = ~kAddressMask;
+
+// MTECheckedPtr has no business with the topmost bits reserved for the
+// tag used by true ARM MTE, so we strip it out here.
+constexpr uintptr_t kTagMask =
+    ~kAddressMask & partition_alloc::internal::kMemTagUnmask;
+
 constexpr int kTopBitShift = 63;
 constexpr uintptr_t kTopBit = 1ull << kTopBitShift;
 static_assert(kTopBit << 1 == 0, "kTopBit should really be the top bit");
@@ -212,7 +217,7 @@
   static RAW_PTR_FUNC_ATTRIBUTES T* SafelyUnwrapPtrForDereference(
       T* wrapped_ptr) {
     uintptr_t wrapped_addr = reinterpret_cast<uintptr_t>(wrapped_ptr);
-    uintptr_t tag = wrapped_addr >> kValidAddressBits;
+    uintptr_t tag = ExtractTag(wrapped_addr);
     if (tag > 0) {
       // Read the tag provided by PartitionAlloc.
       //
@@ -224,7 +229,7 @@
               PartitionAllocSupport::TagPointer(ExtractAddress(wrapped_addr)));
       if (UNLIKELY(tag != read_tag))
         IMMEDIATE_CRASH();
-      return reinterpret_cast<T*>(wrapped_addr & kAddressMask);
+      return reinterpret_cast<T*>(ExtractAddress(wrapped_addr));
     }
     return wrapped_ptr;
   }
@@ -287,7 +292,7 @@
   }
 
   static ALWAYS_INLINE uintptr_t ExtractTag(uintptr_t wrapped_ptr) {
-    return wrapped_ptr & kTagMask;
+    return (wrapped_ptr & kTagMask) >> kValidAddressBits;
   }
 };
 
diff --git a/base/profiler/metadata_recorder.cc b/base/profiler/metadata_recorder.cc
index c51728f..4aee0486 100644
--- a/base/profiler/metadata_recorder.cc
+++ b/base/profiler/metadata_recorder.cc
@@ -60,18 +60,12 @@
       if (!was_active)
         inactive_item_count_--;
 
-      UMA_HISTOGRAM_COUNTS_10000("StackSamplingProfiler.MetadataSlotsUsed",
-                                 item_slots_used);
-
       return;
     }
   }
 
   item_slots_used = TryReclaimInactiveSlots(item_slots_used);
 
-  UMA_HISTOGRAM_COUNTS_10000("StackSamplingProfiler.MetadataSlotsUsed",
-                             item_slots_used + 1);
-
   if (item_slots_used == items_.size()) {
     // The metadata recorder is full, forcing us to drop this metadata. The
     // above UMA histogram counting occupied metadata slots should help us set a
diff --git a/base/profiler/metadata_recorder_unittest.cc b/base/profiler/metadata_recorder_unittest.cc
index 82a4e90f..6edad06 100644
--- a/base/profiler/metadata_recorder_unittest.cc
+++ b/base/profiler/metadata_recorder_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "base/ranges/algorithm.h"
 #include "base/test/gtest_util.h"
-#include "base/test/metrics/histogram_tester.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -315,22 +314,4 @@
   EXPECT_THAT(recorder_items, ::testing::UnorderedElementsAreArray(items_arr));
 }
 
-TEST(MetadataRecorderTest, MetadataSlotsUsedUmaHistogram) {
-  MetadataRecorder recorder;
-  HistogramTester histogram_tester;
-
-  for (size_t i = 0; i < MetadataRecorder::MAX_METADATA_COUNT; ++i) {
-    recorder.Set(i * 10, absl::nullopt, absl::nullopt, i * 100);
-  }
-
-  EXPECT_THAT(
-      histogram_tester.GetAllSamples("StackSamplingProfiler.MetadataSlotsUsed"),
-      testing::ElementsAre(Bucket(1, 1), Bucket(2, 1), Bucket(3, 1),
-                           Bucket(4, 1), Bucket(5, 1), Bucket(6, 1),
-                           Bucket(7, 1), Bucket(8, 2), Bucket(10, 2),
-                           Bucket(12, 2), Bucket(14, 3), Bucket(17, 3),
-                           Bucket(20, 4), Bucket(24, 5), Bucket(29, 5),
-                           Bucket(34, 6), Bucket(40, 8), Bucket(48, 3)));
-}
-
 }  // namespace base
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index 1c5f310..40aab7e 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -180,7 +180,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [
       "scoped_chromeos_version_info.cc",
       "scoped_chromeos_version_info.h",
diff --git a/base/test/icu_test_util.h b/base/test/icu_test_util.h
index d4d55ff..c7cdf45c 100644
--- a/base/test/icu_test_util.h
+++ b/base/test/icu_test_util.h
@@ -24,14 +24,13 @@
  public:
   ScopedRestoreICUDefaultLocale();
   explicit ScopedRestoreICUDefaultLocale(const std::string& locale);
+  ScopedRestoreICUDefaultLocale(const ScopedRestoreICUDefaultLocale&) = delete;
+  ScopedRestoreICUDefaultLocale& operator=(
+      const ScopedRestoreICUDefaultLocale&) = delete;
   ~ScopedRestoreICUDefaultLocale();
 
  private:
   const std::string default_locale_;
-
-  ScopedRestoreICUDefaultLocale(const ScopedRestoreICUDefaultLocale&) = delete;
-  ScopedRestoreICUDefaultLocale& operator=(
-      const ScopedRestoreICUDefaultLocale&) = delete;
 };
 
 // In unit tests, prefer ScopedRestoreDefaultTimezone over
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index a4b1c18..93d1ce9 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -3277,13 +3277,15 @@
 
     forward_variables_from(invoker, [ "testonly" ])
     _is_prebuilt = defined(invoker.jar_path)
-    _is_annotation_processor = invoker.type == "java_annotation_processor"
-    _is_java_binary =
-        invoker.type == "java_binary" || invoker.type == "junit_binary"
+    _type = invoker.type
+    _is_annotation_processor = _type == "java_annotation_processor"
+    _is_java_binary = _type == "java_binary" || _type == "junit_binary"
     _supports_android =
         defined(invoker.supports_android) && invoker.supports_android
     _requires_android =
         defined(invoker.requires_android) && invoker.requires_android
+    _bypass_platform_checks = defined(invoker.bypass_platform_checks) &&
+                              invoker.bypass_platform_checks
 
     _invoker_deps = []
     if (defined(invoker.deps)) {
@@ -3321,14 +3323,13 @@
     }
 
     if (_is_java_binary) {
-      assert(defined(invoker.main_class),
-             "${invoker.type}() must set main_class")
+      assert(defined(invoker.main_class), "${_type}() must set main_class")
     } else if (_is_annotation_processor) {
       assert(defined(invoker.main_class),
              "java_annotation_processor() must set main_class")
     } else {
       assert(!defined(invoker.main_class),
-             "main_class cannot be used for target of type ${invoker.type}")
+             "main_class cannot be used for target of type ${_type}")
     }
 
     if (defined(invoker.chromium_code)) {
@@ -3363,10 +3364,9 @@
         _output_name = _main_target_name
       }
 
-      _build_host_jar = _is_java_binary || _is_annotation_processor ||
-                        invoker.type == "java_library"
-      _build_device_jar =
-          invoker.type != "system_java_library" && _supports_android
+      _build_host_jar =
+          _is_java_binary || _is_annotation_processor || _type == "java_library"
+      _build_device_jar = _type != "system_java_library" && _supports_android
 
       _jacoco_instrument =
           use_jacoco_coverage && _chromium_code && _java_files != [] &&
@@ -3525,7 +3525,7 @@
                                "r_text_path",
                                "type",
                              ])
-      if (type == "android_apk" || type == "android_app_bundle_module") {
+      if (_type == "android_apk" || _type == "android_app_bundle_module") {
         forward_variables_from(
             invoker,
             [
@@ -3546,7 +3546,7 @@
               "library_renames",
             ])
       }
-      if (type == "android_apk") {
+      if (_type == "android_apk") {
         forward_variables_from(invoker,
                                [
                                  "apk_path",
@@ -3555,7 +3555,7 @@
                                  "incremental_install_json_path",
                                ])
       }
-      if (type == "android_app_bundle_module") {
+      if (_type == "android_app_bundle_module") {
         forward_variables_from(invoker,
                                [
                                  "add_view_trace_events",
@@ -3589,8 +3589,7 @@
 
       supports_android = _supports_android
       requires_android = _requires_android
-      bypass_platform_checks = defined(invoker.bypass_platform_checks) &&
-                               invoker.bypass_platform_checks
+      bypass_platform_checks = _bypass_platform_checks
 
       if (defined(_resources_package)) {
         custom_package = _resources_package
@@ -3643,11 +3642,12 @@
             _java_files != [] && _chromium_code && use_errorprone_java_compiler
       }
 
-      _type = invoker.type
+      if (defined(_resources_package) && _type == "java_library") {
+        assert(_requires_android || _bypass_platform_checks,
+               "Setting resources_package applicable only for " +
+                   "android_library(), or java_library() with " +
+                   "bypass_platform_checks=true. Target=$target_name")
 
-      _uses_fake_rjava = _type == "java_library" && _requires_android
-
-      if (_uses_fake_rjava && defined(_resources_package)) {
         # has _resources at the end so it looks like a resources pattern, since
         # it does act like one (and other resources patterns need to depend on
         # this before they can read its output R.txt).
diff --git a/build/config/chromeos/rules.gni b/build/config/chromeos/rules.gni
index 60a21ab..55655f4 100644
--- a/build/config/chromeos/rules.gni
+++ b/build/config/chromeos/rules.gni
@@ -10,7 +10,7 @@
 import("//build/config/python.gni")
 import("//build/util/generate_wrapper.gni")
 
-assert((is_chromeos_ash || is_chromeos_lacros) && is_chromeos_device)
+assert(is_chromeos && is_chromeos_device)
 
 # Determine the real paths for various items in the SDK, which may be used
 # in the 'generate_runner_script' template below. We do so outside the template
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 006aac4..4871a35 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -72,11 +72,10 @@
   # not ARC or linux-chromeos since it's been seen to not play nicely with
   # Chrome's clang. crbug.com/1033839
   use_thin_lto =
-      is_cfi ||
-      (is_clang && is_official_build && chrome_pgo_phase != 1 &&
-       (is_linux || is_win || is_mac || is_ios ||
-        (is_android && target_os != "chromeos") ||
-        ((is_chromeos_ash || is_chromeos_lacros) && is_chromeos_device)))
+      is_cfi || (is_clang && is_official_build && chrome_pgo_phase != 1 &&
+                 (is_linux || is_win || is_mac || is_ios ||
+                  (is_android && target_os != "chromeos") ||
+                  (is_chromeos && is_chromeos_device)))
 
   # If true, use Goma for ThinLTO code generation where applicable.
   use_goma_thin_lto = false
@@ -138,7 +137,7 @@
 # and build arguments.
 # TODO(crbug.com/1052397): Consider changing is_chromeos_ash to is_chromeos after
 # lacros-chrome switches to target_os="chromeos".
-if (is_chromeos_ash || is_chromeos_lacros) {
+if (is_chromeos) {
   # ChromeOS generally prefers frame pointers, to support CWP.
   # However, Clang does not currently generate usable frame pointers in ARM
   # 32-bit builds (https://bugs.llvm.org/show_bug.cgi?id=18505) so disable them
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index b897c992..d304d08 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -40,8 +40,7 @@
     defines = [ "OS_CHROMEOS" ]
   }
 
-  if ((!(is_chromeos_ash || is_chromeos_lacros) ||
-       default_toolchain != "//build/toolchain/cros:target") &&
+  if ((!is_chromeos || default_toolchain != "//build/toolchain/cros:target") &&
       (!use_custom_libcxx || current_cpu == "mipsel")) {
     libs = [ "atomic" ]
   }
diff --git a/build/config/locales.gni b/build/config/locales.gni
index 94cee21b..6088761 100644
--- a/build/config/locales.gni
+++ b/build/config/locales.gni
@@ -158,7 +158,7 @@
 
 # The base list for all platforms except Android excludes the extended locales.
 # Add or subtract platform specific locales below.
-if (is_chromeos_ash || is_chromeos_lacros) {
+if (is_chromeos) {
   platform_pak_locales += [
     "eu",
     "gl",
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni
index ded87a5..3dedd2d 100644
--- a/build/config/sanitizers/sanitizers.gni
+++ b/build/config/sanitizers/sanitizers.gni
@@ -112,7 +112,7 @@
   # Enable checks for bad casts: derived cast and unrelated cast.
   # TODO(krasin): remove this, when we're ready to add these checks by default.
   # https://crbug.com/626794
-  use_cfi_cast = is_cfi && (is_chromeos_ash || is_chromeos_lacros)
+  use_cfi_cast = is_cfi && is_chromeos
 
   # Compile for Undefined Behaviour Sanitizer's vptr checks.
   is_ubsan_vptr = is_ubsan_security
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index c10001a..fc4791d 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-7.20220329.2.1
+7.20220330.2.1
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index d78414f..efabb097 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -284,6 +284,14 @@
   $chromeos_lib_list
 "
 
+# this can be moved into the lib list without a guard when xenial is deprecated
+if package_exists libegl1; then
+  lib_list="${lib_list} libegl1"
+fi
+if package_exists libegl1:i386; then
+  lib_list="${lib_list} libegl1:i386"
+fi
+
 # 32-bit libraries needed e.g. to compile V8 snapshot for Android or armhf
 lib32_list="linux-libc-dev:i386 libpci3:i386"
 
@@ -543,11 +551,6 @@
     dev_list="${dev_list} snapcraft"
 fi
 
-# this can be moved into the dev list when xenial is deprecated
-if package_exists libegl1; then
-  dev_list="${dev_list} libegl1"
-fi
-
 # Cross-toolchain strip is needed for building the sysroots.
 if package_exists binutils-arm-linux-gnueabihf; then
   dev_list="${dev_list} binutils-arm-linux-gnueabihf"
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index f1e0552..6b8f877 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1426,7 +1426,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     public_deps += [ "//chromeos/dbus/constants" ]
   }
 
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantNavigationIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantNavigationIntegrationTest.java
index c6e3de11..b54c1ac 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantNavigationIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantNavigationIntegrationTest.java
@@ -32,6 +32,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.autofill_assistant.proto.ActionProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.ChipProto;
 import org.chromium.chrome.browser.autofill_assistant.proto.NavigateProto;
@@ -80,6 +81,7 @@
 
     @Test
     @MediumTest
+    @DisabledTest(message = "https://crbug.com/1311815")
     public void navigatingWithLocationBarShowsError() {
         ArrayList<ActionProto> list = new ArrayList<>();
         list.add(ActionProto.newBuilder()
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index a44e41340..4f77c336 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -212,7 +212,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     deps += [ "//chromeos/dbus/constants" ]
   }
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 9089b36e..8947d562 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5272,6 +5272,11 @@
       <message name="IDS_DEPRECATED_APPS_LEARN_MORE" desc="Redirects to a link with more information on chrome apps deprecation">
         Learn more
       </message>
+      <message name="IDS_DEPRECATED_APPS_DELETION_LINK" desc="Contains link to trigger the deprecated apps deletion dialog from chrome://apps">
+        {NUM_APPS, plural,
+        =1 {Delete 1 unsupported app}
+        other {Delete # unsupported apps}}
+      </message>
       <if expr="use_titlecase">
         <message name="IDS_DEPRECATED_APPS_OK_LABEL" desc="Label for OK button on deprecated apps dialog">
           {NUM_APPS, plural,
diff --git a/chrome/app/generated_resources_grd/IDS_DEPRECATED_APPS_DELETION_LINK.png.sha1 b/chrome/app/generated_resources_grd/IDS_DEPRECATED_APPS_DELETION_LINK.png.sha1
new file mode 100644
index 0000000..b9455dd3
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_DEPRECATED_APPS_DELETION_LINK.png.sha1
@@ -0,0 +1 @@
+6ff2631811c45b9f3b84abc7c67b5c5afcd547e5
\ No newline at end of file
diff --git a/chrome/app/resources/BUILD.gn b/chrome/app/resources/BUILD.gn
index 6203eb18..5bb79fd 100644
--- a/chrome/app/resources/BUILD.gn
+++ b/chrome/app/resources/BUILD.gn
@@ -25,7 +25,7 @@
     source = "locale_settings_win.grd"
   } else if (is_mac) {
     source = "locale_settings_mac.grd"
-  } else if (is_chromeos_ash || is_chromeos_lacros) {
+  } else if (is_chromeos) {
     if (is_chrome_branded) {
       source = "locale_settings_google_chromeos.grd"
     } else {
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 16bb2ba..53c7217 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -5326,7 +5326,7 @@
     assert(!is_chromeos_device || !is_component_build)
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [
       "apps/app_service/app_notifications.cc",
       "apps/app_service/app_notifications.h",
@@ -7213,7 +7213,7 @@
     ]
   }
   if (enable_supervised_users && enable_extensions) {
-    assert(is_chromeos_ash || is_chromeos_lacros)
+    assert(is_chromeos)
     sources += [
       "supervised_user/supervised_user_extensions_delegate_impl.cc",
       "supervised_user/supervised_user_extensions_delegate_impl.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index be9031fc..81a9402 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -960,6 +960,7 @@
 const FeatureEntry::FeatureParam
     kJourneysOnDeviceClusteringLabelingNoContentClusteringParams[] = {
         {"should_label_clusters", "true"},
+        {"labels_from_entities", "true"},
         {"content_clustering_enabled", "false"},
 };
 const FeatureEntry::FeatureParam
@@ -970,6 +971,7 @@
 const FeatureEntry::FeatureParam
     kJourneysOnDeviceClusteringLabelingWithContentClusteringParams[] = {
         {"should_label_clusters", "true"},
+        {"labels_from_entities", "true"},
         {"content_clustering_enabled", "true"},
 };
 const FeatureEntry::FeatureParam
@@ -5862,9 +5864,9 @@
      flag_descriptions::kAshEnablePipRoundedCornersName,
      flag_descriptions::kAshEnablePipRoundedCornersDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kPipRoundedCorners)},
-    {"ash-enable-floating-window", flag_descriptions::kWindowControlMenu,
-     flag_descriptions::kWindowControlMenuDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kWindowControlMenu)},
+    {"cros-labs-float-window", flag_descriptions::kFloatWindow,
+     flag_descriptions::kFloatWindowDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kFloatWindow)},
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -6040,6 +6042,11 @@
      flag_descriptions::kFastPairSoftwareScanningDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kFastPairSoftwareScanning)},
 
+    {"fast-pair-subsequent-pairing-ux",
+     flag_descriptions::kFastPairSubsequentPairingUXName,
+     flag_descriptions::kFastPairSubsequentPairingUXDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kFastPairSubsequentPairingUX)},
+
     {"pcie-billboard-notification",
      flag_descriptions::kPcieBillboardNotificationName,
      flag_descriptions::kPcieBillboardNotificationDescription, kOsCrOS,
@@ -7128,7 +7135,9 @@
      // multiple related features when they are available.
      SINGLE_VALUE_TYPE_AND_VALUE(switches::kEnableFeatures,
                                  "PrivacySandboxAdsAPIsOverride,"
-                                 "Fledge,BrowsingTopics,ConversionMeasurement,"
+                                 "InterestGroupStorage,Fledge,"
+                                 "AllowURNsInIframes,BrowsingTopics,"
+                                 "ConversionMeasurement,"
                                  "OverridePrivacySandboxSettingsLocalTesting")},
 
     {"animated-image-resume", flag_descriptions::kAnimatedImageResumeName,
@@ -7695,6 +7704,11 @@
      flag_descriptions::kPartitionedCookiesBypassOriginTrialDescription, kOsAll,
      FEATURE_VALUE_TYPE(net::features::kPartitionedCookiesBypassOriginTrial)},
 
+    {"nonced-partitioned-cookies",
+     flag_descriptions::kNoncedPartitionedCookiesName,
+     flag_descriptions::kNoncedPartitionedCookiesDescription, kOsAll,
+     FEATURE_VALUE_TYPE(net::features::kNoncedPartitionedCookies)},
+
 #if BUILDFLAG(IS_CHROMEOS_ASH)
     {kBorealisBigGlInternalName, flag_descriptions::kBorealisBigGlName,
      flag_descriptions::kBorealisBigGlDescription, kOsCrOS,
diff --git a/chrome/browser/ash/apps/apk_web_app_installer.cc b/chrome/browser/ash/apps/apk_web_app_installer.cc
index c6b5812..b126bba 100644
--- a/chrome/browser/ash/apps/apk_web_app_installer.cc
+++ b/chrome/browser/ash/apps/apk_web_app_installer.cc
@@ -188,7 +188,10 @@
             ->web_app_service_ash()
             ->GetWebAppProviderBridge();
     if (!web_app_provider_bridge) {
-      // TODO(crbug.com/1225830): handle crosapi disconnections
+      // TODO(crbug.com/1311501): make installation idempotent: by handle
+      // WebAppProviderBridge reconnect events.
+      CompleteInstallation(web_app::AppId(),
+                           webapps::InstallResultCode::kWebAppProviderNotReady);
       return;
     }
     web_app_provider_bridge->WebAppInstalledInArc(
diff --git a/chrome/browser/ash/apps/apk_web_app_service.cc b/chrome/browser/ash/apps/apk_web_app_service.cc
index da7e74e..7dd2946e 100644
--- a/chrome/browser/ash/apps/apk_web_app_service.cc
+++ b/chrome/browser/ash/apps/apk_web_app_service.cc
@@ -237,7 +237,8 @@
             ->web_app_service_ash()
             ->GetWebAppProviderBridge();
     if (!web_app_provider_bridge) {
-      // TODO(crbug.com/1225830): handle crosapi disconnections
+      // TODO(crbug.com/1311501): make uninstallation idempotent: handle
+      // WebAppProviderBridge reconnect events.
       return;
     }
     web_app_provider_bridge->WebAppUninstalledInArc(web_app_id,
diff --git a/chrome/browser/ash/arc/enterprise/arc_enterprise_reporting_service.cc b/chrome/browser/ash/arc/enterprise/arc_enterprise_reporting_service.cc
index 780d93b8..06798c5d 100644
--- a/chrome/browser/ash/arc/enterprise/arc_enterprise_reporting_service.cc
+++ b/chrome/browser/ash/arc/enterprise/arc_enterprise_reporting_service.cc
@@ -12,6 +12,9 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/strcat.h"
+#include "chrome/browser/ash/arc/arc_util.h"
 #include "chrome/browser/ash/arc/session/arc_session_manager.h"
 
 namespace arc {
@@ -36,6 +39,45 @@
   ~ArcEnterpriseReportingServiceFactory() override = default;
 };
 
+const char* TimedCloudDpcOpToString(mojom::TimedCloudDpcOp op) {
+  switch (op) {
+    case mojom::TimedCloudDpcOp::UNKNOWN_OP:
+      NOTREACHED();  // handled by if-statement in calling method
+      return "";
+    case mojom::TimedCloudDpcOp::SETUP_TOTAL:
+      return "SetupService.Total";
+    case mojom::TimedCloudDpcOp::SETUP_CHECK_FOR_ANDROID_ID:
+      return "SetupService.CheckForAndroidId";
+    case mojom::TimedCloudDpcOp::SETUP_CHECK_FOR_FIRST_ACCOUNT_READY:
+      return "SetupService.CheckForFirstAccountReady";
+    case mojom::TimedCloudDpcOp::SETUP_REGISTER:
+      return "SetupService.Register";
+    case mojom::TimedCloudDpcOp::SETUP_PULL_AND_APPLY_POLICIES:
+      return "SetupService.PullAndApplyPolicies";
+    case mojom::TimedCloudDpcOp::SETUP_REPORT_POLICY_COMPLIANCE:
+      return "SetupService.ReportPolicyCompliance";
+    case mojom::TimedCloudDpcOp::SETUP_QUARANTINED:
+      return "SetupService.QuarantinedRevised";
+    case mojom::TimedCloudDpcOp::SETUP_ADD_ACCOUNT:
+      return "SetupService.AddAccount";
+    case mojom::TimedCloudDpcOp::SETUP_INSTALL_APPS:
+      return "SetupService.InstallApps";
+    case mojom::TimedCloudDpcOp::SETUP_INSTALL_APPS_RETRY:
+      return "SetupService.InstallAppsRetry";
+    case mojom::TimedCloudDpcOp::SETUP_UPDATE_PLAY_SERVICES:
+      return "SetupService.UpdatePlayServices";
+    case mojom::TimedCloudDpcOp::SETUP_CHECK_REGISTRATION_TOKEN:
+      return "SetupService.CheckRegistrationToken";
+    case mojom::TimedCloudDpcOp::SETUP_THIRD_PARTY_SIGNIN:
+      return "SetupService.ThirdPartySignin";
+    case mojom::TimedCloudDpcOp::DEVICE_SETUP:
+      return "DeviceSetup";
+  }
+
+  NOTREACHED();
+  return "";
+}
+
 }  // namespace
 
 // static
@@ -70,4 +112,23 @@
   }
 }
 
+void ArcEnterpriseReportingService::ReportCloudDpcOperationTime(
+    int64_t time_ms,
+    mojom::TimedCloudDpcOp op,
+    bool success) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  if (op != mojom::TimedCloudDpcOp::UNKNOWN_OP) {
+    const std::string histogram_name =
+        base::StrCat({"Arc.CloudDpc.", TimedCloudDpcOpToString(op),
+                      ".TimeDelta", success ? ".Success" : ".Failure"});
+
+    base::UmaHistogramMediumTimes(
+        GetHistogramNameByUserTypeForPrimaryProfile(histogram_name),
+        base::Milliseconds(time_ms));
+  } else {
+    DLOG(ERROR) << "Attempted to record time for unknown op";
+  }
+}
+
 }  // namespace arc
diff --git a/chrome/browser/ash/arc/enterprise/arc_enterprise_reporting_service.h b/chrome/browser/ash/arc/enterprise/arc_enterprise_reporting_service.h
index a432ee5..09f0f33 100644
--- a/chrome/browser/ash/arc/enterprise/arc_enterprise_reporting_service.h
+++ b/chrome/browser/ash/arc/enterprise/arc_enterprise_reporting_service.h
@@ -39,6 +39,9 @@
 
   // mojom::EnterpriseReportingHost overrides:
   void ReportManagementState(mojom::ManagementState state) override;
+  void ReportCloudDpcOperationTime(int64_t time_ms,
+                                   mojom::TimedCloudDpcOp op,
+                                   bool success) override;
 
  private:
   THREAD_CHECKER(thread_checker_);
diff --git a/chrome/browser/ash/arc/optin/arc_optin_preference_handler.cc b/chrome/browser/ash/arc/optin/arc_optin_preference_handler.cc
index 9490985..77dc19b0 100644
--- a/chrome/browser/ash/arc/optin/arc_optin_preference_handler.cc
+++ b/chrome/browser/ash/arc/optin/arc_optin_preference_handler.cc
@@ -25,15 +25,12 @@
   if (!base::FeatureList::IsEnabled(ash::features::kPerUserMetrics))
     return false;
 
-  // Metrics mode should be propagated to owner if current user is not the owner
-  // OR ownership has not been taken.
-  const bool is_owner =
-      user_manager::UserManager::Get()->IsCurrentUserOwner() ||
-      ash::DeviceSettingsService::Get()->GetOwnershipStatus() ==
-          ash::DeviceSettingsService::OWNERSHIP_NONE;
+  auto* metrics_service = g_browser_process->metrics_service();
 
-  if (is_owner)
+  if (!metrics_service ||
+      !metrics_service->GetCurrentUserMetricsConsent().has_value()) {
     return false;
+  }
 
   // Per user metrics should be disabled if the device metrics was disabled by
   // the owner.
diff --git a/chrome/browser/ash/crosapi/local_printer_ash.cc b/chrome/browser/ash/crosapi/local_printer_ash.cc
index bea138c..0efcd40 100644
--- a/chrome/browser/ash/crosapi/local_printer_ash.cc
+++ b/chrome/browser/ash/crosapi/local_printer_ash.cc
@@ -491,9 +491,7 @@
        deny_list_from_prefs->GetListDeprecated()) {
     const std::string& deny_list_str = deny_list_value.GetString();
     printing::mojom::PrinterType printer_type;
-    if (deny_list_str == "privet")
-      printer_type = printing::mojom::PrinterType::kPrivet;
-    else if (deny_list_str == "extension")
+    if (deny_list_str == "extension")
       printer_type = printing::mojom::PrinterType::kExtension;
     else if (deny_list_str == "pdf")
       printer_type = printing::mojom::PrinterType::kPdf;
diff --git a/chrome/browser/ash/crosapi/web_app_service_ash.cc b/chrome/browser/ash/crosapi/web_app_service_ash.cc
index 24dfd8bd..a0b910d 100644
--- a/chrome/browser/ash/crosapi/web_app_service_ash.cc
+++ b/chrome/browser/ash/crosapi/web_app_service_ash.cc
@@ -9,6 +9,14 @@
 WebAppServiceAsh::WebAppServiceAsh() = default;
 WebAppServiceAsh::~WebAppServiceAsh() = default;
 
+void WebAppServiceAsh::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void WebAppServiceAsh::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void WebAppServiceAsh::BindReceiver(
     mojo::PendingReceiver<mojom::WebAppService> pending_receiver) {
   receivers_.Add(this, std::move(pending_receiver));
@@ -26,6 +34,9 @@
   web_app_provider_bridge_.Bind(std::move(web_app_provider_bridge));
   web_app_provider_bridge_.set_disconnect_handler(base::BindOnce(
       &WebAppServiceAsh::OnBridgeDisconnected, weak_factory_.GetWeakPtr()));
+  for (auto& observer : observers_) {
+    observer.OnWebAppProviderBridgeConnected();
+  }
 }
 
 mojom::WebAppProviderBridge* WebAppServiceAsh::GetWebAppProviderBridge() {
@@ -39,6 +50,9 @@
 
 void WebAppServiceAsh::OnBridgeDisconnected() {
   web_app_provider_bridge_.reset();
+  for (auto& observer : observers_) {
+    observer.OnWebAppProviderBridgeDisconnected();
+  }
 }
 
 }  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/web_app_service_ash.h b/chrome/browser/ash/crosapi/web_app_service_ash.h
index e655bff3..8bf2fce 100644
--- a/chrome/browser/ash/crosapi/web_app_service_ash.h
+++ b/chrome/browser/ash/crosapi/web_app_service_ash.h
@@ -6,6 +6,8 @@
 #define CHROME_BROWSER_ASH_CROSAPI_WEB_APP_SERVICE_ASH_H_
 
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "chromeos/crosapi/mojom/web_app_service.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -20,9 +22,18 @@
 //    ash-chrome to modify or query WebAppProvider in lacros-chrome.
 class WebAppServiceAsh : public crosapi::mojom::WebAppService {
  public:
+  class Observer : public base::CheckedObserver {
+   public:
+    virtual void OnWebAppProviderBridgeConnected() {}
+    virtual void OnWebAppProviderBridgeDisconnected() {}
+  };
+
   WebAppServiceAsh();
   ~WebAppServiceAsh() override;
 
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
   void BindReceiver(mojo::PendingReceiver<mojom::WebAppService> receiver);
 
   // crosapi::mojom::WebAppService:
@@ -46,6 +57,8 @@
   // TODO(crbug.com/1174246): Support SxS lacros.
   mojo::Remote<mojom::WebAppProviderBridge> web_app_provider_bridge_;
 
+  base::ObserverList<Observer> observers_;
+
   base::WeakPtrFactory<WebAppServiceAsh> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ash/eche_app/eche_app_manager_factory.cc b/chrome/browser/ash/eche_app/eche_app_manager_factory.cc
index ec6af5d..253f909 100644
--- a/chrome/browser/ash/eche_app/eche_app_manager_factory.cc
+++ b/chrome/browser/ash/eche_app/eche_app_manager_factory.cc
@@ -100,7 +100,7 @@
   const auto gurl = GURL(url);
 
   if (features::IsEcheCustomWidgetEnabled()) {
-    return LaunchBubble(gurl, icon);
+    return LaunchBubble(gurl, icon, visible_name);
   }
   web_app::SystemAppLaunchParams params;
   params.url = gurl;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index ce0a697..71deada 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2303,11 +2303,6 @@
           safe_browsing::IsSafeBrowsingEnabled(*prefs) &&
           !base::CommandLine::ForCurrentProcess()->HasSwitch(
               ::switches::kDisableClientSidePhishingDetection);
-#if BUILDFLAG(SAFE_BROWSING_DB_REMOTE)
-      client_side_detection_enabled &= base::FeatureList::IsEnabled(
-          safe_browsing::kClientSideDetectionForAndroid);
-#endif  // BUILDFLAG(SAFE_BROWSING_DB_REMOTE)
-
       // Disable client-side phishing detection in the renderer if it is
       // disabled in the Profile preferences, or by command line flag, or by not
       // being enabled on Android.
diff --git a/chrome/browser/component_updater/pki_metadata_component_installer.cc b/chrome/browser/component_updater/pki_metadata_component_installer.cc
index 180abb0..90a2c1ba 100644
--- a/chrome/browser/component_updater/pki_metadata_component_installer.cc
+++ b/chrome/browser/component_updater/pki_metadata_component_installer.cc
@@ -10,19 +10,20 @@
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/check.h"
 #include "base/containers/flat_map.h"
 #include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/no_destructor.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_features.h"
 #include "chrome/browser/net/key_pinning.pb.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/network_service_instance.h"
 #include "services/network/public/cpp/network_service_buildflags.h"
 #include "services/network/public/mojom/key_pinning.mojom.h"
@@ -69,6 +70,13 @@
 const base::FilePath::CharType kKPConfigProtoFileName[] =
     FILE_PATH_LITERAL("kp_pinslist.pb");
 
+// Returns the install folder path. Returns an empty path if the component is
+// not ready.
+base::FilePath& GetInstallFolderPathInstance() {
+  static base::NoDestructor<base::FilePath> instance;
+  return *instance;
+}
+
 std::string LoadBinaryProtoFromDisk(const base::FilePath& pb_path) {
   std::string result;
   if (pb_path.empty())
@@ -83,109 +91,9 @@
   return result;
 }
 
-}  // namespace
-
-namespace component_updater {
-
-PKIMetadataComponentInstallerPolicy::PKIMetadataComponentInstallerPolicy() =
-    default;
-
-PKIMetadataComponentInstallerPolicy::~PKIMetadataComponentInstallerPolicy() =
-    default;
-
-// static
-std::vector<std::vector<uint8_t>>
-PKIMetadataComponentInstallerPolicy::BytesArrayFromProtoBytes(
-    google::protobuf::RepeatedPtrField<std::string> proto_bytes) {
-  std::vector<std::vector<uint8_t>> bytes;
-  bytes.reserve(proto_bytes.size());
-  std::transform(proto_bytes.begin(), proto_bytes.end(),
-                 std::back_inserter(bytes), [](std::string element) {
-                   const uint8_t* raw_data =
-                       reinterpret_cast<const uint8_t*>(element.data());
-                   return std::vector<uint8_t>(raw_data,
-                                               raw_data + element.length());
-                 });
-  return bytes;
-}
-
-bool PKIMetadataComponentInstallerPolicy::
-    SupportsGroupPolicyEnabledComponentUpdates() const {
-  return true;
-}
-
-bool PKIMetadataComponentInstallerPolicy::RequiresNetworkEncryption() const {
-  return false;
-}
-
-update_client::CrxInstaller::Result
-PKIMetadataComponentInstallerPolicy::OnCustomInstall(
-    const base::Value& /* manifest */,
-    const base::FilePath& /* install_dir */) {
-  return update_client::CrxInstaller::Result(0);  // Nothing custom here.
-}
-
-void PKIMetadataComponentInstallerPolicy::OnCustomUninstall() {}
-
-void PKIMetadataComponentInstallerPolicy::ComponentReady(
-    const base::Version& version,
-    const base::FilePath& install_dir,
-    base::Value /* manifest */) {
-  if (base::FeatureList::IsEnabled(
-          certificate_transparency::features::
-              kCertificateTransparencyComponentUpdater)) {
-    base::ThreadPool::PostTaskAndReplyWithResult(
-        FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
-        base::BindOnce(&LoadBinaryProtoFromDisk,
-                       install_dir.Append(kCTConfigProtoFileName)),
-        base::BindOnce(&PKIMetadataComponentInstallerPolicy::
-                           UpdateNetworkServiceCTListOnUI,
-                       base::Unretained(this)));
-  }
-  if (base::FeatureList::IsEnabled(features::kKeyPinningComponentUpdater)) {
-    base::ThreadPool::PostTaskAndReplyWithResult(
-        FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
-        base::BindOnce(&LoadBinaryProtoFromDisk,
-                       install_dir.Append(kKPConfigProtoFileName)),
-        base::BindOnce(&PKIMetadataComponentInstallerPolicy::
-                           UpdateNetworkServiceKPListOnUI,
-                       base::Unretained(this)));
-  }
-}
-
-// Called during startup and installation before ComponentReady().
-bool PKIMetadataComponentInstallerPolicy::VerifyInstallation(
-    const base::Value& /* manifest */,
-    const base::FilePath& install_dir) const {
-  if (!base::PathExists(install_dir)) {
-    return false;
-  }
-
-  return true;
-}
-
-base::FilePath PKIMetadataComponentInstallerPolicy::GetRelativeInstallDir()
-    const {
-  return base::FilePath(FILE_PATH_LITERAL("PKIMetadata"));
-}
-
-void PKIMetadataComponentInstallerPolicy::GetHash(
-    std::vector<uint8_t>* hash) const {
-  hash->assign(std::begin(kPKIMetadataPublicKeySHA256),
-               std::end(kPKIMetadataPublicKeySHA256));
-}
-
-std::string PKIMetadataComponentInstallerPolicy::GetName() const {
-  return "PKI Metadata";
-}
-
-update_client::InstallerAttributes
-PKIMetadataComponentInstallerPolicy::GetInstallerAttributes() const {
-  return update_client::InstallerAttributes();
-}
-
-void PKIMetadataComponentInstallerPolicy::UpdateNetworkServiceCTListOnUI(
-    const std::string& ct_config_bytes) {
+// Updates the network service CT list with the component delivered data.
+// |ct_config_bytes| should be a serialized CTLogList proto message.
+void UpdateNetworkServiceCTListOnUI(const std::string& ct_config_bytes) {
 #if BUILDFLAG(IS_CT_SUPPORTED)
   auto proto =
       std::make_unique<chrome_browser_certificate_transparency::CTConfig>();
@@ -285,13 +193,15 @@
 
   // Send the updated popular SCTs list to the network service, if available.
   std::vector<std::vector<uint8_t>> popular_scts =
-      BytesArrayFromProtoBytes(proto->popular_scts());
+      component_updater::PKIMetadataComponentInstallerPolicy::
+          BytesArrayFromProtoBytes(proto->popular_scts());
   network_service->UpdateCtKnownPopularSCTs(std::move(popular_scts));
 #endif  // BUILDFLAG(IS_CT_SUPPORTED)
 }
 
-void PKIMetadataComponentInstallerPolicy::UpdateNetworkServiceKPListOnUI(
-    const std::string& kp_config_bytes) {
+// Updates the network service pins list with the component delivered data.
+// |kp_config_bytes| should be a serialized KPConfig proto message.
+void UpdateNetworkServiceKPListOnUI(const std::string& kp_config_bytes) {
   auto proto = std::make_unique<chrome_browser_key_pinning::PinList>();
   if (!proto->ParseFromString(kp_config_bytes)) {
     return;
@@ -309,9 +219,11 @@
     network::mojom::PinSetPtr pinset_ptr = network::mojom::PinSet::New();
     pinset_ptr->name = pinset.name();
     pinset_ptr->static_spki_hashes =
-        BytesArrayFromProtoBytes(pinset.static_spki_hashes_sha256());
+        component_updater::PKIMetadataComponentInstallerPolicy::
+            BytesArrayFromProtoBytes(pinset.static_spki_hashes_sha256());
     pinset_ptr->bad_static_spki_hashes =
-        BytesArrayFromProtoBytes(pinset.bad_static_spki_hashes_sha256());
+        component_updater::PKIMetadataComponentInstallerPolicy::
+            BytesArrayFromProtoBytes(pinset.bad_static_spki_hashes_sha256());
     pinset_ptr->report_uri = pinset.report_uri();
     pinlist_ptr->pinsets.push_back(std::move(pinset_ptr));
   }
@@ -332,6 +244,123 @@
   network_service->UpdateKeyPinsList(std::move(pinlist_ptr), update_time);
 }
 
+}  // namespace
+
+namespace component_updater {
+
+PKIMetadataComponentInstallerPolicy::PKIMetadataComponentInstallerPolicy() =
+    default;
+
+PKIMetadataComponentInstallerPolicy::~PKIMetadataComponentInstallerPolicy() =
+    default;
+
+// static
+void PKIMetadataComponentInstallerPolicy::ReconfigureAfterNetworkRestart() {
+  // Runs on UI thread.
+  if (GetInstallFolderPathInstance().empty()) {
+    return;
+  }
+  if (base::FeatureList::IsEnabled(
+          certificate_transparency::features::
+              kCertificateTransparencyComponentUpdater)) {
+    base::ThreadPool::PostTaskAndReplyWithResult(
+        FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
+        base::BindOnce(
+            &LoadBinaryProtoFromDisk,
+            GetInstallFolderPathInstance().Append(kCTConfigProtoFileName)),
+        base::BindOnce(&UpdateNetworkServiceCTListOnUI));
+  }
+  if (base::FeatureList::IsEnabled(features::kKeyPinningComponentUpdater)) {
+    base::ThreadPool::PostTaskAndReplyWithResult(
+        FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
+        base::BindOnce(
+            &LoadBinaryProtoFromDisk,
+            GetInstallFolderPathInstance().Append(kKPConfigProtoFileName)),
+        base::BindOnce(&UpdateNetworkServiceKPListOnUI));
+  }
+}
+
+// static
+std::vector<std::vector<uint8_t>>
+PKIMetadataComponentInstallerPolicy::BytesArrayFromProtoBytes(
+    google::protobuf::RepeatedPtrField<std::string> proto_bytes) {
+  std::vector<std::vector<uint8_t>> bytes;
+  bytes.reserve(proto_bytes.size());
+  std::transform(proto_bytes.begin(), proto_bytes.end(),
+                 std::back_inserter(bytes), [](std::string element) {
+                   const uint8_t* raw_data =
+                       reinterpret_cast<const uint8_t*>(element.data());
+                   return std::vector<uint8_t>(raw_data,
+                                               raw_data + element.length());
+                 });
+  return bytes;
+}
+
+// static
+void PKIMetadataComponentInstallerPolicy::WriteComponentForTesting(
+    const base::FilePath& path,
+    std::string contents) {
+  CHECK(base::WriteFile(path.Append(kCTConfigProtoFileName), contents));
+  GetInstallFolderPathInstance() = path;
+}
+
+bool PKIMetadataComponentInstallerPolicy::
+    SupportsGroupPolicyEnabledComponentUpdates() const {
+  return true;
+}
+
+bool PKIMetadataComponentInstallerPolicy::RequiresNetworkEncryption() const {
+  return false;
+}
+
+update_client::CrxInstaller::Result
+PKIMetadataComponentInstallerPolicy::OnCustomInstall(
+    const base::Value& /* manifest */,
+    const base::FilePath& /* install_dir */) {
+  return update_client::CrxInstaller::Result(0);  // Nothing custom here.
+}
+
+void PKIMetadataComponentInstallerPolicy::OnCustomUninstall() {}
+
+void PKIMetadataComponentInstallerPolicy::ComponentReady(
+    const base::Version& version,
+    const base::FilePath& install_dir,
+    base::Value /* manifest */) {
+  GetInstallFolderPathInstance() = install_dir;
+  ReconfigureAfterNetworkRestart();
+}
+
+// Called during startup and installation before ComponentReady().
+bool PKIMetadataComponentInstallerPolicy::VerifyInstallation(
+    const base::Value& /* manifest */,
+    const base::FilePath& install_dir) const {
+  if (!base::PathExists(install_dir)) {
+    return false;
+  }
+
+  return true;
+}
+
+base::FilePath PKIMetadataComponentInstallerPolicy::GetRelativeInstallDir()
+    const {
+  return base::FilePath(FILE_PATH_LITERAL("PKIMetadata"));
+}
+
+void PKIMetadataComponentInstallerPolicy::GetHash(
+    std::vector<uint8_t>* hash) const {
+  hash->assign(std::begin(kPKIMetadataPublicKeySHA256),
+               std::end(kPKIMetadataPublicKeySHA256));
+}
+
+std::string PKIMetadataComponentInstallerPolicy::GetName() const {
+  return "PKI Metadata";
+}
+
+update_client::InstallerAttributes
+PKIMetadataComponentInstallerPolicy::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
+}
+
 void MaybeRegisterPKIMetadataComponent(ComponentUpdateService* cus) {
   bool should_install =
       base::FeatureList::IsEnabled(features::kKeyPinningComponentUpdater);
diff --git a/chrome/browser/component_updater/pki_metadata_component_installer.h b/chrome/browser/component_updater/pki_metadata_component_installer.h
index a7ce1898..dcad294 100644
--- a/chrome/browser/component_updater/pki_metadata_component_installer.h
+++ b/chrome/browser/component_updater/pki_metadata_component_installer.h
@@ -26,11 +26,18 @@
       const PKIMetadataComponentInstallerPolicy&) = delete;
   ~PKIMetadataComponentInstallerPolicy() override;
 
+  // Sets the PKI metadata configuration on the current network service. This is
+  // a no-op if the component is not ready.
+  static void ReconfigureAfterNetworkRestart();
+
   // Converts a protobuf repeated bytes array to an array of uint8_t arrays.
   // Exposed for testing.
   static std::vector<std::vector<uint8_t>> BytesArrayFromProtoBytes(
       google::protobuf::RepeatedPtrField<std::string> proto_bytes);
 
+  static void WriteComponentForTesting(const base::FilePath& path,
+                                       std::string contents);
+
  private:
   // ComponentInstallerPolicy methods:
   bool SupportsGroupPolicyEnabledComponentUpdates() const override;
@@ -48,14 +55,6 @@
   void GetHash(std::vector<uint8_t>* hash) const override;
   std::string GetName() const override;
   update_client::InstallerAttributes GetInstallerAttributes() const override;
-
-  // Updates the network service CT list with the component delivered data.
-  // |ct_config_bytes| should be a serialized CTLogList proto message.
-  void UpdateNetworkServiceCTListOnUI(const std::string& ct_config_bytes);
-
-  // Updates the network service pins list with the component delivered data.
-  // |kp_config_bytes| should be a serialized KPConfig proto message.
-  void UpdateNetworkServiceKPListOnUI(const std::string& kp_config_bytes);
 };
 
 void MaybeRegisterPKIMetadataComponent(ComponentUpdateService* cus);
diff --git a/chrome/browser/component_updater/pki_metadata_component_installer_browsertest.cc b/chrome/browser/component_updater/pki_metadata_component_installer_browsertest.cc
new file mode 100644
index 0000000..a9e3159
--- /dev/null
+++ b/chrome/browser/component_updater/pki_metadata_component_installer_browsertest.cc
@@ -0,0 +1,122 @@
+// 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 "base/command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/component_updater/pki_metadata_component_installer.h"
+#include "chrome/browser/net/system_network_context_manager.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/chrome_test_utils.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/test_launcher_utils.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/certificate_transparency/certificate_transparency_config.pb.h"
+#include "components/certificate_transparency/ct_features.h"
+#include "content/public/browser/network_service_instance.h"
+#include "content/public/common/network_service_util.h"
+#include "content/public/test/browser_test.h"
+#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
+#include "services/network/public/mojom/network_service_test.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+enum class CTEnforcement { kEnabled, kDisabled };
+
+void SetRequireCTForTesting() {
+  mojo::Remote<network::mojom::NetworkServiceTest> network_service_test;
+  content::GetNetworkService()->BindTestInterface(
+      network_service_test.BindNewPipeAndPassReceiver());
+
+  mojo::ScopedAllowSyncCallForTesting allow_sync_call;
+  network_service_test->SetRequireCT(
+      network::mojom::NetworkServiceTest::RequireCT::REQUIRE);
+  return;
+}
+
+}  // namespace
+
+// TODO(crbug.com/1286121): add tests for pinning enforcement.
+class PKIMetadataComponentUpdaterTest
+    : public InProcessBrowserTest,
+      public testing::WithParamInterface<CTEnforcement> {
+ public:
+  void SetUpInProcessBrowserTestFixture() override {
+    InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+    SystemNetworkContextManager::SetEnableCertificateTransparencyForTesting(
+        true);
+    CHECK(component_dir_.CreateUniqueTempDir());
+
+    // Set up a configuration that will enable or disable CT enforcement
+    // depending on the test parameter.
+    chrome_browser_certificate_transparency::CTConfig ct_config;
+    ct_config.set_disable_ct_enforcement(GetParam() ==
+                                         CTEnforcement::kDisabled);
+    ct_config.mutable_log_list()->mutable_timestamp()->set_seconds(
+        (base::Time::Now() - base::Time::UnixEpoch()).InSeconds());
+    component_updater::PKIMetadataComponentInstallerPolicy::
+        WriteComponentForTesting(component_dir_.GetPath(),
+                                 ct_config.SerializeAsString());
+  }
+
+ protected:
+  void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
+    base::CommandLine default_command_line(base::CommandLine::NO_PROGRAM);
+    InProcessBrowserTest::SetUpDefaultCommandLine(&default_command_line);
+    test_launcher_utils::RemoveCommandLineSwitch(
+        default_command_line, switches::kDisableComponentUpdate, command_line);
+  }
+
+  base::test::ScopedFeatureList scoped_feature_list_{
+      certificate_transparency::features::
+          kCertificateTransparencyComponentUpdater};
+  base::ScopedTempDir component_dir_;
+};
+
+// Tests that the PKI Metadata configuration is recovered after a network
+// service restart.
+IN_PROC_BROWSER_TEST_P(PKIMetadataComponentUpdaterTest,
+                       ReloadsPKIMetadataConfigAfterCrash) {
+  // Network service is not running out of process, so cannot be crashed.
+  if (!content::IsOutOfProcessNetworkService())
+    return;
+
+  // CT enforcement is disabled by default on tests. Override this behaviour.
+  SetRequireCTForTesting();
+
+  net::EmbeddedTestServer https_server_ok(net::EmbeddedTestServer::TYPE_HTTPS);
+  https_server_ok.SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
+  https_server_ok.ServeFilesFromSourceDirectory("chrome/test/data");
+  ASSERT_TRUE(https_server_ok.Start());
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), https_server_ok.GetURL("/simple.html")));
+
+  // Check that the page is blocked depending on CT enforcement.
+  content::WebContents* tab = chrome_test_utils::GetActiveWebContents(this);
+  ASSERT_TRUE(WaitForRenderFrameReady(tab->GetMainFrame()));
+  if (GetParam() == CTEnforcement::kEnabled) {
+    EXPECT_NE(u"OK", chrome_test_utils::GetActiveWebContents(this)->GetTitle());
+  } else {
+    EXPECT_EQ(u"OK", chrome_test_utils::GetActiveWebContents(this)->GetTitle());
+  }
+
+  // Restart the network service.
+  SimulateNetworkServiceCrash();
+  SetRequireCTForTesting();
+
+  // Check that the page is still blocked depending on CT enforcement.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), https_server_ok.GetURL("/simple.html")));
+  ASSERT_TRUE(WaitForRenderFrameReady(tab->GetMainFrame()));
+  if (GetParam() == CTEnforcement::kEnabled) {
+    EXPECT_NE(u"OK", chrome_test_utils::GetActiveWebContents(this)->GetTitle());
+  } else {
+    EXPECT_EQ(u"OK", chrome_test_utils::GetActiveWebContents(this)->GetTitle());
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(PKIMetadataComponentUpdater,
+                         PKIMetadataComponentUpdaterTest,
+                         testing::Values(CTEnforcement::kEnabled,
+                                         CTEnforcement::kDisabled));
diff --git a/chrome/browser/component_updater/pki_metadata_component_installer_unittest.cc b/chrome/browser/component_updater/pki_metadata_component_installer_unittest.cc
index a8fa88df..c183145 100644
--- a/chrome/browser/component_updater/pki_metadata_component_installer_unittest.cc
+++ b/chrome/browser/component_updater/pki_metadata_component_installer_unittest.cc
@@ -32,7 +32,7 @@
 
 namespace {
 // An arbitrary, DER-encoded subjectpublickeyinfo encoded as BASE64.
-const char* kLogSPKIBase64 =
+const char kLogSPKIBase64[] =
     "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1+5tMt7sGC0MTw/AloiaTsFbEpW3s"
     "g3GCAFY6wRP5Izt+mV/Q9xHb450LppfptaYh94nIkVIhtTkSQ4b2GRxOAcaSkpTsN+PUPaO2D"
     "Jd/5M7MFxXeHGYqXIbdD+rgSsU5rcBspFbJkRv+Q34bqNeiwKT+zcYqfAEH3cYvDGF+FIxXrZ"
@@ -44,30 +44,28 @@
     "Iyrq1REXsoc/O0HVCXQXKP1/g6mduco4wA57lH1BSJrSet5Rc8NyR5g7zR8FPzXvav+eErLwd"
     "RsVdo4HNxlBlrc50CqkbsNFg2hdU1uCbbzRHKAF5Ih/NGdFkQZ9N+pPbTcpA8z5mWyjo6cCAw"
     "EAAQ==";
-const char* kLogIdBase64 = "ASNFZ4mrze8QERITFBUWFxgZGhscHR4f";
+const char kLogIdBase64[] = "ASNFZ4mrze8QERITFBUWFxgZGhscHR4f";
 constexpr uint64_t kLogMMDSeconds = 42;
-const char* kLogURL = "https://futuregadgetlab.jp";
-const char* kLogName = "FutureGadgetLog2022";
-const char* kLogOperatorName = "Future Gadget Lab";
-const char* kLogOperatorEmail = "kurisu@dmail.com";
+const char kLogURL[] = "https://futuregadgetlab.jp";
+const char kLogName[] = "FutureGadgetLog2022";
+const char kLogOperatorName[] = "Future Gadget Lab";
+const char kLogOperatorEmail[] = "kurisu@dmail.com";
 constexpr base::TimeDelta kCurrentOperatorStart = base::Days(3);
-const char* kPreviousOperator1Name = "SERN";
+const char kPreviousOperator1Name[] = "SERN";
 constexpr base::TimeDelta kPreviousOperator1Start = base::Days(2);
-const char* kPreviousOperator2Name = "DURPA";
+const char kPreviousOperator2Name[] = "DURPA";
 constexpr base::TimeDelta kPreviousOperator2Start = base::Days(1);
-const char* kGoogleLogName = "GoogleLog2022";
-const char* kGoogleLogOperatorName = "Google";
+const char kGoogleLogName[] = "GoogleLog2022";
+const char kGoogleLogOperatorName[] = "Google";
 constexpr base::TimeDelta kGoogleLogDisqualificationDate = base::Days(2);
 
 // BASE64 encoded fake leaf hashes.
-const std::string kPopularSCT1 = "EBESExQVFhcYGRobHB0eHwEjRWeJq83v";
-const std::string kPopularSCT2 = "oKGio6SlpqeoqaqrrK2urwEjRWeJq83v";
+const char kPopularSCT1[] = "EBESExQVFhcYGRobHB0eHwEjRWeJq83v";
+const char kPopularSCT2[] = "oKGio6SlpqeoqaqrrK2urwEjRWeJq83v";
 
 constexpr uint64_t kMaxSupportedCompatibilityVersion = 2;
 }  // namespace
 
-// TODO(crbug.com/1306559): add a test for disabling ct enforcement once
-// crbug.com/1306559 is fixed.
 class PKIMetadataComponentInstallerTest : public testing::Test {
  public:
   void SetUp() override {
@@ -212,6 +210,30 @@
   task_environment_.RunUntilIdle();
 }
 
+// Tests that setting the CT enforcement kill switch successfully disables CT
+// enforcement.
+TEST_F(PKIMetadataComponentInstallerTest, CTEnforcementKillSwitch) {
+  // Initialize the network service.
+  content::GetNetworkService();
+  task_environment_.RunUntilIdle();
+
+  ct_config_.set_disable_ct_enforcement(true);
+  WriteCtConfigToFile();
+  policy_->ComponentReady(base::Version("1.2.3.4"),
+                          component_install_dir_.GetPath(), base::Value());
+  task_environment_.RunUntilIdle();
+
+  network::NetworkService* network_service =
+      network::NetworkService::GetNetworkServiceForTesting();
+  ASSERT_TRUE(network_service);
+
+  // Logs should not have been updated.
+  const std::vector<network::mojom::CTLogInfoPtr>& logs =
+      network_service->log_list();
+  EXPECT_EQ(logs.size(), 0u);
+  EXPECT_FALSE(network_service->is_ct_enforcement_enabled_for_testing());
+}
+
 // Tests that installing the PKI Metadata component updates the network service.
 TEST_F(PKIMetadataComponentInstallerTest, InstallComponent) {
   // Initialize the network service.
@@ -265,6 +287,8 @@
   EXPECT_TRUE(cache->IsPopularSCT(*base::Base64Decode(kPopularSCT1)));
   EXPECT_TRUE(cache->IsPopularSCT(*base::Base64Decode(kPopularSCT2)));
   EXPECT_FALSE(cache->IsPopularSCT(std::vector<const uint8_t>{1, 2, 3, 4}));
+
+  EXPECT_TRUE(network_service->is_ct_enforcement_enabled_for_testing());
 }
 
 // Tests that installing the PKI Metadata component bails out if the proto is
@@ -292,6 +316,7 @@
   const std::vector<network::mojom::CTLogInfoPtr>& logs =
       network_service->log_list();
   EXPECT_EQ(logs.size(), 0u);
+  EXPECT_TRUE(network_service->is_ct_enforcement_enabled_for_testing());
 }
 
 // Tests that installing the PKI Metadata component bails out if the CT
@@ -318,6 +343,24 @@
   const std::vector<network::mojom::CTLogInfoPtr>& logs =
       network_service->log_list();
   EXPECT_EQ(logs.size(), 0u);
+  EXPECT_TRUE(network_service->is_ct_enforcement_enabled_for_testing());
+}
+
+// Tests that calling |ReconfigureAfterNetworkRestart| is a no-op if the
+// component has not been installed.
+TEST_F(PKIMetadataComponentInstallerTest, ReconfigureWhenNotInstalled) {
+  // Initialize the network service.
+  content::GetNetworkService();
+  task_environment_.RunUntilIdle();
+  PKIMetadataComponentInstallerPolicy::ReconfigureAfterNetworkRestart();
+
+  // The logs should not have been updated.
+  network::NetworkService* network_service =
+      network::NetworkService::GetNetworkServiceForTesting();
+  ASSERT_TRUE(network_service);
+  const std::vector<network::mojom::CTLogInfoPtr>& logs =
+      network_service->log_list();
+  EXPECT_EQ(logs.size(), 0u);
 }
 
 class PKIMetadataComponentInstallerDisabledTest
diff --git a/chrome/browser/error_reporting/BUILD.gn b/chrome/browser/error_reporting/BUILD.gn
index 68719e2..e6486a1a 100644
--- a/chrome/browser/error_reporting/BUILD.gn
+++ b/chrome/browser/error_reporting/BUILD.gn
@@ -5,7 +5,7 @@
 
 # TODO(crbug.com/1129544) This is currently disabled due to Windows DLL
 # thunking issues. Fix & re-enable.
-assert(is_linux || is_chromeos_ash || is_chromeos_lacros)
+assert(is_linux || is_chromeos)
 
 source_set("constants") {
   sources = [
@@ -36,7 +36,7 @@
     "//services/network:network_service",
     "//services/network/public/cpp",
   ]
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [ "chrome_js_error_report_processor_chromeos.cc" ]
     deps += [ ":constants" ]
   } else {
@@ -60,7 +60,7 @@
     "//components/crash/content/browser/error_reporting:mock_crash_endpoint",
     "//components/variations",
   ]
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     data_deps = [ ":mock_chromeos_crash_reporter" ]
   }
 }
@@ -83,7 +83,7 @@
   ]
 }
 
-if (is_chromeos_ash || is_chromeos_lacros) {
+if (is_chromeos) {
   executable("mock_chromeos_crash_reporter") {
     testonly = true
     sources = [ "mock_chromeos_crash_reporter.cc" ]
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 37537b8c..a71defe 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -1273,7 +1273,7 @@
       "setupapi.lib",
       "propsys.lib",
     ]
-  } else if (use_aura && !is_chromeos_ash && !is_chromeos_lacros) {
+  } else if (use_aura && !is_chromeos) {
     sources += [
       "system_display/display_info_provider_aura.cc",
       "system_display/display_info_provider_aura.h",
diff --git a/chrome/browser/extensions/api/favicon/favicon_apitest.cc b/chrome/browser/extensions/api/favicon/favicon_apitest.cc
index e173531f..d6113ce 100644
--- a/chrome/browser/extensions/api/favicon/favicon_apitest.cc
+++ b/chrome/browser/extensions/api/favicon/favicon_apitest.cc
@@ -2,14 +2,23 @@
 // // Use of this source code is governed by a BSD-style license that can be
 // // found in the LICENSE file.
 
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "components/version_info/channel.h"
 #include "content/public/test/browser_test.h"
+#include "extensions/common/extension_features.h"
 
 namespace extensions {
 
 class FaviconApiTest : public ExtensionApiTest {
+ public:
+  FaviconApiTest() {
+    feature_list_.InitAndEnableFeature(
+        extensions_features::kNewExtensionFaviconHandling);
+  }
+
  private:
+  base::test::ScopedFeatureList feature_list_;
   ScopedCurrentChannel current_cnannel_{version_info::Channel::CANARY};
 };
 
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc b/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
index d70e369..16e1a8d 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
+++ b/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
@@ -277,42 +277,60 @@
   EXPECT_FALSE(match.deletable);
 }
 
-IN_PROC_BROWSER_TEST_P(OmniboxApiBackgroundPageTest, OnInputEntered) {
-  ASSERT_TRUE(RunExtensionTest("omnibox")) << message_;
+IN_PROC_BROWSER_TEST_P(OmniboxApiTest, OnInputEntered) {
+  constexpr char kManifest[] =
+      R"({
+           "name": "Basic Send Suggestions",
+           "manifest_version": 2,
+           "version": "0.1",
+           "omnibox": { "keyword": "alpha" },
+           "background": { "scripts": [ "background.js" ], "persistent": true }
+         })";
+  // This extension will collect input entered into the omnibox and pass it
+  // to the browser when instructed.
+  constexpr char kBackground[] =
+      R"(let results = [];
+         chrome.omnibox.onInputEntered.addListener((text, disposition) => {
+           if (text == 'send results') {
+             chrome.test.sendMessage(JSON.stringify(results));
+             return;
+           }
+           results.push({text, disposition});
+         });)";
+
+  extensions::TestExtensionDir test_dir;
+  test_dir.WriteManifest(kManifest);
+  test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackground);
+  const extensions::Extension* extension =
+      LoadExtension(test_dir.UnpackedPath());
+  ASSERT_TRUE(extension);
 
   LocationBar* location_bar = GetLocationBar(browser());
   OmniboxView* omnibox_view = location_bar->GetOmniboxView();
   ResultCatcher catcher;
   AutocompleteController* autocomplete_controller = GetAutocompleteController();
-  omnibox_view->OnBeforePossibleChange();
-  omnibox_view->SetUserText(u"kw command");
-  omnibox_view->OnAfterPossibleChange(true);
 
-  {
-    AutocompleteInput input(u"kw command", metrics::OmniboxEventProto::NTP,
+  auto send_input = [this, autocomplete_controller, omnibox_view](
+                        std::u16string input_string,
+                        WindowOpenDisposition disposition) {
+    AutocompleteInput input(input_string, metrics::OmniboxEventProto::NTP,
                             ChromeAutocompleteSchemeClassifier(profile()));
     autocomplete_controller->Start(input);
-  }
-  omnibox_view->model()->AcceptInput(WindowOpenDisposition::CURRENT_TAB);
-  WaitForAutocompleteDone(browser());
-  EXPECT_TRUE(autocomplete_controller->done());
-  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+    omnibox_view->model()->AcceptInput(disposition);
+    WaitForAutocompleteDone(browser());
+  };
 
-  omnibox_view->OnBeforePossibleChange();
-  omnibox_view->SetUserText(u"kw newtab");
-  omnibox_view->OnAfterPossibleChange(true);
-  WaitForAutocompleteDone(browser());
-  EXPECT_TRUE(autocomplete_controller->done());
+  send_input(u"alpha current tab", WindowOpenDisposition::CURRENT_TAB);
+  send_input(u"alpha new tab", WindowOpenDisposition::NEW_FOREGROUND_TAB);
 
-  {
-    AutocompleteInput input(u"kw newtab", metrics::OmniboxEventProto::NTP,
-                            ChromeAutocompleteSchemeClassifier(profile()));
-    autocomplete_controller->Start(input);
-  }
-  omnibox_view->model()->AcceptInput(WindowOpenDisposition::NEW_FOREGROUND_TAB);
-  WaitForAutocompleteDone(browser());
-  EXPECT_TRUE(autocomplete_controller->done());
-  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+  ExtensionTestMessageListener listener(/*will_reply=*/false);
+  send_input(u"alpha send results", WindowOpenDisposition::CURRENT_TAB);
+  ASSERT_TRUE(listener.WaitUntilSatisfied());
+
+  static constexpr char kExpectedResult[] =
+      R"([{"text":"current tab","disposition":"currentTab"},)"
+      R"({"text":"new tab","disposition":"newForegroundTab"}])";
+  EXPECT_EQ(kExpectedResult, listener.message());
 }
 
 // Tests receiving suggestions from and sending input to the incognito context
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index d0e1946..65a7a34 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -308,11 +308,6 @@
     "expiry_milestone": 102
   },
   {
-    "name": "ash-enable-floating-window",
-    "owners": [ "shidi", "afakhry" ],
-    "expiry_milestone": 100
-  },
-  {
     "name": "ash-enable-pip-rounded-corners",
     "owners": [ "edcourtney" ],
     "expiry_milestone": 96
@@ -1006,6 +1001,11 @@
     "expiry_milestone": 100
   },
   {
+    "name": "cros-labs-float-window",
+    "owners": [ "shidi", "afakhry" ],
+    "expiry_milestone": 110
+  },
+  {
     "name": "crosh-swa",
     "owners": [ "joelhockey", "benwells" ],
     "expiry_milestone": 110
@@ -3183,6 +3183,11 @@
     "expiry_milestone": 102
   },
   {
+    "name": "fast-pair-subsequent-pairing-ux",
+    "owners": [ "//ash/quick_pair/OWNERS", "dclasson@google.com" ],
+    "expiry_milestone": 104
+  },
+  {
     "name": "feature-notification-guide",
     "owners": [ "shaktisahu"],
     "expiry_milestone": 110
@@ -4172,6 +4177,11 @@
     "expiry_milestone": 100
   },
   {
+    "name": "nonced-partitioned-cookies",
+    "owners": [ "dylancutler" ],
+    "expiry_milestone": 112
+  },
+  {
     "name": "notification-permission-rationale-dialog",
     "owners": ["shaktisahu", "salg"],
     "expiry_milestone": 110
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index c9083c6..cb2272cf 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2209,6 +2209,13 @@
     "origin trial in order to send or receive cookies set with the Partitioned "
     "attribute.";
 
+const char kNoncedPartitionedCookiesName[] = "Nonced partitioned cookies only";
+const char kNoncedPartitionedCookiesDescription[] =
+    "When this flag is enabled, we allow partitioned cookies whose "
+    "partition keys contain a nonce even if the \"Partitioned cookies\" "
+    "feature is disabled. If \"Partitioned cookies\" are enabled, then "
+    "enabling or disabling this feature does nothing.";
+
 const char kScrollableTabStripFlagId[] = "scrollable-tabstrip";
 const char kScrollableTabStripName[] = "Tab Scrolling";
 const char kScrollableTabStripDescription[] =
@@ -4439,6 +4446,12 @@
     "Allow using Fast Pair on devices which don't support hardware offloading "
     "of BLE scans. For development use.";
 
+const char kFastPairSubsequentPairingUXName[] =
+    "Enable Fast Pair Subsequent Pairing UX";
+const char kFastPairSubsequentPairingUXDescription[] =
+    "Enables the \"Subsequent Pairing\" Fast Pair scenario in Bluetooth "
+    "Settings and Quick Settings.";
+
 const char kUseHDRTransferFunctionName[] =
     "Monitor/Display HDR transfer function";
 const char kUseHDRTransferFunctionDescription[] =
@@ -4810,6 +4823,11 @@
 const char kFilesWebDriveOfficeDescription[] =
     "Enable opening Office files located in Files app Drive in Web Drive.";
 
+const char kFloatWindow[] = "CrOS Labs: Float current active window";
+const char kFloatWindowDescription[] =
+    "Enables the accelerator (Command + Alt + F) to float current active "
+    "window.";
+
 const char kForceSpectreVariant2MitigationName[] =
     "Force Spectre variant 2 mitigagtion";
 const char kForceSpectreVariant2MitigationDescription[] =
@@ -5379,11 +5397,6 @@
     "Enables the option to sync Wi-Fi network configurations between Chrome OS "
     "devices and a connected Android phone";
 
-const char kWindowControlMenu[] = "Float current active window";
-const char kWindowControlMenuDescription[] =
-    "Enables the accelerator (Command + Alt + F) to float current active "
-    "window.";
-
 const char kLauncherNudgeName[] = "Enable launcher nudge";
 const char kLauncherNudgeDescription[] =
     "Enables nudges that bring new users' attention to the launcher button.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 8a5c89bd..b4701ff 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1247,6 +1247,9 @@
 extern const char kPartitionedCookiesBypassOriginTrialName[];
 extern const char kPartitionedCookiesBypassOriginTrialDescription[];
 
+extern const char kNoncedPartitionedCookiesName[];
+extern const char kNoncedPartitionedCookiesDescription[];
+
 extern const char kScrollableTabStripFlagId[];
 extern const char kScrollableTabStripName[];
 extern const char kScrollableTabStripDescription[];
@@ -2544,6 +2547,9 @@
 extern const char kFastPairSoftwareScanningName[];
 extern const char kFastPairSoftwareScanningDescription[];
 
+extern const char kFastPairSubsequentPairingUXName[];
+extern const char kFastPairSubsequentPairingUXDescription[];
+
 extern const char kUseHDRTransferFunctionName[];
 extern const char kUseHDRTransferFunctionDescription[];
 
@@ -2763,6 +2769,9 @@
 extern const char kFiltersInRecentsName[];
 extern const char kFiltersInRecentsDescription[];
 
+extern const char kFloatWindow[];
+extern const char kFloatWindowDescription[];
+
 extern const char kFocusFollowsCursorName[];
 extern const char kFocusFollowsCursorDescription[];
 
@@ -3095,9 +3104,6 @@
 extern const char kWifiSyncAndroidName[];
 extern const char kWifiSyncAndroidDescription[];
 
-extern const char kWindowControlMenu[];
-extern const char kWindowControlMenuDescription[];
-
 extern const char kLauncherNudgeName[];
 extern const char kLauncherNudgeDescription[];
 
diff --git a/chrome/browser/media/router/providers/cast/app_activity_unittest.cc b/chrome/browser/media/router/providers/cast/app_activity_unittest.cc
index fd787e8..8a34872 100644
--- a/chrome/browser/media/router/providers/cast/app_activity_unittest.cc
+++ b/chrome/browser/media/router/providers/cast/app_activity_unittest.cc
@@ -51,8 +51,9 @@
     CastActivityTestBase::SetUp();
 
     activity_ = std::make_unique<AppActivity>(
-        MediaRoute(kRouteId, MediaSource(), kSinkId, "", false), kAppId,
-        &message_handler_, &session_tracker_);
+        MediaRoute(kRouteId, MediaSource("https://example.com/receiver.html"),
+                   kSinkId, "", false),
+        kAppId, &message_handler_, &session_tracker_);
   }
 
   void SetUpSession() { activity_->SetOrUpdateSession(*session_, sink_, ""); }
diff --git a/chrome/browser/metrics/metrics_reporting_state.cc b/chrome/browser/metrics/metrics_reporting_state.cc
index 6cbc25e..38dcfad3 100644
--- a/chrome/browser/metrics/metrics_reporting_state.cc
+++ b/chrome/browser/metrics/metrics_reporting_state.cc
@@ -26,6 +26,8 @@
 #include "content/public/browser/browser_thread.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
+#include "chrome/browser/browser_process_platform_part.h"
 #include "components/metrics/structured/neutrino_logging.h"  // nogncheck
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
@@ -185,21 +187,25 @@
 }
 
 bool IsMetricsReportingPolicyManaged() {
-  const PrefService* pref_service = g_browser_process->local_state();
-  const PrefService::Preference* pref =
-      pref_service->FindPreference(metrics::prefs::kMetricsReportingEnabled);
-  bool is_managed = pref && pref->IsManaged();
-
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+  policy::BrowserPolicyConnectorAsh* policy_connector =
+      g_browser_process->platform_part()->browser_policy_connector_ash();
+  const bool is_managed = policy_connector->IsDeviceEnterpriseManaged();
+
   metrics::structured::NeutrinoDevicesLogPolicy(
       g_browser_process->local_state()->GetString(
           metrics::prefs::kMetricsClientID),
       is_managed,
       metrics::structured::NeutrinoDevicesLocation::
           kIsMetricsReportingPolicyManaged);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   return is_managed;
+#else
+  const PrefService* pref_service = g_browser_process->local_state();
+  const PrefService::Preference* pref =
+      pref_service->FindPreference(metrics::prefs::kMetricsReportingEnabled);
+  return pref && pref->IsManaged();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void ClearPreviouslyCollectedMetricsData() {
diff --git a/chrome/browser/metrics/metrics_reporting_state.h b/chrome/browser/metrics/metrics_reporting_state.h
index 810c42a0..e5366d1f 100644
--- a/chrome/browser/metrics/metrics_reporting_state.h
+++ b/chrome/browser/metrics/metrics_reporting_state.h
@@ -67,6 +67,10 @@
 
 // Returns whether MetricsReporting can be modified by the user (except
 // Android).
+//
+// For Ash Chrome, metrics reporting may be controlled by an enterprise policy
+// and the metrics service pref inherits the value from the policy. Reporting
+// policy will be considered managed if an enterprise policy exists.
 bool IsMetricsReportingPolicyManaged();
 
 // Clears previously collected metrics data. Used when enabling metrics to
diff --git a/chrome/browser/metrics/metrics_reporting_state_browsertest.cc b/chrome/browser/metrics/metrics_reporting_state_browsertest.cc
index 48dab582..8f95a13 100644
--- a/chrome/browser/metrics/metrics_reporting_state_browsertest.cc
+++ b/chrome/browser/metrics/metrics_reporting_state_browsertest.cc
@@ -29,6 +29,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_service_accessor.h"
+#include "components/policy/core/common/cloud/test/policy_builder.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
@@ -36,6 +37,7 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/components/tpm/stub_install_attributes.h"
 #include "chrome/browser/ash/settings/device_settings_cache.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "components/policy/proto/device_management_backend.pb.h"
@@ -82,12 +84,12 @@
     return ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled();
   }
 
-  virtual bool is_metrics_reporting_enabled_initial_value() const = 0;
+  virtual bool IsMetricsReportingEnabledInitialValue() const = 0;
 
   // InProcessBrowserTest overrides:
   bool SetUpUserDataDirectory() override {
     local_state_path_ = metrics::SetUpUserDataDirectoryForTesting(
-        is_metrics_reporting_enabled_initial_value());
+        IsMetricsReportingEnabledInitialValue());
     return !local_state_path_.empty();
   }
 
@@ -99,7 +101,7 @@
         true);
     static_cast<ChromeBrowserMainParts*>(parts)->AddParts(
         std::make_unique<ChromeBrowserMainExtraPartsChecker>(
-            is_metrics_reporting_enabled_initial_value()));
+            IsMetricsReportingEnabledInitialValue()));
   }
 
  protected:
@@ -126,7 +128,7 @@
 
   ~MetricsReportingStateTestParameterized() override = default;
 
-  bool is_metrics_reporting_enabled_initial_value() const override {
+  bool IsMetricsReportingEnabledInitialValue() const override {
     return GetParam().initial_value;
   }
 
@@ -147,9 +149,7 @@
           ChangeMetricsReportingStateCalledFrom> {
  public:
   // Set metrics reporting to false initially.
-  bool is_metrics_reporting_enabled_initial_value() const override {
-    return false;
-  }
+  bool IsMetricsReportingEnabledInitialValue() const override { return false; }
 };
 
 void ChromeBrowserMainExtraPartsChecker::PostEarlyInitialization() {
@@ -178,7 +178,7 @@
 // Verifies that metrics reporting state is correctly written to disk when set.
 IN_PROC_BROWSER_TEST_P(MetricsReportingStateTestParameterized,
                        ChangeMetricsReportingState) {
-  ASSERT_EQ(is_metrics_reporting_enabled_initial_value(),
+  ASSERT_EQ(IsMetricsReportingEnabledInitialValue(),
             MetricsReportingStateTest::IsMetricsAndCrashReportingEnabled());
 
   // Update the client's metrics reporting state.
@@ -286,3 +286,52 @@
     testing::ValuesIn<ChangeMetricsReportingStateCalledFrom>(
         {ChangeMetricsReportingStateCalledFrom::kUnknown,
          ChangeMetricsReportingStateCalledFrom::kUiSettings}));
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+// Used to verify that managed/unmanged devices returns correct values based on
+// management state.
+class MetricsReportingStateManagedTest
+    : public MetricsReportingStateTest,
+      public testing::WithParamInterface<bool> {
+ public:
+  MetricsReportingStateManagedTest() = default;
+  MetricsReportingStateManagedTest(const MetricsReportingStateManagedTest&) =
+      delete;
+  MetricsReportingStateManagedTest& operator=(
+      const MetricsReportingStateManagedTest&) = delete;
+  ~MetricsReportingStateManagedTest() = default;
+
+  void SetUp() override {
+    is_managed_ = GetParam();
+    if (is_managed()) {
+      install_attributes_ = std::make_unique<ash::ScopedStubInstallAttributes>(
+          ash::StubInstallAttributes::CreateCloudManaged("domain",
+                                                         "device_id"));
+    } else {
+      install_attributes_ = std::make_unique<ash::ScopedStubInstallAttributes>(
+          ash::StubInstallAttributes::CreateConsumerOwned());
+    }
+
+    MetricsReportingStateTest::SetUp();
+  }
+
+  // Set metrics reporting to false.
+  bool IsMetricsReportingEnabledInitialValue() const override { return false; }
+
+ protected:
+  bool is_managed() const { return is_managed_; }
+
+ private:
+  bool is_managed_;
+  std::unique_ptr<ash::ScopedStubInstallAttributes> install_attributes_;
+};
+
+IN_PROC_BROWSER_TEST_P(MetricsReportingStateManagedTest,
+                       IsMetricsReportingPolicyManagedReturnsCorrectValue) {
+  EXPECT_EQ(IsMetricsReportingPolicyManaged(), is_managed());
+}
+
+INSTANTIATE_TEST_SUITE_P(MetricsReportingStateTests,
+                         MetricsReportingStateManagedTest,
+                         testing::Bool());
+#endif
diff --git a/chrome/browser/metrics/structured/BUILD.gn b/chrome/browser/metrics/structured/BUILD.gn
index d18f1ce..8818379 100644
--- a/chrome/browser/metrics/structured/BUILD.gn
+++ b/chrome/browser/metrics/structured/BUILD.gn
@@ -5,7 +5,7 @@
 import("//build/config/chrome_build.gni")
 import("//build/config/chromeos/ui_mode.gni")
 
-assert(is_chromeos_ash || is_chromeos_lacros)
+assert(is_chromeos)
 
 static_library("structured") {
   sources = [
diff --git a/chrome/browser/net/net_export_helper.cc b/chrome/browser/net/net_export_helper.cc
index 9cea0a60..db46203 100644
--- a/chrome/browser/net/net_export_helper.cc
+++ b/chrome/browser/net/net_export_helper.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/net/net_export_helper.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/values.h"
 #include "build/build_config.h"
@@ -56,12 +57,11 @@
           extensions::ExtensionRegistry::Get(profile)
               ->GenerateInstalledExtensionsSet());
       for (const auto& extension : *extensions) {
-        std::unique_ptr<base::DictionaryValue> extension_info(
-            new base::DictionaryValue());
+        base::Value::Dict extension_info;
         bool enabled = extension_service->IsExtensionEnabled(extension->id());
         extensions::GetExtensionBasicInfo(extension.get(), enabled,
-                                          extension_info.get());
-        extension_list->Append(std::move(extension_info));
+                                          &extension_info);
+        extension_list->Append(base::Value(std::move(extension_info)));
       }
     }
   }
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index 689fa22e..b7c4568 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/component_updater/crl_set_component_installer.h"
 #include "chrome/browser/component_updater/first_party_sets_component_installer.h"
+#include "chrome/browser/component_updater/pki_metadata_component_installer.h"
 #include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
 #include "chrome/browser/net/convert_explicitly_allowed_network_ports_pref.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
@@ -691,6 +692,9 @@
   // Configure SCT Auditing in the NetworkService.
   SCTReportingService::ReconfigureAfterNetworkRestart();
 
+  component_updater::PKIMetadataComponentInstallerPolicy::
+      ReconfigureAfterNetworkRestart();
+
   UpdateExplicitlyAllowedNetworkPorts();
 }
 
diff --git a/chrome/browser/policy/messaging_layer/upload/record_handler_impl_unittest.cc b/chrome/browser/policy/messaging_layer/upload/record_handler_impl_unittest.cc
index 31945dc..59e0de1 100644
--- a/chrome/browser/policy/messaging_layer/upload/record_handler_impl_unittest.cc
+++ b/chrome/browser/policy/messaging_layer/upload/record_handler_impl_unittest.cc
@@ -352,6 +352,30 @@
   EXPECT_EQ(response.status().error_code(), error::INTERNAL);
 }
 
+TEST_P(RecordHandlerImplTest, MissingSequenceInformation) {
+  static constexpr int64_t kNumTestRecords = 10;
+  static constexpr int64_t kGenerationId = 1234;
+  // test records that has one record with missing sequence information.
+  auto test_records = BuildTestRecordsVector(kNumTestRecords, kGenerationId);
+  test_records->back().clear_sequence_information();
+
+  // The response should show an error and UploadEncryptedReport should not have
+  // been even called, because UploadEncryptedReportingRequestBuilder::Build()
+  // should fail in this situation.
+  EXPECT_CALL(*client_, UploadEncryptedReport(_, _, _)).Times(0);
+
+  test::TestEvent<SignedEncryptionInfo> encryption_key_attached_event;
+  test::TestEvent<DmServerUploadService::CompletionResponse> responder_event;
+
+  RecordHandlerImpl handler(client_.get());
+  handler.HandleRecords(need_encryption_key(), std::move(test_records),
+                        responder_event.cb(),
+                        encryption_key_attached_event.cb());
+
+  auto response = responder_event.result();
+  EXPECT_EQ(response.status().error_code(), error::INTERNAL);
+}
+
 TEST_P(RecordHandlerImplTest, ReportsUploadFailure) {
   static constexpr int64_t kNumTestRecords = 10;
   static constexpr int64_t kGenerationId = 1234;
diff --git a/chrome/browser/policy/messaging_layer/upload/upload_provider.cc b/chrome/browser/policy/messaging_layer/upload/upload_provider.cc
index 35900331..7bd5798 100644
--- a/chrome/browser/policy/messaging_layer/upload/upload_provider.cc
+++ b/chrome/browser/policy/messaging_layer/upload/upload_provider.cc
@@ -244,7 +244,9 @@
   if (upload_client_ == nullptr) {
     stored_need_encryption_key_ |= need_encryption_key;
     int64_t generation_id = 0;
-    if (records && !records->empty()) {
+    if (records && !records->empty() &&
+        records->begin()->has_sequence_information() &&
+        records->begin()->sequence_information().has_generation_id()) {
       generation_id = records->begin()->sequence_information().generation_id();
     }
     stored_records_.emplace(generation_id, std::move(records));
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 772044d..433ea0d 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -737,6 +737,8 @@
 const char kStabilityLaunchCount[] =
     "user_experience_metrics.stability.launch_count";
 #endif
+const char kStabilityExtensionRendererLaunchCount[] =
+    "user_experience_metrics.stability.extension_renderer_launch_count";
 
 // Register local state used only for migration (clearing or moving to a new
 // key).
@@ -774,6 +776,7 @@
 #if !BUILDFLAG(IS_ANDROID)
   registry->RegisterIntegerPref(kStabilityLaunchCount, 0);
 #endif
+  registry->RegisterIntegerPref(kStabilityExtensionRendererLaunchCount, 0);
 }
 
 // Register prefs used only for migration (clearing or moving to a new key).
@@ -1616,6 +1619,7 @@
 #if !BUILDFLAG(IS_ANDROID)
   local_state->ClearPref(kStabilityLaunchCount);
 #endif
+  local_state->ClearPref(kStabilityExtensionRendererLaunchCount);
 
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_LOCAL_STATE_PREFS
diff --git a/chrome/browser/printing/print_test_utils.cc b/chrome/browser/printing/print_test_utils.cc
index 0199470..ad17f0c6 100644
--- a/chrome/browser/printing/print_test_utils.cc
+++ b/chrome/browser/printing/print_test_utils.cc
@@ -18,6 +18,8 @@
 const char kDummyPrinterName[] = "DefaultPrinter";
 
 base::Value GetPrintTicket(mojom::PrinterType type) {
+  DCHECK_NE(type, mojom::PrinterType::kPrivetDeprecated);
+
   base::Value ticket(base::Value::Type::DICTIONARY);
 
   // Letter
@@ -53,8 +55,7 @@
 
   if (type == mojom::PrinterType::kCloud) {
     ticket.SetStringKey(kSettingCloudPrintId, kDummyPrinterName);
-  } else if (type == mojom::PrinterType::kPrivet ||
-             type == mojom::PrinterType::kExtension) {
+  } else if (type == mojom::PrinterType::kExtension) {
     base::Value capabilities(base::Value::Type::DICTIONARY);
     capabilities.SetBoolKey("duplex", true);  // non-empty
     std::string caps_string;
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
index e97f38b2..072fdde 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/BUILD.gn
@@ -64,7 +64,6 @@
   "common/abstract_earcons.js",
   "common/braille_interface.js",
   "common/chromevox.js",
-  "common/console_tts.js",
   "common/extension_bridge.js",
   "common/key_sequence.js",
   "common/msgs.js",
@@ -120,6 +119,7 @@
   "common/abstract_tts.js",
   "common/command_store.js",
   "common/composite_tts.js",
+  "common/console_tts.js",
   "common/editable_text_base.js",
   "common/key_util.js",
   "common/keyboard_handler.js",
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
index c62c6cd..2a46403 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/classic_background.js
@@ -8,6 +8,7 @@
 
 import {AbstractTts} from '../common/abstract_tts.js';
 import {CompositeTts} from '../common/composite_tts.js';
+import {ConsoleTts} from '../common/console_tts.js';
 import {ChromeVoxEditableTextBase, TypingEcho} from '../common/editable_text_base.js';
 import {TtsBackground} from '../common/tts_background.js';
 
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
index c264236..1394a369 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/loader.js
@@ -22,7 +22,6 @@
 goog.require('ChromeVoxState');
 goog.require('ChromeVoxStateObserver');
 goog.require('CommandHandlerInterface');
-goog.require('ConsoleTts');
 goog.require('EventGenerator');
 goog.require('EventSourceState');
 goog.require('EventStreamLogger');
@@ -40,6 +39,7 @@
 goog.require('PanelCommand');
 goog.require('PhoneticData');
 goog.require('QueueMode');
+goog.require('SpeechLog');
 goog.require('TreeDumper');
 goog.require('TreePathRecoveryStrategy');
 goog.require('TtsInterface');
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js
index 52c3eda..a4e37a6 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/prefs.js
@@ -7,6 +7,7 @@
  * the background context (background page or options page).
  *
  */
+import {ConsoleTts} from '../common/console_tts.js';
 
 /**
  * This object has default values of preferences and contains the common
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/common/console_tts.js b/chrome/browser/resources/chromeos/accessibility/chromevox/common/console_tts.js
index 90621fe..f053cd1 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/common/console_tts.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/common/console_tts.js
@@ -6,16 +6,10 @@
  * @fileoverview A TTS engine that writes to window.console.
  */
 
-goog.provide('ConsoleTts');
-
-goog.require('LogStore');
-goog.require('SpeechLog');
-goog.require('TtsInterface');
-
 /**
  * @implements {TtsInterface}
  */
-ConsoleTts = class {
+export class ConsoleTts {
   constructor() {
     /**
      * True if the console TTS is enabled by the user.
@@ -25,6 +19,20 @@
     this.enabled_ = false;
   }
 
+  /** @return {!ConsoleTts} */
+  static getInstance() {
+    if (!ConsoleTts.instance_) {
+      ConsoleTts.instance_ = new ConsoleTts();
+    }
+    return ConsoleTts.instance_;
+  }
+
+  /**
+   * @param {string} textString
+   * @param {!QueueMode} queueMode
+   * @param {Object=} properties
+   * @return {!ConsoleTts}
+   */
   speak(textString, queueMode, properties) {
     if (this.enabled_ && window['console']) {
       let category = TtsCategory.NAV;
@@ -60,8 +68,12 @@
   /** @override */
   increaseOrDecreaseProperty() {}
 
-  /** @override */
-  propertyToPercentage() {}
+  /**
+   * @param {string} property
+   * @return {number}
+   * @override
+   */
+  propertyToPercentage(property) {}
 
   /**
    * Sets the enabled bit.
@@ -71,13 +83,28 @@
     this.enabled_ = enabled;
   }
 
-  /** @override */
+  /**
+   * @param {string} property
+   * @return {number}
+   * @override
+   */
   getDefaultProperty(property) {}
 
-  /** @override */
+  /**
+   * @return {boolean}
+   * @override
+   */
   toggleSpeechOnOrOff() {}
 
   /** @override */
   resetTextToSpeechSettings() {}
-};
-goog.addSingletonGetter(ConsoleTts);
+}
+
+/** @private {!ConsoleTts} */
+ConsoleTts.instance_;
+
+chrome.runtime.onMessage.addListener((message, sender, respond) => {
+  if (message.target === 'ConsoleTts' && message.action === 'getInstance') {
+    respond(ConsoleTts.getInstance());
+  }
+});
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
index a1b4a018..6ec524d 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options.js
@@ -7,8 +7,8 @@
  *
  */
 import {ChromeVoxPrefs} from '../background/prefs.js';
-
 import {AbstractTts} from '../common/abstract_tts.js';
+import {ConsoleTts} from '../common/console_tts.js';
 import {TtsBackground} from '../common/tts_background.js';
 
 /** @const {string} */
@@ -28,8 +28,6 @@
    */
   static init() {
     OptionsPage.prefs = chrome.extension.getBackgroundPage()['prefs'];
-    OptionsPage.consoleTts =
-        chrome.extension.getBackgroundPage().ConsoleTts.getInstance();
     OptionsPage.backgroundTts =
         chrome.extension.getBackgroundPage().ChromeVoxState.backgroundTts;
     OptionsPage.populateVoicesSelect();
@@ -556,6 +554,10 @@
 };
 
 
+chrome.runtime.sendMessage(
+    {target: 'ConsoleTts', action: 'getInstance'},
+    (consoleTts) => OptionsPage.consoleTts = consoleTts);
+
 document.addEventListener('DOMContentLoaded', function() {
   OptionsPage.init();
 }, false);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js
index 6d265b2..58744888 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/options/options_loader.js
@@ -10,12 +10,13 @@
 goog.require('BrailleTable');
 goog.require('BrailleTranslatorManager');
 goog.require('ChromeVox');
-goog.require('ConsoleTts');
 goog.require('EventStreamLogger');
 goog.require('ExtensionBridge');
+goog.require('LogStore');
 goog.require('Msgs');
 goog.require('PanelCommand');
 goog.require('PhoneticData');
+goog.require('SpeechLog');
 goog.require('TtsInterface');
 
 goog.require('constants');
diff --git a/chrome/browser/resources/new_tab_page/modules/modules.ts b/chrome/browser/resources/new_tab_page/modules/modules.ts
index 771eaba..4dd4d23c 100644
--- a/chrome/browser/resources/new_tab_page/modules/modules.ts
+++ b/chrome/browser/resources/new_tab_page/modules/modules.ts
@@ -271,6 +271,10 @@
         return moduleContainer;
       });
 
+      if (modules.length > 0) {
+        NewTabPageProxy.getInstance().handler.incrementModulesShownCount();
+      }
+
       chrome.metricsPrivate.recordSmallCount(
           'NewTabPage.Modules.LoadedModulesCount', modules.length);
 
diff --git a/chrome/browser/resources/ntp4/new_tab.css b/chrome/browser/resources/ntp4/new_tab.css
index 47e47f6..dda8cfc 100644
--- a/chrome/browser/resources/ntp4/new_tab.css
+++ b/chrome/browser/resources/ntp4/new_tab.css
@@ -45,11 +45,30 @@
   height: 100%;
 }
 
+#deprecated-apps-link-container {
+  align-items: center;
+  display: inline-flex;
+  margin-top: 10px;
+  padding-inline-end: 20px;
+  position: fixed;
+  right: 0;
+}
+
+html[dir='rtl'] #deprecated-apps-link-container {
+  left: 0;
+  right: auto;
+}
+
+#deprecated-apps-link-container img {
+  height: 16px;
+  width: 16px;
+}
+
 #attribution {
   bottom: 0;
-  margin-left: 8px;
+  margin-left: 8px;   /* csschecker-disable-line left-right */
   /* Leave room for the scrollbar. */
-  margin-right: 13px;
+  margin-right: 13px;  /* csschecker-disable-line left-right */
   position: absolute;
   z-index: -5;
 }
@@ -57,7 +76,7 @@
 html[dir='rtl'] #attribution {
   left: 0;
   right: auto;
-  text-align: right;
+  text-align: right;   /* csschecker-disable-line left-right */
 }
 
 #attribution > span {
diff --git a/chrome/browser/resources/ntp4/new_tab.html b/chrome/browser/resources/ntp4/new_tab.html
index 90b769c..bbd51e6 100644
--- a/chrome/browser/resources/ntp4/new_tab.html
+++ b/chrome/browser/resources/ntp4/new_tab.html
@@ -45,6 +45,11 @@
     </div>
   </div>
 
+  <div id="deprecated-apps-link-container" hidden>
+    <img src="images/error_yellow900.svg">
+    <a is="action-link" id="deprecated-apps-link" href="#"></a>
+  </div>
+
   <div id="footer">
     <div id="footer-border"></div>
     <div id="footer-content">
diff --git a/chrome/browser/resources/ntp4/new_tab.js b/chrome/browser/resources/ntp4/new_tab.js
index 52a84b3..430376bc 100644
--- a/chrome/browser/resources/ntp4/new_tab.js
+++ b/chrome/browser/resources/ntp4/new_tab.js
@@ -134,6 +134,18 @@
 }
 
 /**
+ * Launches the deprecated apps deletion dialog on click.
+ * @param {!Event} e The click/auxclick event.
+ */
+function onChromeDeprecatedAppsDeletionLinkClick(e) {
+  if (/** @type {MouseEvent} */ (e).button > 1) {
+    return;
+  }
+  e.preventDefault();
+  chrome.send('deprecatedDialogLinkClicked');
+}
+
+/**
  * Queued callbacks which lie in wait for all sections to be ready.
  * @type {Array}
  */
@@ -289,11 +301,29 @@
  * Note that calls to this function can occur at any time, not just in
  * response to a getApps request. For example, when a user
  * installs/uninstalls an app on another synchronized devices.
- * @param {{apps: Array<AppInfo>, appPageNames: Array<string>}} data
- *     An object with all the data on available applications.
+ * @param {{apps: Array<AppInfo>, appPageNames: Array<string>,
+ *     deprecatedAppsDialogLinkText: string}} data An object with all the data
+ *     on available applications.
  */
 function getAppsCallback(data) {
   newTabView.getAppsCallback(data);
+  setUpDeprecatedAppsDialogLink(data.deprecatedAppsDialogLinkText);
+}
+
+/**
+ * Called whenever there are deprecated apps on the page, to set up the link
+ * to trigger the deprecated apps dialog.
+ * @param {string} linkText The link text to trigger the deprecated apps dialog.
+ */
+function setUpDeprecatedAppsDialogLink(linkText) {
+  if (linkText) {
+    $('deprecated-apps-link').textContent = linkText;
+    $('deprecated-apps-link')
+        .addEventListener('click', onChromeDeprecatedAppsDeletionLinkClick);
+    $('deprecated-apps-link-container').hidden = false;
+  } else {
+    $('deprecated-apps-link-container').hidden = true;
+  }
 }
 
 /**
diff --git a/chrome/browser/resources/ntp4/page_list_view.js b/chrome/browser/resources/ntp4/page_list_view.js
index 1ed39d54..09adbe7 100644
--- a/chrome/browser/resources/ntp4/page_list_view.js
+++ b/chrome/browser/resources/ntp4/page_list_view.js
@@ -298,8 +298,9 @@
    * Note that calls to this function can occur at any time, not just in
    * response to a getApps request. For example, when a user
    * installs/uninstalls an app on another synchronized devices.
-   * @param {{apps: Array<AppInfo>, appPageNames: Array<string>}} data
-   *     An object with all the data on available applications.
+   * @param {{apps: Array<AppInfo>, appPageNames: Array<string>,
+   *     deprecatedAppsDialogLinkText: string}} data An object with all the data
+   *     on available applications.
    */
   getAppsCallback(data) {
     // Remember this to select the correct card when done rebuilding.
diff --git a/chrome/browser/resources/print_preview/data/destination_match.ts b/chrome/browser/resources/print_preview/data/destination_match.ts
index 22a474ef..1fa20239 100644
--- a/chrome/browser/resources/print_preview/data/destination_match.ts
+++ b/chrome/browser/resources/print_preview/data/destination_match.ts
@@ -7,11 +7,10 @@
 
 /**
  * Printer types for capabilities and printer list requests.
- * Must match PrinterType in printing/print_job_constants.h
- * Note: PRIVET_PRINTER is deprecated.
+ * Must match PrinterType in printing/mojom/print.mojom
  */
 export enum PrinterType {
-  PRIVET_PRINTER = 0,
+  PRIVET_PRINTER_DEPRECATED = 0,
   EXTENSION_PRINTER = 1,
   PDF_PRINTER = 2,
   LOCAL_PRINTER = 3,
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index ee0e4fc2..5d9a919 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -269,7 +269,7 @@
     "//tools/typescript/definitions/runtime.d.ts",
     "//tools/typescript/definitions/settings_private.d.ts",
   ]
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     definitions +=
         [ "//tools/typescript/definitions/quick_unlock_private.d.ts" ]
   }
diff --git a/chrome/browser/resources/settings/settings.gni b/chrome/browser/resources/settings/settings.gni
index 4bc4264b..2b827ed2c1 100644
--- a/chrome/browser/resources/settings/settings.gni
+++ b/chrome/browser/resources/settings/settings.gni
@@ -165,7 +165,7 @@
   ]
 }
 
-if (!is_chromeos_ash && !is_chromeos_lacros) {
+if (!is_chromeos) {
   web_component_files += [
     "default_browser_page/default_browser_page.ts",
     "people_page/import_data_dialog.ts",
@@ -186,7 +186,7 @@
   ]
 }
 
-if (is_chromeos_ash || is_chromeos_lacros) {
+if (is_chromeos) {
   web_component_files += [ "controls/password_prompt_dialog.ts" ]
 }
 
@@ -270,7 +270,7 @@
   "site_settings/website_usage_browser_proxy.ts",
 ]
 
-if (is_chromeos_ash || is_chromeos_lacros) {
+if (is_chromeos) {
   non_web_component_files += [ "autofill_page/blocking_request_manager.ts" ]
 }
 
diff --git a/chrome/browser/safe_browsing/client_side_detection_service_factory.cc b/chrome/browser/safe_browsing/client_side_detection_service_factory.cc
index 91d4a16..c2e1bac 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service_factory.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service_factory.cc
@@ -43,16 +43,6 @@
 
 KeyedService* ClientSideDetectionServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  bool client_side_detection_enabled =
-#if BUILDFLAG(FULL_SAFE_BROWSING)
-      true;
-#else
-      base::FeatureList::IsEnabled(
-          safe_browsing::kClientSideDetectionForAndroid);
-#endif
-  if (!client_side_detection_enabled)
-    return nullptr;
-
   Profile* profile = Profile::FromBrowserContext(context);
   return new ClientSideDetectionService(
       std::make_unique<ChromeClientSideDetectionServiceDelegate>(profile));
diff --git a/chrome/browser/safe_browsing/download_protection/file_analyzer.cc b/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
index 5d37a7e5..a2b7083 100644
--- a/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
+++ b/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
@@ -103,9 +103,7 @@
     StartExtractDmgFeatures();
 #endif
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
-  } else if (base::FeatureList::IsEnabled(
-                 safe_browsing::kClientSideDetectionDocumentScanning) &&
-             inspection_type == DownloadFileType::OFFICE_DOCUMENT) {
+  } else if (inspection_type == DownloadFileType::OFFICE_DOCUMENT) {
     StartExtractDocumentFeatures();
 #endif
   } else {
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_cros.cc b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_cros.cc
index 8cf75076..56188a9 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_cros.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_cros.cc
@@ -18,13 +18,186 @@
 
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_29SiteA_11SiteA_40Client2_11SiteA_34SiteA_22) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_7SiteA_12SiteA_37SiteA_17_20) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconNotShown();
+  helper_.CheckLaunchIconShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestCros,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_7SiteA_12SiteA_41_10SiteA_42_12SiteA_7SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.SyncTurnOff();
+  helper_.UninstallFromList("SiteA");
+  helper_.SyncTurnOn();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestCros,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_7SiteA_12SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.SwitchProfileClients("Client1");
+  helper_.CheckAppNotInList("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestCros,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_7SiteA_12SiteA_37SiteA_17_20) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconNotShown();
+  helper_.CheckLaunchIconShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestCros,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_7SiteA_12SiteA_41_10SiteA_42_12SiteA_7SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.SyncTurnOff();
+  helper_.UninstallFromList("SiteA");
+  helper_.SyncTurnOn();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestCros,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_7SiteA_12SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.SwitchProfileClients("Client1");
+  helper_.CheckAppNotInList("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestCros,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_7SiteA_12SiteA_37SiteA_17_20) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconNotShown();
+  helper_.CheckLaunchIconShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestCros,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_7SiteA_12SiteA_41_10SiteA_42_12SiteA_7SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.SyncTurnOff();
+  helper_.UninstallFromList("SiteA");
+  helper_.SyncTurnOn();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestCros,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_7SiteA_12SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.SwitchProfileClients("Client1");
+  helper_.CheckAppNotInList("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestCros,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_7SiteA_11SiteA_34SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutTabbed("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckTabCreated();
@@ -32,184 +205,39 @@
 
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_30SiteA_24_12SiteA_40Client2_12SiteA_37SiteA_17_20) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconNotShown();
-  helper_.CheckLaunchIconShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_31SiteA_24_12SiteA_40Client2_12SiteA_37SiteA_17_20) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconNotShown();
-  helper_.CheckLaunchIconShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_47SiteA_24_12SiteA_40Client2_12SiteA_37SiteA_17_20) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconNotShown();
-  helper_.CheckLaunchIconShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_30SiteA_24_12SiteA_40Client2_12SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.SwitchProfileClients("Client1");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_31SiteA_24_12SiteA_40Client2_12SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.SwitchProfileClients("Client1");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_47SiteA_24_12SiteA_40Client2_12SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.SwitchProfileClients("Client1");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_29SiteA_11SiteA_40Client2_11SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_7SiteA_11SiteA_41_10SiteA_42_11SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutTabbed("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.SwitchProfileClients("Client1");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_30SiteA_24_12SiteA_40Client2_12SiteA_41_10SiteA_42_12SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListWindowed("SiteA");
   helper_.SyncTurnOff();
   helper_.UninstallFromList("SiteA");
   helper_.SyncTurnOn();
-  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_31SiteA_24_12SiteA_40Client2_12SiteA_41_10SiteA_42_12SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SyncTurnOff();
-  helper_.UninstallFromList("SiteA");
-  helper_.SyncTurnOn();
-  helper_.CheckAppInListWindowed("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_47SiteA_24_12SiteA_40Client2_12SiteA_41_10SiteA_42_12SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SyncTurnOff();
-  helper_.UninstallFromList("SiteA");
-  helper_.SyncTurnOn();
-  helper_.CheckAppInListWindowed("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestCros,
-    WebAppIntegration_29SiteA_11SiteA_40Client2_11SiteA_41_10SiteA_42_11SiteA) {
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_7SiteA_11SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutTabbed("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
-  helper_.SyncTurnOff();
   helper_.UninstallFromList("SiteA");
-  helper_.SyncTurnOn();
-  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.SwitchProfileClients("Client1");
+  helper_.CheckAppNotInList("SiteA");
 }
 
 }  // namespace
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc
index 5887d9203..a536851 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_mac_win_linux.cc
@@ -20,388 +20,6 @@
 
 // TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
 #if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20 \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20
-#else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20 \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconNotShown();
-  helper_.CheckLaunchIconShown();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24 \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24
-#else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24 \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22 \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22
-#else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22 \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckTabCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19 \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19
-#else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19 \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20 \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20
-#else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20 \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconNotShown();
-  helper_.CheckLaunchIconShown();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24 \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24
-#else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24 \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22 \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22
-#else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22 \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckTabCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19 \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19
-#else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19 \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20 \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20
-#else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20 \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_37SiteA_17_20) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconNotShown();
-  helper_.CheckLaunchIconShown();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24 \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24
-#else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24 \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_34SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22 \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22
-#else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22 \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_34SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckTabCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19 \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19
-#else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19 \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_46SiteA_11SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_46SiteA_11SiteA_34SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckTabCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_34SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckTabCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_30SiteC_12SiteC_40Client2_45SiteC_46SiteC_12SiteC_37SiteC_17_20 \
-  DISABLED_WebAppIntegration_30SiteC_12SiteC_40Client2_45SiteC_46SiteC_12SiteC_37SiteC_17_20
-#else
-#define MAYBE_WebAppIntegration_30SiteC_12SiteC_40Client2_45SiteC_46SiteC_12SiteC_37SiteC_17_20 \
-  WebAppIntegration_30SiteC_12SiteC_40Client2_45SiteC_46SiteC_12SiteC_37SiteC_17_20
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteC_12SiteC_40Client2_45SiteC_46SiteC_12SiteC_37SiteC_17_20) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteC");
-  helper_.InstallLocally("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.NavigateBrowser("SiteC");
-  helper_.CheckInstallIconNotShown();
-  helper_.CheckLaunchIconShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    WebAppIntegration_29SiteC_11SiteC_40Client2_45SiteC_46SiteC_11SiteC_37SiteC_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteC");
-  helper_.CheckAppInListTabbed("SiteC");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteC");
-  helper_.InstallLocally("SiteC");
-  helper_.CheckAppInListTabbed("SiteC");
-  helper_.NavigateBrowser("SiteC");
-  helper_.CheckLaunchIconNotShown();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
 #define MAYBE_WebAppIntegration_41_30SiteA_42_40Client2_45SiteA \
   DISABLED_WebAppIntegration_41_30SiteA_42_40Client2_45SiteA
 #else
@@ -510,24 +128,81 @@
 
 // TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
 #if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24 \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20 \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20
 #else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24 \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20 \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20
 #endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24) {
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconNotShown();
+  helper_.CheckLaunchIconShown();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24 \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24
+#else
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24 \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24 \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24
+#else
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24 \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromLaunchIcon("SiteA");
   helper_.CheckWindowCreated();
@@ -535,24 +210,286 @@
 
 // TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
 #if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24 \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24 \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24
 #else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24 \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24 \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24
 #endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24) {
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24 \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24
+#else
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24 \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromPlatformShortcut("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22 \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22
+#else
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22 \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckTabCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22 \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22
+#else
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22 \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.LaunchFromPlatformShortcut("SiteA");
+  helper_.CheckTabCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19 \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19
+#else
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19 \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
+#else
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.SyncTurnOff();
+  helper_.UninstallFromList("SiteA");
+  helper_.SyncTurnOn();
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#else
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.SyncTurnOff();
+  helper_.UninstallFromMenu("SiteA");
+  helper_.SyncTurnOn();
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
+  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
+#else
+#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
+  WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.SwitchProfileClients("Client1");
+  helper_.CheckAppNotInList("SiteA");
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20 \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20
+#else
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20 \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconNotShown();
+  helper_.CheckLaunchIconShown();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24 \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24
+#else
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24 \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24 \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24
+#else
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24 \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromLaunchIcon("SiteA");
   helper_.CheckWindowCreated();
@@ -560,24 +497,286 @@
 
 // TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
 #if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24 \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24 \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24
 #else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24 \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24 \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24
 #endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_35SiteA_24) {
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24 \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24
+#else
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24 \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromPlatformShortcut("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22 \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22
+#else
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22 \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckTabCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22 \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22
+#else
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22 \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.LaunchFromPlatformShortcut("SiteA");
+  helper_.CheckTabCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19 \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19
+#else
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19 \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
+#else
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.SyncTurnOff();
+  helper_.UninstallFromList("SiteA");
+  helper_.SyncTurnOn();
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#else
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.SyncTurnOff();
+  helper_.UninstallFromMenu("SiteA");
+  helper_.SyncTurnOn();
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
+  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
+#else
+#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
+  WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.SwitchProfileClients("Client1");
+  helper_.CheckAppNotInList("SiteA");
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20 \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20
+#else
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20 \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_37SiteA_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconNotShown();
+  helper_.CheckLaunchIconShown();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24 \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24
+#else
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24 \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_69SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24 \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24
+#else
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24 \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromLaunchIcon("SiteA");
   helper_.CheckWindowCreated();
@@ -585,178 +784,149 @@
 
 // TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
 #if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24 \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24
 #else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24 \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24
 #endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.SwitchProfileClients("Client1");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
-#else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.SwitchProfileClients("Client1");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
-#else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_34SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.SwitchProfileClients("Client1");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.SwitchProfileClients("Client1");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
-#else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.SyncTurnOff();
-  helper_.UninstallFromList("SiteA");
-  helper_.SyncTurnOn();
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
-#else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.SyncTurnOff();
-  helper_.UninstallFromList("SiteA");
-  helper_.SyncTurnOn();
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
 }
 
 // TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
 #if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24 \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24
 #else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24 \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24
 #endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA) {
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_12SiteA_1SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.SyncTurnOff();
-  helper_.UninstallFromList("SiteA");
-  helper_.SyncTurnOn();
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromPlatformShortcut("SiteA");
+  helper_.CheckWindowCreated();
 }
 
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22 \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22
+#else
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22 \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22
+#endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA) {
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_34SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckTabCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22 \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22
+#else
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22 \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_1SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.LaunchFromPlatformShortcut("SiteA");
+  helper_.CheckTabCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19 \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19
+#else
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19 \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
+#else
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.SyncTurnOff();
@@ -767,21 +937,22 @@
 
 // TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
 #if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
 #else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
 #endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA) {
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.SyncTurnOff();
@@ -792,46 +963,165 @@
 
 // TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
 #if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
+  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
 #else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA \
+  WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA
 #endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA) {
+    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
+  helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.SwitchProfileClients("Client1");
+  helper_.CheckAppNotInList("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_11SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_11SiteA_34SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckTabCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_11SiteA_1SiteA_22 \
+  DISABLED_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_11SiteA_1SiteA_22
+#else
+#define MAYBE_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_11SiteA_1SiteA_22 \
+  WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_11SiteA_1SiteA_22
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_46SiteA_7SiteA_11SiteA_1SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.InstallLocally("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.LaunchFromPlatformShortcut("SiteA");
+  helper_.CheckTabCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_34SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckTabCreated();
+}
+
+// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_1SiteA_22 \
+  DISABLED_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_1SiteA_22
+#else
+#define MAYBE_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_1SiteA_22 \
+  WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_1SiteA_22
+#endif
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    MAYBE_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_1SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.LaunchFromPlatformShortcut("SiteA");
+  helper_.CheckTabCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_41_10SiteA_42_45SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.SyncTurnOff();
-  helper_.UninstallFromMenu("SiteA");
+  helper_.UninstallFromList("SiteA");
   helper_.SyncTurnOn();
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
 }
 
 // TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
 #if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#define MAYBE_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
+  DISABLED_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
 #else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#define MAYBE_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
+  WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
 #endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA) {
+    MAYBE_WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.SyncTurnOff();
@@ -840,293 +1130,66 @@
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
 }
 
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_10SiteA_15SiteA_40Client1_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.SwitchProfileClients("Client1");
+  helper_.CheckAppNotInList("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    TwoClientWebAppsIntegrationTestMacWinLinux,
+    WebAppIntegration_29SiteC_11SiteC_7SiteC_40Client2_45SiteC_46SiteC_11SiteC_7SiteC_37SiteC_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteC");
+  helper_.CheckAppInListTabbed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.SwitchProfileClients("Client2");
+  helper_.CheckAppInListNotLocallyInstalled("SiteC");
+  helper_.InstallLocally("SiteC");
+  helper_.CheckAppInListTabbed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.NavigateBrowser("SiteC");
+  helper_.CheckLaunchIconNotShown();
+}
+
 // TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
 #if BUILDFLAG(IS_MAC)
-#define MAYBE_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
-  DISABLED_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#define MAYBE_WebAppIntegration_30SiteC_12SiteC_7SiteC_40Client2_45SiteC_46SiteC_12SiteC_7SiteC_37SiteC_17_20 \
+  DISABLED_WebAppIntegration_30SiteC_12SiteC_7SiteC_40Client2_45SiteC_46SiteC_12SiteC_7SiteC_37SiteC_17_20
 #else
-#define MAYBE_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA \
-  WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA
+#define MAYBE_WebAppIntegration_30SiteC_12SiteC_7SiteC_40Client2_45SiteC_46SiteC_12SiteC_7SiteC_37SiteC_17_20 \
+  WebAppIntegration_30SiteC_12SiteC_7SiteC_40Client2_45SiteC_46SiteC_12SiteC_7SiteC_37SiteC_17_20
 #endif
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_41_43SiteA_42_45SiteA) {
+    MAYBE_WebAppIntegration_30SiteC_12SiteC_7SiteC_40Client2_45SiteC_46SiteC_12SiteC_7SiteC_37SiteC_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
+  helper_.InstallCreateShortcutWindowed("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.SyncTurnOff();
-  helper_.UninstallFromMenu("SiteA");
-  helper_.SyncTurnOn();
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24 \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24
-#else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24 \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24 \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24
-#else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24 \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24 \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24
-#else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24 \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24 \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24
-#else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24 \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromPlatformShortcut("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22 \
-  DISABLED_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22
-#else
-#define MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22 \
-  WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.LaunchFromPlatformShortcut("SiteA");
-  helper_.CheckTabCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24 \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24
-#else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24 \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromPlatformShortcut("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22 \
-  DISABLED_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22
-#else
-#define MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22 \
-  WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.LaunchFromPlatformShortcut("SiteA");
-  helper_.CheckTabCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24 \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24
-#else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24 \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_46SiteA_12SiteA_1SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromPlatformShortcut("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22 \
-  DISABLED_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22
-#else
-#define MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22 \
-  WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_1SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.LaunchFromPlatformShortcut("SiteA");
-  helper_.CheckTabCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_46SiteA_11SiteA_1SiteA_22 \
-  DISABLED_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_46SiteA_11SiteA_1SiteA_22
-#else
-#define MAYBE_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_46SiteA_11SiteA_1SiteA_22 \
-  WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_46SiteA_11SiteA_1SiteA_22
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_46SiteA_11SiteA_1SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.InstallLocally("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.LaunchFromPlatformShortcut("SiteA");
-  helper_.CheckTabCreated();
-}
-
-// TODO(crbug.com/1301414): Mac shims failing to launch on Mac debug and ASAN.
-#if BUILDFLAG(IS_MAC) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
-#define MAYBE_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_1SiteA_22 \
-  DISABLED_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_1SiteA_22
-#else
-#define MAYBE_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_1SiteA_22 \
-  WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_1SiteA_22
-#endif
-IN_PROC_BROWSER_TEST_F(
-    TwoClientWebAppsIntegrationTestMacWinLinux,
-    MAYBE_WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_1SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SwitchProfileClients("Client2");
-  helper_.CheckAppInListNotLocallyInstalled("SiteA");
-  helper_.LaunchFromPlatformShortcut("SiteA");
-  helper_.CheckTabCreated();
+  helper_.CheckAppInListNotLocallyInstalled("SiteC");
+  helper_.InstallLocally("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.NavigateBrowser("SiteC");
+  helper_.CheckInstallIconNotShown();
+  helper_.CheckLaunchIconShown();
 }
 
 }  // namespace
diff --git a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_win.cc b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_win.cc
index 59ce1280..172e8db 100644
--- a/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_win.cc
+++ b/chrome/browser/sync/test/integration/two_client_web_apps_integration_test_win.cc
@@ -17,13 +17,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestWin,
-    WebAppIntegration_30SiteA_24_12SiteA_40Client2_45SiteA_41_87SiteA_42_45SiteA) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_87SiteA_42_45SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.SyncTurnOff();
@@ -34,13 +35,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestWin,
-    WebAppIntegration_31SiteA_24_12SiteA_40Client2_45SiteA_41_87SiteA_42_45SiteA) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_87SiteA_42_45SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.SyncTurnOff();
@@ -51,13 +53,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestWin,
-    WebAppIntegration_47SiteA_24_12SiteA_40Client2_45SiteA_41_87SiteA_42_45SiteA) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_40Client2_45SiteA_41_87SiteA_42_45SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.SyncTurnOff();
@@ -68,12 +71,13 @@
 
 IN_PROC_BROWSER_TEST_F(
     TwoClientWebAppsIntegrationTestWin,
-    WebAppIntegration_29SiteA_11SiteA_40Client2_45SiteA_41_87SiteA_42_45SiteA) {
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_40Client2_45SiteA_41_87SiteA_42_45SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutTabbed("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SwitchProfileClients("Client2");
   helper_.CheckAppInListNotLocallyInstalled("SiteA");
   helper_.SyncTurnOff();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 589cd002..e17aaa6 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1848,7 +1848,7 @@
   }
 
   if (enable_supervised_users && enable_extensions) {
-    assert(is_chromeos_ash || is_chromeos_lacros)
+    assert(is_chromeos)
     sources += [
       "supervised_user/parent_permission_dialog.h",
       "views/supervised_user/extension_install_blocked_by_parent_dialog_view.cc",
@@ -3257,7 +3257,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     deps += [ "//chrome/browser/ui/webui/settings/chromeos/constants:mojom" ]
   }
 
@@ -5138,7 +5138,7 @@
       "//ui/wm",
     ]
 
-    if (!is_chromeos_ash && !is_chromeos_lacros) {
+    if (!is_chromeos) {
       sources +=
           [ "views/frame/browser_non_client_frame_view_factory_views.cc" ]
     }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
index 433b7ad..1c57dc9 100644
--- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
+++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/voice/VoiceRecognitionHandler.java
@@ -1019,6 +1019,10 @@
         if (windowAndroid.getActivity().get() == null) return false;
         if (!VoiceRecognitionUtil.isVoiceSearchPermittedByPolicy(false)) return false;
 
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.LOCATION_BAR_MODEL_OPTIMIZATIONS)) {
+            return VoiceRecognitionUtil.isVoiceSearchEnabled(windowAndroid);
+        }
+
         if (mIsVoiceSearchEnabledCached == null) {
             mIsVoiceSearchEnabledCached = VoiceRecognitionUtil.isVoiceSearchEnabled(windowAndroid);
 
diff --git a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
index 2f89d41..ce0e5089 100644
--- a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
+++ b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/platform_util.h"
+#include "chrome/browser/policy/system_features_disable_list_policy_handler.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/capture_mode/recording_overlay_view_impl.h"
 #include "chrome/browser/ui/ash/screenshot_area.h"
@@ -255,6 +256,12 @@
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
+bool ChromeCaptureModeDelegate::IsCameraDisabledByPolicy() const {
+  return policy::SystemFeaturesDisableListPolicyHandler::
+      IsSystemFeatureDisabled(policy::SystemFeature::kCamera,
+                              g_browser_process->local_state());
+}
+
 void ChromeCaptureModeDelegate::OnGetDriveQuotaUsage(
     ash::OnGotDriveFsFreeSpace callback,
     drive::FileError error,
diff --git a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h
index 2c9ea2e..ebe14449 100644
--- a/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h
+++ b/chrome/browser/ui/ash/capture_mode/chrome_capture_mode_delegate.h
@@ -71,6 +71,7 @@
       mojo::PendingReceiver<video_capture::mojom::VideoSourceProvider> receiver)
       override;
   void GetDriveFsFreeSpaceBytes(ash::OnGotDriveFsFreeSpace callback) override;
+  bool IsCameraDisabledByPolicy() const override;
 
  private:
   // Called back by the Drive integration service when the quota usage is
diff --git a/chrome/browser/ui/ash/desks_templates/desks_templates_client.cc b/chrome/browser/ui/ash/desks_templates/desks_templates_client.cc
index 9518a5c..781096ae 100644
--- a/chrome/browser/ui/ash/desks_templates/desks_templates_client.cc
+++ b/chrome/browser/ui/ash/desks_templates/desks_templates_client.cc
@@ -9,18 +9,16 @@
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/desk_template.h"
 #include "ash/public/cpp/session/session_controller.h"
-#include "ash/public/cpp/session/session_observer.h"
 #include "ash/wm/desks/desks_controller.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
-#include "base/guid.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/scoped_observation.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sync/desk_sync_service_factory.h"
 #include "chrome/browser/ui/ash/desks_templates/desks_templates_app_launch_handler.h"
@@ -29,7 +27,6 @@
 #include "components/app_restore/window_properties.h"
 #include "components/desks_storage/core/desk_sync_service.h"
 #include "components/desks_storage/core/local_desk_data_manager.h"
-#include "components/sync/model/model_type_store.h"
 #include "ui/views/widget/widget.h"
 
 namespace {
@@ -39,20 +36,7 @@
 // Used to generate unique IDs for desk template launches.
 int32_t g_launch_id = 0;
 
-// TODO(https://crbug.com/1284774): Remove metrics from this file.
-// Histogram names.
-constexpr char kWindowCountHistogramName[] = "Ash.DeskTemplate.WindowCount";
-constexpr char kTabCountHistogramName[] = "Ash.DeskTemplate.TabCount";
-constexpr char kWindowAndTabCountHistogramName[] =
-    "Ash.DeskTemplate.WindowAndTabCount";
-constexpr char kLaunchFromTemplateHistogramName[] =
-    "Ash.DeskTemplate.LaunchFromTemplate";
-constexpr char kUserTemplateCountHistogramName[] =
-    "Ash.DeskTemplate.UserTemplateCount";
-constexpr char kTimeToLoadTemplateHistogramName[] =
-    "Ash.DeskTemplate.TimeToLoadTemplate";
-
-// Error strings
+// Error strings for the private API.
 constexpr char kMaximumDesksOpenedError[] =
     "The maximum number of desks is already open.";
 constexpr char kMissingTemplateDataError[] =
@@ -63,9 +47,15 @@
     "Either the profile is not valid or there is not an active proflile.";
 constexpr char kNoSavedTemplatesError[] = "You can create up to 6 templates.";
 
-// Timeout time used in LaunchPerformanceTracker
+// Timeout time used in LaunchPerformanceTracker.
 constexpr base::TimeDelta kLaunchPerformanceTimeout = base::Minutes(3);
 
+// Histogram name to track estimated time it takes to load a template. Used by
+// LaunchPerformanceTracker. Note that this is in a different spot than the
+// other metrics because the class that uses this is owned by `this`.
+constexpr char kTimeToLoadTemplateHistogramName[] =
+    "Ash.DeskTemplate.TimeToLoadTemplate";
+
 // Launch data is cleared after this time.
 constexpr base::TimeDelta kClearLaunchDataDuration = base::Seconds(20);
 
@@ -409,52 +399,6 @@
     id_to_tracker.second->OnMovedSingleInstanceApp(window_id);
 }
 
-void DesksTemplatesClient::RecordWindowAndTabCountHistogram(
-    ash::DeskTemplate* desk_template) {
-  const app_restore::RestoreData* restore_data =
-      desk_template->desk_restore_data();
-  DCHECK(restore_data);
-
-  int window_count = 0;
-  int tab_count = 0;
-  int total_count = 0;
-
-  const auto& launch_list = restore_data->app_id_to_launch_list();
-  for (const auto& iter : launch_list) {
-    // Since apps aren't guaranteed to have the url field set up correctly, this
-    // is necessary to ensure things are not double-counted.
-    if (iter.first != app_constants::kChromeAppId) {
-      ++window_count;
-      ++total_count;
-      continue;
-    }
-
-    for (const auto& window_iter : iter.second) {
-      absl::optional<std::vector<GURL>> urls = window_iter.second->urls;
-      if (!urls || urls->empty())
-        continue;
-
-      ++window_count;
-      tab_count += urls->size();
-      total_count += urls->size();
-    }
-  }
-
-  base::UmaHistogramCounts100(kWindowCountHistogramName, window_count);
-  base::UmaHistogramCounts100(kTabCountHistogramName, tab_count);
-  base::UmaHistogramCounts100(kWindowAndTabCountHistogramName, total_count);
-}
-
-void DesksTemplatesClient::RecordLaunchFromTemplateHistogram() {
-  base::UmaHistogramBoolean(kLaunchFromTemplateHistogramName, true);
-}
-
-void DesksTemplatesClient::RecordTemplateCountHistogram() {
-  UMA_HISTOGRAM_EXACT_LINEAR(kUserTemplateCountHistogramName,
-                             GetDeskModel()->GetEntryCount(),
-                             GetDeskModel()->GetMaxEntryCount());
-}
-
 void DesksTemplatesClient::OnGetTemplateForDeskLaunch(
     LaunchDeskTemplateCallback callback,
     base::Time time_launch_started,
@@ -465,8 +409,6 @@
     return;
   }
 
-  RecordLaunchFromTemplateHistogram();
-
   // Launch the windows as specified in the template to a new desk.
   const auto template_name = entry->template_name();
   const bool activate_desk = entry->type() == ash::DeskTemplateType::kTemplate;
@@ -513,8 +455,6 @@
                           desks_storage::DeskModel::AddOrUpdateEntryStatus::kOk
                       ? kNoSavedTemplatesError
                       : ""));
-
-  RecordTemplateCountHistogram();
 }
 
 void DesksTemplatesClient::OnDeleteDeskTemplate(
@@ -524,7 +464,6 @@
       std::string(status != desks_storage::DeskModel::DeleteEntryStatus::kOk
                       ? kNoCurrentUserError
                       : ""));
-  RecordTemplateCountHistogram();
 }
 
 void DesksTemplatesClient::OnUpdateDeskTemplate(
@@ -570,7 +509,6 @@
   if (!desk_template)
     return;
 
-  RecordWindowAndTabCountHistogram(desk_template.get());
   auto desk_template_clone = desk_template->Clone();
   GetDeskModel()->AddOrUpdateEntry(
       std::move(desk_template_clone),
diff --git a/chrome/browser/ui/ash/desks_templates/desks_templates_client.h b/chrome/browser/ui/ash/desks_templates/desks_templates_client.h
index ee9fadb..6297154 100644
--- a/chrome/browser/ui/ash/desks_templates/desks_templates_client.h
+++ b/chrome/browser/ui/ash/desks_templates/desks_templates_client.h
@@ -5,20 +5,19 @@
 #ifndef CHROME_BROWSER_UI_ASH_DESKS_TEMPLATES_DESKS_TEMPLATES_CLIENT_H_
 #define CHROME_BROWSER_UI_ASH_DESKS_TEMPLATES_DESKS_TEMPLATES_CLIENT_H_
 
+#include <map>
 #include <memory>
 
-#include "ash/public/cpp/desk_template.h"
 #include "ash/public/cpp/session/session_observer.h"
 #include "base/callback.h"
 #include "base/containers/flat_map.h"
+#include "base/guid.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/ash/desks_templates/desks_templates_app_launch_handler.h"
-#include "components/app_restore/app_restore_info.h"
 #include "components/desks_storage/core/desk_model.h"
 
 class DesksTemplatesAppLaunchHandler;
+class Profile;
 
 namespace ash {
 class Desk;
@@ -139,10 +138,6 @@
   friend class DesksTemplatesClientTest;
   friend class ScopedDesksTemplatesAppLaunchHandlerSetter;
 
-  void RecordWindowAndTabCountHistogram(ash::DeskTemplate* desk_template);
-  void RecordLaunchFromTemplateHistogram();
-  void RecordTemplateCountHistogram();
-
   // Launches DeskTemplate after retrieval from storage.
   void OnGetTemplateForDeskLaunch(
       LaunchDeskTemplateCallback callback,
diff --git a/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc b/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc
index 8d2a252..ab5364a 100644
--- a/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc
+++ b/chrome/browser/ui/ash/desks_templates/desks_templates_client_browsertest.cc
@@ -869,88 +869,6 @@
   EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
 }
 
-// Tests that the windows and tabs count histogram is recorded properly.
-IN_PROC_BROWSER_TEST_F(DesksTemplatesClientTest,
-                       DeskTemplateWindowAndTabCountHistogram) {
-  ASSERT_TRUE(DesksTemplatesClient::Get());
-
-  base::HistogramTester histogram_tester;
-
-  Profile* profile = browser()->profile();
-
-  // Create the settings app, which is a system web app.
-  CreateSettingsSystemWebApp(profile);
-
-  CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2)});
-  CreateBrowser({GURL(kExampleUrl1), GURL(kExampleUrl2), GURL(kExampleUrl3)});
-
-  std::unique_ptr<ash::DeskTemplate> desk_template =
-      CaptureActiveDeskAndSaveTemplate();
-  ASSERT_TRUE(desk_template);
-
-  const app_restore::RestoreData* restore_data =
-      desk_template->desk_restore_data();
-  const auto& app_id_to_launch_list = restore_data->app_id_to_launch_list();
-  EXPECT_EQ(app_id_to_launch_list.size(), 2u);
-
-  constexpr char kWindowCountHistogramName[] = "Ash.DeskTemplate.WindowCount";
-  constexpr char kTabCountHistogramName[] = "Ash.DeskTemplate.TabCount";
-  constexpr char kWindowAndTabCountHistogramName[] =
-      "Ash.DeskTemplate.WindowAndTabCount";
-  // NOTE: there is an existing browser with 1 tab created by BrowserMain().
-  histogram_tester.ExpectBucketCount(kWindowCountHistogramName, 4, 1);
-  histogram_tester.ExpectBucketCount(kTabCountHistogramName, 6, 1);
-  histogram_tester.ExpectBucketCount(kWindowAndTabCountHistogramName, 7, 1);
-}
-
-// Tests that the launch from template histogram is recorded properly.
-IN_PROC_BROWSER_TEST_F(DesksTemplatesClientTest,
-                       DeskTemplateLaunchFromTemplateHistogram) {
-  ASSERT_TRUE(DesksTemplatesClient::Get());
-
-  base::HistogramTester histogram_tester;
-
-  // Create a new browser.
-  CreateBrowser({});
-
-  // Save the template.
-  std::unique_ptr<ash::DeskTemplate> desk_template =
-      CaptureActiveDeskAndSaveTemplate();
-  ASSERT_TRUE(desk_template);
-
-  const int launches = 5;
-  for (int i = 0; i < launches; i++) {
-    auto launch_template = desk_template->Clone();
-    SetAndLaunchTemplate(std::move(launch_template));
-  }
-
-  constexpr char kLaunchFromTemplateHistogramName[] =
-      "Ash.DeskTemplate.LaunchFromTemplate";
-  histogram_tester.ExpectTotalCount(kLaunchFromTemplateHistogramName, launches);
-}
-
-// Tests that the template count histogram is recorded properly.
-IN_PROC_BROWSER_TEST_F(DesksTemplatesClientTest,
-                       DeskTemplateUserTemplateCountHistogram) {
-  ASSERT_TRUE(DesksTemplatesClient::Get());
-
-  base::HistogramTester histogram_tester;
-
-  // Verify that all template saves and deletes are captured by the histogram.
-  CaptureActiveDeskAndSaveTemplate();
-  CaptureActiveDeskAndSaveTemplate();
-  std::unique_ptr<ash::DeskTemplate> desk_template =
-      CaptureActiveDeskAndSaveTemplate();
-  DeleteDeskTemplate(desk_template->uuid());
-  CaptureActiveDeskAndSaveTemplate();
-
-  constexpr char kUserTemplateCountHistogramName[] =
-      "Ash.DeskTemplate.UserTemplateCount";
-  histogram_tester.ExpectBucketCount(kUserTemplateCountHistogramName, 1, 1);
-  histogram_tester.ExpectBucketCount(kUserTemplateCountHistogramName, 2, 2);
-  histogram_tester.ExpectBucketCount(kUserTemplateCountHistogramName, 3, 2);
-}
-
 // Tests that browser windows created from a template have the correct bounds
 // and window state.
 IN_PROC_BROWSER_TEST_F(DesksTemplatesClientTest, BrowserWindowRestorationTest) {
@@ -1380,6 +1298,8 @@
 
   aura::Window* settings_window = FindBrowserWindow(kSettingsWindowId);
   aura::Window* help_window = FindBrowserWindow(kHelpWindowId);
+  aura::Window* browser_window = browser()->window()->GetNativeWindow();
+  aura::Window* parent = settings_window->parent();
   ASSERT_TRUE(settings_window);
   ASSERT_TRUE(help_window);
   EXPECT_EQ(3u, BrowserList::GetInstance()->size());
@@ -1388,10 +1308,13 @@
   const gfx::Rect settings_bounds(100, 100, 600, 400);
   settings_window->SetBounds(settings_bounds);
   ash::WindowState::Get(help_window)->Maximize();
-  // Focus the browser so that the settings window is stacked at the bottom.
-  browser()->window()->GetNativeWindow()->Focus();
-  ASSERT_THAT(settings_window->parent()->children(),
-              ElementsAre(settings_window, help_window, _));
+
+  // Focus the settings window and then the help window. The MRU order should be
+  // [`browser_window`, `settings_window`, `help_window`].
+  settings_window->Focus();
+  help_window->Focus();
+  ASSERT_THAT(parent->children(),
+              ElementsAre(browser_window, settings_window, help_window));
 
   // Enter overview and save the current desk as a template.
   ash::ToggleOverview();
@@ -1400,16 +1323,20 @@
   ClickSaveDeskAsTemplateButton();
 
   // Exit overview and move the settings window to a new place and stack it on
-  // top so that we can later verify that it has been placed and stacked
-  // correctly.
+  // top so that we can later verify that it has been placed.
   ash::ToggleOverview();
   ash::WaitForOverviewExitAnimation();
   settings_window->SetBounds(gfx::Rect(150, 150, 650, 500));
-  settings_window->Focus();
 
   // Restore the help window so we can later verify that it remaximizes.
   ash::WindowState::Get(help_window)->Restore();
 
+  // Focus the settings window so it is now on top. We will verify that it gets
+  // restacked later.
+  settings_window->Focus();
+  ASSERT_THAT(parent->children(),
+              ElementsAre(browser_window, help_window, settings_window));
+
   // Enter overview, head over to the desks templates grid and launch the
   // template.
   ash::ToggleOverview();
@@ -1421,6 +1348,19 @@
   // Wait for the tabs to load.
   content::RunAllTasksUntilIdle();
 
+  EXPECT_EQ(4u, BrowserList::GetInstance()->size());
+  aura::Window* new_browser_window =
+      BrowserList::GetInstance()->get(3)->window()->GetNativeWindow();
+
+  // Tests that the stacking is correct while in overview. The parent has other
+  // children for overview mode windows, but the first three elements should
+  // be [`new_browser_window`, `settings_window`, `help_window`].
+  parent = settings_window->parent();
+  ASSERT_GE(parent->children().size(), 3u);
+  EXPECT_EQ(new_browser_window, parent->children()[0]);
+  EXPECT_EQ(settings_window, parent->children()[1]);
+  EXPECT_EQ(help_window, parent->children()[2]);
+
   // Exit overview.
   ash::ToggleOverview();
   ash::WaitForOverviewExitAnimation();
@@ -1428,18 +1368,20 @@
   ash::DesksController* desks_controller = ash::DesksController::Get();
   ASSERT_EQ(1, desks_controller->GetActiveDeskIndex());
 
-  // We launch a new browser window, but not a new settings or help app. Verify
+  // Verify
   // that the settings window has been moved to the right place and stacked at
   // the bottom. Verify that the help window is maximized.
-  EXPECT_EQ(4u, BrowserList::GetInstance()->size());
+  EXPECT_TRUE(desks_controller->BelongsToActiveDesk(new_browser_window));
   EXPECT_TRUE(desks_controller->BelongsToActiveDesk(settings_window));
   EXPECT_TRUE(desks_controller->BelongsToActiveDesk(help_window));
   EXPECT_EQ(settings_bounds, settings_window->bounds());
   EXPECT_TRUE(ash::WindowState::Get(help_window)->IsMaximized());
 
-  // TODO(crbug.com/1281393): Verify that the element order is correct.
+  // Tests that the stacking is correct after exiting overview.
+  EXPECT_THAT(parent->children(),
+              ElementsAre(new_browser_window, settings_window, help_window));
 
-  // Tests that there is no clipping on the either window.
+  // Tests that there is no clipping on either window.
   EXPECT_EQ(gfx::Rect(), settings_window->layer()->clip_rect());
   EXPECT_EQ(gfx::Rect(), help_window->layer()->clip_rect());
 }
diff --git a/chrome/browser/ui/media_router/cast_modes_with_media_sources.h b/chrome/browser/ui/media_router/cast_modes_with_media_sources.h
index 26650c77..d490f8a9 100644
--- a/chrome/browser/ui/media_router/cast_modes_with_media_sources.h
+++ b/chrome/browser/ui/media_router/cast_modes_with_media_sources.h
@@ -50,8 +50,7 @@
 
  private:
   MediaSink sink_;
-  std::map<MediaCastMode, std::unordered_set<MediaSource, MediaSource::Hash>>
-      cast_modes_;
+  std::map<MediaCastMode, std::set<MediaSource, MediaSource::Cmp>> cast_modes_;
 };
 
 }  // namespace media_router
diff --git a/chrome/browser/ui/media_router/query_result_manager.cc b/chrome/browser/ui/media_router/query_result_manager.cc
index a6905d3..71c4ac38 100644
--- a/chrome/browser/ui/media_router/query_result_manager.cc
+++ b/chrome/browser/ui/media_router/query_result_manager.cc
@@ -83,7 +83,7 @@
   DCHECK(router_);
   auto observer = std::make_unique<AnyMediaSinksObserver>(router_, this);
   observer->Init();
-  sinks_observers_[MediaSource()] = std::move(observer);
+  sinks_observers_[absl::nullopt] = std::move(observer);
 }
 
 QueryResultManager::~QueryResultManager() {
diff --git a/chrome/browser/ui/media_router/query_result_manager.h b/chrome/browser/ui/media_router/query_result_manager.h
index fc49354..af4eba97 100644
--- a/chrome/browser/ui/media_router/query_result_manager.h
+++ b/chrome/browser/ui/media_router/query_result_manager.h
@@ -167,9 +167,12 @@
   // MediaSinksObservers that listen for compatible MediaSink updates.
   // Each observer is associated with a MediaSource. Results received by
   // observers are propagated back to this class.
-  std::unordered_map<MediaSource,
-                     std::unique_ptr<MediaSinksObserver>,
-                     MediaSource::Hash>
+  // A nullopt for the MediaSource indicates that the observer is
+  // listening for all MediaSink updates regardless of the MediaSource
+  // associated with them.
+  std::map<absl::optional<MediaSource>,
+           std::unique_ptr<MediaSinksObserver>,
+           MediaSource::Cmp>
       sinks_observers_;
 
   // Holds registrations of MediaSources for cast modes.
diff --git a/chrome/browser/ui/media_router/query_result_manager_unittest.cc b/chrome/browser/ui/media_router/query_result_manager_unittest.cc
index 28f9ad19..0264e5c0 100644
--- a/chrome/browser/ui/media_router/query_result_manager_unittest.cc
+++ b/chrome/browser/ui/media_router/query_result_manager_unittest.cc
@@ -179,7 +179,8 @@
   std::vector<MediaSinkWithCastModes> expected_sinks = {
       {sink1, {}}, {sink2, {}}, {sink3, {}}, {sink4, {}}};
   const auto& sinks_observers = query_result_manager_.sinks_observers_;
-  auto* any_sink_observer = sinks_observers.find(MediaSource())->second.get();
+  auto* any_sink_observer =
+      sinks_observers.find(absl::optional<MediaSource>())->second.get();
   EXPECT_CALL(mock_observer_,
               OnResultsUpdated(VectorSetEquals(expected_sinks)));
   any_sink_observer->OnSinksUpdated(sinks_query_result, {});
diff --git a/chrome/browser/ui/user_education/help_bubble_factory_registry.cc b/chrome/browser/ui/user_education/help_bubble_factory_registry.cc
index 7e69879..cb2c52c 100644
--- a/chrome/browser/ui/user_education/help_bubble_factory_registry.cc
+++ b/chrome/browser/ui/user_education/help_bubble_factory_registry.cc
@@ -71,6 +71,15 @@
   return toggle_focus_callbacks_.Add(std::move(callback));
 }
 
+HelpBubble* HelpBubbleFactoryRegistry::GetHelpBubble(
+    ui::ElementContext context) {
+  for (const auto& pr : help_bubbles_) {
+    if (pr.first->GetContext() == context)
+      return pr.first;
+  }
+  return nullptr;
+}
+
 void HelpBubbleFactoryRegistry::OnHelpBubbleClosed(HelpBubble* bubble) {
   const auto result = help_bubbles_.erase(bubble);
   DCHECK(result);
diff --git a/chrome/browser/ui/user_education/help_bubble_factory_registry.h b/chrome/browser/ui/user_education/help_bubble_factory_registry.h
index fadeba8..e8330d4 100644
--- a/chrome/browser/ui/user_education/help_bubble_factory_registry.h
+++ b/chrome/browser/ui/user_education/help_bubble_factory_registry.h
@@ -53,6 +53,10 @@
   base::CallbackListSubscription AddToggleFocusCallback(
       ToggleFocusCallback callback);
 
+  // Gets the first visible help bubble in the given context, or null if none
+  // exists.
+  HelpBubble* GetHelpBubble(ui::ElementContext context);
+
   // Adds a bubble factory of type `T` to the list of bubble factories, if it
   // is not already present.
   template <class T, typename... Args>
diff --git a/chrome/browser/ui/user_education/interaction_sequence_browser_util_unittest.cc b/chrome/browser/ui/user_education/interaction_sequence_browser_util_unittest.cc
new file mode 100644
index 0000000..b17efea3
--- /dev/null
+++ b/chrome/browser/ui/user_education/interaction_sequence_browser_util_unittest.cc
@@ -0,0 +1,23 @@
+// 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/user_education/interaction_sequence_browser_util.h"
+
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(InteractionSequenceBrowserUtilTest, IsTruthy) {
+  EXPECT_FALSE(InteractionSequenceBrowserUtil::IsTruthy(base::Value()));
+  EXPECT_FALSE(InteractionSequenceBrowserUtil::IsTruthy(base::Value(0)));
+  EXPECT_TRUE(InteractionSequenceBrowserUtil::IsTruthy(base::Value(3)));
+  EXPECT_FALSE(InteractionSequenceBrowserUtil::IsTruthy(base::Value(0.0)));
+  EXPECT_TRUE(InteractionSequenceBrowserUtil::IsTruthy(base::Value(3.0)));
+  EXPECT_FALSE(InteractionSequenceBrowserUtil::IsTruthy(base::Value("")));
+  EXPECT_TRUE(InteractionSequenceBrowserUtil::IsTruthy(base::Value("abc")));
+  // Even empty lists and objects/dictionaries are truthy.
+  EXPECT_TRUE(InteractionSequenceBrowserUtil::IsTruthy(
+      base::Value(base::Value::List())));
+  EXPECT_TRUE(InteractionSequenceBrowserUtil::IsTruthy(
+      base::Value(base::Value::Dict())));
+}
diff --git a/chrome/browser/ui/views/tabs/tab_container.cc b/chrome/browser/ui/views/tabs/tab_container.cc
index e303e509..01e9373 100644
--- a/chrome/browser/ui/views/tabs/tab_container.cc
+++ b/chrome/browser/ui/views/tabs/tab_container.cc
@@ -373,7 +373,8 @@
   return tab_ptr;
 }
 
-void TabContainer::MoveTab(Tab* tab, int from_model_index, int to_model_index) {
+void TabContainer::MoveTab(int from_model_index, int to_model_index) {
+  Tab* tab = GetTabAtModelIndex(from_model_index);
   ReorderChildView(tab, GetViewInsertionIndex(tab->group(), from_model_index,
                                               to_model_index));
   tabs_view_model_.Move(from_model_index, to_model_index);
diff --git a/chrome/browser/ui/views/tabs/tab_container.h b/chrome/browser/ui/views/tabs/tab_container.h
index c2b09a1..add426b 100644
--- a/chrome/browser/ui/views/tabs/tab_container.h
+++ b/chrome/browser/ui/views/tabs/tab_container.h
@@ -49,7 +49,7 @@
       base::RepeatingCallback<int()> available_width_callback);
 
   Tab* AddTab(std::unique_ptr<Tab> tab, int model_index, TabPinned pinned);
-  void MoveTab(Tab* tab, int from_model_index, int to_model_index);
+  void MoveTab(int from_model_index, int to_model_index);
   void RemoveTab(int index, bool was_active);
   void SetTabPinned(int model_index, TabPinned pinned);
 
diff --git a/chrome/browser/ui/views/tabs/tab_container_unittest.cc b/chrome/browser/ui/views/tabs/tab_container_unittest.cc
index 598415a..c051975 100644
--- a/chrome/browser/ui/views/tabs/tab_container_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_container_unittest.cc
@@ -55,28 +55,68 @@
         TabPinned::kUnpinned);
     tab_strip_controller_->AddTab(model_index, active == TabActive::kActive);
 
-    if (group) {
-      tab->set_group(group);
-      tab_strip_controller_->AddTabToGroup(model_index, group.value());
-
-      auto& group_views = tab_container_->group_views();
-      if (group_views.find(group.value()) == group_views.end()) {
-        tab_container_->OnGroupCreated(group.value());
-      } else {
-        tab_container_->OnGroupMoved(group.value());
-      }
-    }
+    if (group)
+      AddTabToGroup(model_index, group.value());
 
     return tab;
   }
 
+  void MoveTab(int from_model_index, int to_model_index) {
+    tab_strip_controller_->MoveTab(from_model_index, to_model_index);
+    tab_container_->MoveTab(from_model_index, to_model_index);
+  }
+
+  void AddTabToGroup(int model_index, tab_groups::TabGroupId group) {
+    tab_container_->GetTabAtModelIndex(model_index)->set_group(group);
+    tab_strip_controller_->AddTabToGroup(model_index, group);
+
+    auto& group_views = tab_container_->group_views();
+    if (group_views.find(group) == group_views.end())
+      tab_container_->OnGroupCreated(group);
+
+    tab_container_->OnGroupMoved(group);
+  }
+
+  void RemoveTabFromGroup(int model_index) {
+    Tab* tab = tab_container_->GetTabAtModelIndex(model_index);
+    absl::optional<tab_groups::TabGroupId> old_group = tab->group();
+    DCHECK(old_group);
+
+    tab->set_group(absl::nullopt);
+    tab_strip_controller_->RemoveTabFromGroup(model_index);
+
+    bool group_is_empty = true;
+    for (Tab* tab : tab_container_->layout_helper()->GetTabs()) {
+      if (tab->group() == old_group)
+        group_is_empty = false;
+    }
+
+    if (group_is_empty) {
+      tab_container_->OnGroupClosed(old_group.value());
+    } else {
+      tab_container_->OnGroupMoved(old_group.value());
+    }
+  }
+
+  void MoveTabIntoGroup(int index,
+                        absl::optional<tab_groups::TabGroupId> new_group) {
+    absl::optional<tab_groups::TabGroupId> old_group =
+        tab_container_->GetTabAtModelIndex(index)->group();
+
+    if (old_group.has_value())
+      RemoveTabFromGroup(index);
+    if (new_group.has_value())
+      AddTabToGroup(index, new_group.value());
+  }
+
   // Returns all TabSlotViews in the order that they have as ViewChildren of
   // TabContainer. This should match the actual order that they appear in
   // visually.
   views::View::Views GetTabSlotViewsInFocusOrder() {
     views::View::Views all_children = tab_container_->children();
 
-    const int num_tab_slot_views = tab_container_->GetTabCount();
+    const int num_tab_slot_views =
+        tab_container_->GetTabCount() + tab_container_->group_views().size();
 
     return views::View::Views(all_children.begin(),
                               all_children.begin() + num_tab_slot_views);
@@ -87,9 +127,20 @@
   views::View::Views GetTabSlotViewsInVisualOrder() {
     views::View::Views ordered_views;
 
+    absl::optional<tab_groups::TabGroupId> prev_group = absl::nullopt;
+
     for (int i = 0; i < tab_container_->GetTabCount(); ++i) {
       Tab* tab = tab_container_->GetTabAtModelIndex(i);
 
+      // If the current Tab is the first one in a group, first add the
+      // TabGroupHeader to the list of views.
+      absl::optional<tab_groups::TabGroupId> curr_group = tab->group();
+      if (curr_group.has_value() && curr_group != prev_group) {
+        ordered_views.push_back(
+            tab_container_->group_views()[curr_group.value()]->header());
+      }
+      prev_group = curr_group;
+
       ordered_views.push_back(tab);
     }
 
@@ -110,13 +161,45 @@
   AddTab(2);
   EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
 
-  tab_container_->MoveTab(tab_container_->GetTabAtModelIndex(0), 0, 1);
+  MoveTab(0, 1);
   EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
-  tab_container_->MoveTab(tab_container_->GetTabAtModelIndex(1), 1, 2);
+  MoveTab(1, 2);
   EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
-  tab_container_->MoveTab(tab_container_->GetTabAtModelIndex(1), 1, 0);
+  MoveTab(1, 0);
   EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
-  tab_container_->MoveTab(tab_container_->GetTabAtModelIndex(0), 0, 2);
+  MoveTab(0, 2);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+}
+
+// Verifies child view order matches slot order with group headers.
+TEST_F(TabContainerTest, TabViewOrderWithGroups) {
+  AddTab(0);
+  AddTab(1);
+  AddTab(2);
+  AddTab(3);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+
+  tab_groups::TabGroupId group1 = tab_groups::TabGroupId::GenerateNew();
+  tab_groups::TabGroupId group2 = tab_groups::TabGroupId::GenerateNew();
+
+  // Add multiple tabs to a group and verify view order.
+  AddTabToGroup(0, group1);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+  AddTabToGroup(1, group1);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+
+  // Move tabs within a group and verify view order.
+  MoveTab(1, 0);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+
+  // Add a single tab to a group and verify view order.
+  AddTabToGroup(2, group2);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+
+  // Move and add tabs near a group and verify view order.
+  AddTab(2);
+  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
+  MoveTab(4, 3);
   EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc b/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
index 930621a..b2dbcac 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_controller.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/metrics/tab_count_metrics.h"
 #include "chrome/browser/ui/tabs/tab_style.h"
 #include "chrome/browser/ui/ui_features.h"
+#include "chrome/browser/ui/user_education/help_bubble_factory_registry.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
@@ -22,6 +23,9 @@
 #include "chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h"
 #include "chrome/browser/ui/views/tabs/tab_hover_card_thumbnail_observer.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
+#include "chrome/browser/ui/views/user_education/help_bubble_factory_views.h"
+#include "chrome/browser/ui/views/user_education/help_bubble_view.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_popup_view.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -72,7 +76,7 @@
   // by other secondary UI Widgets (such as the omnibox Widget, see
   // crbug.com/1226536).
   widget->StackAtTop();
-#else   // !deifned(OS_LINUX)
+#else  // !BUILDFLAG(IS_LINUX)
   // Hover card should always render above omnibox (see crbug.com/1272106).
   if (!browser || !widget)
     return;
@@ -84,10 +88,24 @@
                                ->omnibox_view()
                                ->model()
                                ->get_popup_view();
-  if (!popup_view || !popup_view->IsOpen())
+  if (popup_view && popup_view->IsOpen()) {
+    widget->StackAboveWidget(
+        static_cast<OmniboxPopupContentsView*>(popup_view)->GetWidget());
     return;
-  widget->StackAboveWidget(
-      static_cast<OmniboxPopupContentsView*>(popup_view)->GetWidget());
+  }
+
+  // Hover card should always render above help bubbles (see crbug.com/1309238).
+  if (browser_view->GetFeaturePromoController()) {
+    HelpBubbleFactoryRegistry* const registry =
+        browser_view->GetFeaturePromoController()->bubble_factory_registry();
+    auto* const help_bubble =
+        registry->GetHelpBubble(browser_view->GetElementContext());
+    if (help_bubble && help_bubble->IsA<HelpBubbleViews>()) {
+      widget->StackAboveWidget(
+          help_bubble->AsA<HelpBubbleViews>()->bubble_view()->GetWidget());
+    }
+  }
+
 #endif  // !BUILDFLAG(IS_LINUX)
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 603f9eb..720d31cf 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -883,7 +883,7 @@
   Tab* moving_tab = tab_at(from_model_index);
   moving_tab->SetData(std::move(data));
 
-  tab_container_->MoveTab(moving_tab, from_model_index, to_model_index);
+  tab_container_->MoveTab(from_model_index, to_model_index);
 
   selected_tabs_.Move(from_model_index, to_model_index, /*length=*/1);
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
index 408b972..b0b7aa5 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
@@ -235,42 +235,6 @@
     return result;
   }
 
-  // Returns all TabSlotViews in the order that they have as ViewChildren of
-  // TabStrip. This should match the actual order that they appear in visually.
-  views::View::Views GetTabSlotViewsInFocusOrder() {
-    views::View::Views all_children = GetChildViews();
-
-    const int num_tab_slot_views =
-        tab_strip_->GetTabCount() +
-        tab_strip_->tab_container_->group_views().size();
-
-    return views::View::Views(all_children.begin(),
-                              all_children.begin() + num_tab_slot_views);
-  }
-
-  // Returns all TabSlotViews in the order that they appear visually. This is
-  // the expected order of the ViewChildren of TabStrip.
-  views::View::Views GetTabSlotViewsInVisualOrder() {
-    views::View::Views ordered_views;
-
-    absl::optional<tab_groups::TabGroupId> prev_group = absl::nullopt;
-
-    for (int i = 0; i < tab_strip_->GetTabCount(); ++i) {
-      Tab* tab = tab_strip_->tab_at(i);
-
-      // If the current Tab is the first one in a group, first add the
-      // TabGroupHeader to the list of views.
-      absl::optional<tab_groups::TabGroupId> curr_group = tab->group();
-      if (curr_group.has_value() && curr_group != prev_group)
-        ordered_views.push_back(tab_strip_->group_header(curr_group.value()));
-      prev_group = curr_group;
-
-      ordered_views.push_back(tab);
-    }
-
-    return ordered_views;
-  }
-
   // Owned by TabStrip.
   raw_ptr<FakeBaseTabStripController> controller_ = nullptr;
   raw_ptr<TabStrip> tab_strip_ = nullptr;
@@ -400,40 +364,6 @@
   EXPECT_EQ(0, observer.last_tab_removed());
 }
 
-// Verifies child view order matches slot order with group headers.
-TEST_P(TabStripTest, TabViewOrderWithGroups) {
-  controller_->AddTab(0, false);
-  controller_->AddTab(1, false);
-  controller_->AddTab(2, false);
-  controller_->AddTab(3, false);
-  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
-
-  absl::optional<tab_groups::TabGroupId> group1 =
-      tab_groups::TabGroupId::GenerateNew();
-  absl::optional<tab_groups::TabGroupId> group2 =
-      tab_groups::TabGroupId::GenerateNew();
-
-  // Add multiple tabs to a group and verify view order.
-  controller_->MoveTabIntoGroup(0, group1);
-  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
-  controller_->MoveTabIntoGroup(1, group1);
-  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
-
-  // Move tabs within a group and verify view order.
-  controller_->MoveTab(1, 0);
-  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
-
-  // Add a single tab to a group and verify view order.
-  controller_->MoveTabIntoGroup(2, group2);
-  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
-
-  // Move and add tabs near a group and verify view order.
-  controller_->AddTab(2, false);
-  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
-  controller_->MoveTab(4, 3);
-  EXPECT_EQ(GetTabSlotViewsInFocusOrder(), GetTabSlotViewsInVisualOrder());
-}
-
 // Tests that the tab close buttons of non-active tabs are hidden when
 // the tab sizes are shrunk into small sizes.
 TEST_P(TabStripTest, TabCloseButtonVisibility) {
diff --git a/chrome/browser/ui/views/web_apps/deprecated_apps_dialog_view_browsertest.cc b/chrome/browser/ui/views/web_apps/deprecated_apps_dialog_view_browsertest.cc
index 39b3b7d6..7e90e04 100644
--- a/chrome/browser/ui/views/web_apps/deprecated_apps_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/deprecated_apps_dialog_view_browsertest.cc
@@ -6,11 +6,13 @@
 
 #include <set>
 
+#include "base/feature_list.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/logging_chrome.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -19,6 +21,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/common/extension_id.h"
 #include "extensions/test/test_extension_dir.h"
+#include "ui/views/widget/any_widget_observer.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_observer.h"
 
@@ -78,7 +81,9 @@
 class DeprecatedAppsDialogViewBrowserTest
     : public extensions::ExtensionBrowserTest {
  public:
-  DeprecatedAppsDialogViewBrowserTest() = default;
+  DeprecatedAppsDialogViewBrowserTest() {
+    feature_list_.InitWithFeatures({features::kChromeAppsDeprecation}, {});
+  }
 
   DeprecatedAppsDialogViewBrowserTest(
       const DeprecatedAppsDialogViewBrowserTest&) = delete;
@@ -136,6 +141,7 @@
  protected:
   std::set<extensions::ExtensionId> deprecated_app_ids_for_testing_;
   base::WeakPtr<DeprecatedAppsDialogView> test_dialog_view_;
+  base::test::ScopedFeatureList feature_list_;
 };
 
 IN_PROC_BROWSER_TEST_F(DeprecatedAppsDialogViewBrowserTest,
@@ -219,3 +225,17 @@
       ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIAppsURL)));
   ASSERT_FALSE(IsDialogShown());
 }
+
+IN_PROC_BROWSER_TEST_F(DeprecatedAppsDialogViewBrowserTest,
+                       DeprecatedAppsDialogShownFromLinkClick) {
+  auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+  InstallExtensionForTesting(mock_app_manifest1, mock_url1);
+  ASSERT_TRUE(
+      ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIAppsURL)));
+  auto waiter = views::NamedWidgetShownWaiter(
+      views::test::AnyWidgetTestPasskey{}, "DeprecatedAppsDialogView");
+  web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
+      u"document.getElementById('deprecated-apps-link').click()",
+      base::NullCallback());
+  EXPECT_NE(waiter.WaitIfNeededAndGet(), nullptr);
+}
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
index 191dc290..ea72d86 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest.cc
@@ -75,14 +75,48 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_32SiteA_12SiteA_37SiteA_20) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_39SiteB_16_27_14) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.NavigatePwaSiteATo("SiteB");
+  helper_.CheckCustomToolbar();
+  helper_.CloseCustomToolbar();
+  helper_.CheckAppNavigationIsStartUrl();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_39SiteB_16_71_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.NavigatePwaSiteATo("SiteB");
+  helper_.CheckCustomToolbar();
+  helper_.OpenInChrome();
+  helper_.CheckTabCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_37SiteA_20) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckLaunchIconShown();
@@ -90,14 +124,50 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_32SiteA_12SiteA_34SiteA_24) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_69SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_34SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowCreated();
@@ -105,42 +175,49 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_32SiteA_12SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_33SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_33SiteA_7SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_48SiteA_12SiteA_37SiteA_20) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_37SiteA_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.NavigateBrowser("SiteA");
@@ -149,13 +226,46 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_48SiteA_12SiteA_34SiteA_24) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_69SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_34SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
@@ -164,27 +274,31 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_48SiteA_12SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteA_24_12SiteA_37SiteA_17_20) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_37SiteA_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconShown();
@@ -192,27 +306,146 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_28_36SiteA_34SiteA_25) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_28_70SiteA_69SiteA_94_24_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayBrowser("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckTabNotCreated();
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_28_70SiteA_35SiteA_94_24_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayBrowser("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckTabNotCreated();
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_28_70SiteA_34SiteA_94_24_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayBrowser("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckTabNotCreated();
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_28_36SiteA_69SiteA_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayMinimal("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_28_36SiteA_35SiteA_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayMinimal("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_28_36SiteA_34SiteA_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.ClosePwa();
   helper_.ManifestUpdateDisplayMinimal("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowDisplayMinimal();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteA_24_12SiteA_34SiteA_24_26) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_69SiteA_24_26) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayStandalone();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_35SiteA_24_26) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayStandalone();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_34SiteA_24_26) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckWindowDisplayStandalone();
@@ -220,13 +453,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_50SiteA_11SiteA_34SiteA_22) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_50SiteA_11SiteA_34SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
@@ -235,69 +469,140 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_50SiteA_11SiteA_37SiteA_18) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_50SiteA_11SiteA_37SiteA_18) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckInstallIconShown();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteA_24_12SiteA_37SiteAFoo_17_20) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_37SiteAFoo_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteAFoo");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconShown();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteA_24_12SiteA_37SiteB_18_19) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_37SiteB_18_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteB");
   helper_.CheckInstallIconShown();
   helper_.CheckLaunchIconNotShown();
 }
 
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_30SiteA_24_12SiteA_7SiteA_71_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.OpenInChrome();
+  helper_.CheckTabCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_10SiteA_15SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_49SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_49SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_32SiteA_12SiteA_37SiteA_20) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_39SiteB_16_27_14) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.NavigatePwaSiteATo("SiteB");
+  helper_.CheckCustomToolbar();
+  helper_.CloseCustomToolbar();
+  helper_.CheckAppNavigationIsStartUrl();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_39SiteB_16_71_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.NavigatePwaSiteATo("SiteB");
+  helper_.CheckCustomToolbar();
+  helper_.OpenInChrome();
+  helper_.CheckTabCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_37SiteA_20) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckLaunchIconShown();
@@ -305,14 +610,50 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_32SiteA_12SiteA_34SiteA_24) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_69SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_34SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowCreated();
@@ -320,42 +661,49 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_32SiteA_12SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_33SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_33SiteA_7SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_48SiteA_12SiteA_37SiteA_20) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_37SiteA_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.NavigateBrowser("SiteA");
@@ -364,13 +712,46 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_48SiteA_12SiteA_34SiteA_24) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_69SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_34SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
@@ -379,27 +760,31 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_48SiteA_12SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteA_24_12SiteA_37SiteA_17_20) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_37SiteA_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconShown();
@@ -407,27 +792,146 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_28_36SiteA_34SiteA_25) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_28_70SiteA_69SiteA_94_24_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayBrowser("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckTabNotCreated();
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_28_70SiteA_35SiteA_94_24_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayBrowser("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckTabNotCreated();
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_28_70SiteA_34SiteA_94_24_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayBrowser("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckTabNotCreated();
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_28_36SiteA_69SiteA_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayMinimal("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_28_36SiteA_35SiteA_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayMinimal("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_28_36SiteA_34SiteA_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.ClosePwa();
   helper_.ManifestUpdateDisplayMinimal("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowDisplayMinimal();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteA_24_12SiteA_34SiteA_24_26) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_69SiteA_24_26) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayStandalone();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_35SiteA_24_26) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayStandalone();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_34SiteA_24_26) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckWindowDisplayStandalone();
@@ -435,13 +939,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_50SiteA_11SiteA_34SiteA_22) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_50SiteA_11SiteA_34SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
@@ -450,69 +955,140 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_50SiteA_11SiteA_37SiteA_18) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_50SiteA_11SiteA_37SiteA_18) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckInstallIconShown();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteA_24_12SiteA_37SiteAFoo_17_20) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_37SiteAFoo_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteAFoo");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconShown();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteA_24_12SiteA_37SiteB_18_19) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_37SiteB_18_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteB");
   helper_.CheckInstallIconShown();
   helper_.CheckLaunchIconNotShown();
 }
 
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_31SiteA_24_12SiteA_7SiteA_71_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.OpenInChrome();
+  helper_.CheckTabCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_10SiteA_15SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_49SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_49SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_32SiteA_12SiteA_37SiteA_20) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_39SiteB_16_27_14) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.NavigatePwaSiteATo("SiteB");
+  helper_.CheckCustomToolbar();
+  helper_.CloseCustomToolbar();
+  helper_.CheckAppNavigationIsStartUrl();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_39SiteB_16_71_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.NavigatePwaSiteATo("SiteB");
+  helper_.CheckCustomToolbar();
+  helper_.OpenInChrome();
+  helper_.CheckTabCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_37SiteA_20) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckLaunchIconShown();
@@ -520,14 +1096,50 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_32SiteA_12SiteA_34SiteA_24) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_69SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_34SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowCreated();
@@ -535,42 +1147,49 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_32SiteA_12SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_33SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_33SiteA_7SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_48SiteA_12SiteA_37SiteA_20) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_37SiteA_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.NavigateBrowser("SiteA");
@@ -579,13 +1198,46 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_48SiteA_12SiteA_34SiteA_24) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_69SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_34SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
@@ -594,27 +1246,31 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_48SiteA_12SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteA_24_12SiteA_37SiteA_17_20) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_37SiteA_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconShown();
@@ -622,27 +1278,146 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_28_36SiteA_34SiteA_25) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_28_70SiteA_69SiteA_94_24_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayBrowser("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckTabNotCreated();
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_28_70SiteA_35SiteA_94_24_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayBrowser("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckTabNotCreated();
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_28_70SiteA_34SiteA_94_24_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayBrowser("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckTabNotCreated();
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_28_36SiteA_69SiteA_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayMinimal("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_28_36SiteA_35SiteA_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.ClosePwa();
+  helper_.ManifestUpdateDisplayMinimal("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_28_36SiteA_34SiteA_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.ClosePwa();
   helper_.ManifestUpdateDisplayMinimal("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowDisplayMinimal();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteA_24_12SiteA_34SiteA_24_26) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_69SiteA_24_26) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayStandalone();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_35SiteA_24_26) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayStandalone();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_34SiteA_24_26) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckWindowDisplayStandalone();
@@ -650,13 +1425,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_50SiteA_11SiteA_34SiteA_22) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_50SiteA_11SiteA_34SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
@@ -665,58 +1441,326 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_50SiteA_11SiteA_37SiteA_18) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_50SiteA_11SiteA_37SiteA_18) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckInstallIconShown();
 }
 
-// TODO(crbug.com/1279704): Test is consistently failing on Mac and Win7.
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteA_24_12SiteA_37SiteAFoo_17_20) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_37SiteAFoo_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteAFoo");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconShown();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteA_24_12SiteA_37SiteB_18_19) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_37SiteB_18_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteB");
   helper_.CheckInstallIconShown();
   helper_.CheckLaunchIconNotShown();
 }
 
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_47SiteA_24_12SiteA_7SiteA_71_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.OpenInChrome();
+  helper_.CheckTabCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_10SiteA_15SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_49SiteA_44SiteA_12SiteA) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_49SiteA_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_33SiteA_7SiteA_11SiteA_37SiteA_18) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_33SiteA_7SiteA_11SiteA_34SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckTabCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_33SiteA_7SiteA_11SiteA_44SiteA_11SiteA_7SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.UninstallPolicyApp("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_49SiteA_7SiteA_11SiteA_37SiteA_18) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppWindowedShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_49SiteA_7SiteA_11SiteA_34SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppWindowedShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckTabCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_49SiteA_7SiteA_11SiteA_44SiteA_11SiteA_7SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppWindowedShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.UninstallPolicyApp("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_29SiteA_11SiteA_7SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_51SiteA_12SiteA_69SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SetOpenInWindow("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_51SiteA_12SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SetOpenInWindow("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_51SiteA_12SiteA_34SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SetOpenInWindow("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_51SiteA_12SiteA_37SiteA_17_20) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SetOpenInWindow("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconNotShown();
+  helper_.CheckLaunchIconShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_10SiteA_15SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.UninstallFromList("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_32SiteA_44SiteA_11SiteA_7SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.UninstallPolicyApp("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_48SiteA_44SiteA_11SiteA_7SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.InstallPolicyAppTabbedShortcut("SiteA");
+  helper_.UninstallPolicyApp("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+}
+
+// TODO(https://crbug.com/1306779) test is flaky
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    DISABLED_WebAppIntegration_33SiteA_12SiteA_39SiteB_27_14) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.NavigatePwaSiteATo("SiteB");
+  helper_.CloseCustomToolbar();
+  helper_.CheckAppNavigationIsStartUrl();
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
@@ -732,6 +1776,30 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_33SiteA_12SiteA_69SiteA_24_26) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayStandalone();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_33SiteA_12SiteA_35SiteA_24_26) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayStandalone();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_33SiteA_12SiteA_34SiteA_24_26) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -778,68 +1846,117 @@
   helper_.CheckAppNotInList("SiteA");
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteA_12SiteA_37SiteA_17_20) {
+// TODO(https://crbug.com/1306779) test is flaky
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    DISABLED_WebAppIntegration_49SiteA_12SiteA_7SiteA_39SiteB_27_14) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.NavigatePwaSiteATo("SiteB");
+  helper_.CloseCustomToolbar();
+  helper_.CheckAppNavigationIsStartUrl();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_49SiteA_12SiteA_7SiteA_37SiteA_17_20) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconShown();
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteA_12SiteA_34SiteA_24_26) {
+                       WebAppIntegration_49SiteA_12SiteA_7SiteA_69SiteA_24_26) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckWindowDisplayStandalone();
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteA_12SiteA_50SiteA_34SiteA_22) {
+                       WebAppIntegration_49SiteA_12SiteA_7SiteA_35SiteA_24_26) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayStandalone();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_49SiteA_12SiteA_7SiteA_34SiteA_24_26) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.LaunchFromChromeApps("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckWindowDisplayStandalone();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_49SiteA_12SiteA_7SiteA_50SiteA_34SiteA_22) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedShortcut("SiteA");
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckTabCreated();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteA_12SiteA_37SiteAFoo_17_20) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_49SiteA_12SiteA_7SiteA_37SiteAFoo_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteAFoo");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconShown();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteA_12SiteA_44SiteA_15SiteA) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_49SiteA_12SiteA_7SiteA_44SiteA_15SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppNotInList("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_32SiteA_11SiteA_30SiteA_12SiteA_24_44SiteA_12SiteA) {
+    WebAppIntegration_32SiteA_11SiteA_30SiteA_12SiteA_7SiteA_24_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
@@ -847,14 +1964,16 @@
   helper_.CheckAppInListTabbed("SiteA");
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_32SiteA_11SiteA_31SiteA_12SiteA_24_44SiteA_12SiteA) {
+    WebAppIntegration_32SiteA_11SiteA_31SiteA_12SiteA_7SiteA_24_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
@@ -862,14 +1981,16 @@
   helper_.CheckAppInListTabbed("SiteA");
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_32SiteA_11SiteA_47SiteA_12SiteA_24_44SiteA_12SiteA) {
+    WebAppIntegration_32SiteA_11SiteA_47SiteA_12SiteA_7SiteA_24_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
@@ -877,9 +1998,11 @@
   helper_.CheckAppInListTabbed("SiteA");
   helper_.InstallMenuOption("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
@@ -895,6 +2018,30 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_32SiteA_11SiteA_51SiteA_69SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.SetOpenInWindow("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_32SiteA_11SiteA_51SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.SetOpenInWindow("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_32SiteA_11SiteA_51SiteA_34SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -919,219 +2066,108 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_33SiteA_11SiteA_37SiteA_18) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_33SiteA_11SiteA_34SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckTabCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_33SiteA_11SiteA_44SiteA_11SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.UninstallPolicyApp("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_49SiteA_11SiteA_37SiteA_18) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.InstallPolicyAppWindowedShortcut("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_49SiteA_11SiteA_34SiteA_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.InstallPolicyAppWindowedShortcut("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckTabCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_49SiteA_11SiteA_44SiteA_11SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.InstallPolicyAppWindowedShortcut("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.UninstallPolicyApp("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_29SiteA_11SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_51SiteA_12SiteA_34SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SetOpenInWindow("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_51SiteA_12SiteA_37SiteA_17_20) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SetOpenInWindow("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconNotShown();
-  helper_.CheckLaunchIconShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_32SiteA_44SiteA_11SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
-  helper_.UninstallPolicyApp("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_48SiteA_44SiteA_11SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.InstallPolicyAppTabbedShortcut("SiteA");
-  helper_.UninstallPolicyApp("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_48SiteA_11SiteA_30SiteA_12SiteA_24_44SiteA_12SiteA) {
+    WebAppIntegration_48SiteA_11SiteA_7SiteA_30SiteA_12SiteA_7SiteA_24_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_48SiteA_11SiteA_31SiteA_12SiteA_24_44SiteA_12SiteA) {
+    WebAppIntegration_48SiteA_11SiteA_7SiteA_31SiteA_12SiteA_7SiteA_24_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_48SiteA_11SiteA_47SiteA_12SiteA_24_44SiteA_12SiteA) {
+    WebAppIntegration_48SiteA_11SiteA_7SiteA_47SiteA_12SiteA_7SiteA_24_44SiteA_12SiteA_7SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallMenuOption("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_48SiteA_11SiteA_37SiteA_18_19) {
+                       WebAppIntegration_48SiteA_11SiteA_7SiteA_37SiteA_18_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.NavigateBrowser("SiteA");
   helper_.CheckInstallIconShown();
   helper_.CheckLaunchIconNotShown();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_48SiteA_11SiteA_51SiteA_34SiteA_24) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_48SiteA_11SiteA_7SiteA_51SiteA_69SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SetOpenInWindow("SiteA");
+  helper_.LaunchFromMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_48SiteA_11SiteA_7SiteA_51SiteA_35SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppTabbedShortcut("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.SetOpenInWindow("SiteA");
+  helper_.LaunchFromLaunchIcon("SiteA");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_48SiteA_11SiteA_7SiteA_51SiteA_34SiteA_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppTabbedShortcut("SiteA");
+  helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInWindow("SiteA");
   helper_.LaunchFromChromeApps("SiteA");
   helper_.CheckWindowCreated();
@@ -1139,12 +2175,13 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
-    WebAppIntegration_48SiteA_11SiteA_44SiteA_15SiteA_37SiteA_18_19) {
+    WebAppIntegration_48SiteA_11SiteA_7SiteA_44SiteA_15SiteA_37SiteA_18_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.UninstallPolicyApp("SiteA");
   helper_.CheckAppNotInList("SiteA");
   helper_.NavigateBrowser("SiteA");
@@ -1153,51 +2190,105 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteC_12SiteC_37SiteC_17_20) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.NavigateBrowser("SiteC");
-  helper_.CheckInstallIconNotShown();
-  helper_.CheckLaunchIconShown();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteC_12SiteC_34SiteC_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.LaunchFromChromeApps("SiteC");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_29SiteC_11SiteC_37SiteC_17_19) {
+                       WebAppIntegration_29SiteC_11SiteC_7SiteC_37SiteC_17_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutTabbed("SiteC");
   helper_.CheckAppInListTabbed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.NavigateBrowser("SiteC");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconNotShown();
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_29SiteC_11SiteC_34SiteC_22) {
+                       WebAppIntegration_29SiteC_11SiteC_7SiteC_34SiteC_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutTabbed("SiteC");
   helper_.CheckAppInListTabbed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.LaunchFromChromeApps("SiteC");
   helper_.CheckTabCreated();
 }
 
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_29SiteC_11SiteC_7SiteC_10SiteC_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutTabbed("SiteC");
+  helper_.CheckAppInListTabbed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.UninstallFromList("SiteC");
+  helper_.CheckAppNotInList("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_30SiteC_12SiteC_7SiteC_37SiteC_17_20) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.NavigateBrowser("SiteC");
+  helper_.CheckInstallIconNotShown();
+  helper_.CheckLaunchIconShown();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_30SiteC_12SiteC_7SiteC_69SiteC_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.LaunchFromMenuOption("SiteC");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_30SiteC_12SiteC_7SiteC_35SiteC_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.LaunchFromLaunchIcon("SiteC");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_30SiteC_12SiteC_7SiteC_34SiteC_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.LaunchFromChromeApps("SiteC");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTest,
+    WebAppIntegration_30SiteC_12SiteC_7SiteC_10SiteC_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.UninstallFromList("SiteC");
+  helper_.CheckAppNotInList("SiteA");
+}
+
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_33SiteC_12SiteC_37SiteC_17_20) {
   // Test contents are generated by script. Please do not modify!
@@ -1211,6 +2302,28 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_33SiteC_12SiteC_69SiteC_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedNoShortcut("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.LaunchFromMenuOption("SiteC");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_33SiteC_12SiteC_35SiteC_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedNoShortcut("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.LaunchFromLaunchIcon("SiteC");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_33SiteC_12SiteC_34SiteC_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -1245,24 +2358,26 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_48SiteC_11SiteC_37SiteC_17_19) {
+                       WebAppIntegration_48SiteC_11SiteC_7SiteC_37SiteC_17_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppTabbedShortcut("SiteC");
   helper_.CheckAppInListTabbed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.NavigateBrowser("SiteC");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconNotShown();
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_48SiteC_11SiteC_34SiteC_22) {
+                       WebAppIntegration_48SiteC_11SiteC_7SiteC_34SiteC_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppTabbedShortcut("SiteC");
   helper_.CheckAppInListTabbed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.LaunchFromChromeApps("SiteC");
   helper_.CheckTabCreated();
 }
@@ -1278,6 +2393,26 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_30SiteB_69SiteB_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteB");
+  helper_.LaunchFromMenuOption("SiteB");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_30SiteB_35SiteB_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteB");
+  helper_.LaunchFromLaunchIcon("SiteB");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_30SiteB_34SiteB_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -1298,6 +2433,26 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_31SiteB_69SiteB_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteB");
+  helper_.LaunchFromMenuOption("SiteB");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_31SiteB_35SiteB_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteB");
+  helper_.LaunchFromLaunchIcon("SiteB");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_31SiteB_34SiteB_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -1318,6 +2473,26 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_33SiteB_69SiteB_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedNoShortcut("SiteB");
+  helper_.LaunchFromMenuOption("SiteB");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_33SiteB_35SiteB_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedNoShortcut("SiteB");
+  helper_.LaunchFromLaunchIcon("SiteB");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_33SiteB_34SiteB_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -1338,6 +2513,26 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_49SiteB_69SiteB_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedShortcut("SiteB");
+  helper_.LaunchFromMenuOption("SiteB");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_49SiteB_35SiteB_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedShortcut("SiteB");
+  helper_.LaunchFromLaunchIcon("SiteB");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_49SiteB_34SiteB_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -1358,6 +2553,26 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_47SiteB_69SiteB_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteB");
+  helper_.LaunchFromMenuOption("SiteB");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_47SiteB_35SiteB_25) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteB");
+  helper_.LaunchFromLaunchIcon("SiteB");
+  helper_.CheckWindowDisplayMinimal();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_47SiteB_34SiteB_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -1368,24 +2583,50 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteC_12SiteC_37SiteC_17_20) {
+                       WebAppIntegration_49SiteC_12SiteC_7SiteC_37SiteC_17_20) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppWindowedShortcut("SiteC");
   helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.NavigateBrowser("SiteC");
   helper_.CheckInstallIconNotShown();
   helper_.CheckLaunchIconShown();
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteC_12SiteC_34SiteC_24) {
+                       WebAppIntegration_49SiteC_12SiteC_7SiteC_69SiteC_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppWindowedShortcut("SiteC");
   helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.LaunchFromMenuOption("SiteC");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_49SiteC_12SiteC_7SiteC_35SiteC_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedShortcut("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.LaunchFromLaunchIcon("SiteC");
+  helper_.CheckWindowCreated();
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_49SiteC_12SiteC_7SiteC_34SiteC_24) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallPolicyAppWindowedShortcut("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.LaunchFromChromeApps("SiteC");
   helper_.CheckWindowCreated();
 }
@@ -1424,6 +2665,15 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
+                       WebAppIntegration_37SiteA_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_33SiteAFoo_37SiteABar_18_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -1455,15 +2705,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_37SiteA_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
                        WebAppIntegration_37SiteC_15SiteA_17) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -1473,326 +2714,6 @@
   helper_.CheckInstallIconNotShown();
 }
 
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_32SiteA_12SiteA_35SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_48SiteA_12SiteA_35SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_28_36SiteA_35SiteA_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayMinimal("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-// TODO(crbug.com/1279704): Test is consistently failing on Mac and Win7.
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteA_24_12SiteA_35SiteA_24_26) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayStandalone();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_32SiteA_12SiteA_35SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_48SiteA_12SiteA_35SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_28_36SiteA_35SiteA_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayMinimal("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteA_24_12SiteA_35SiteA_24_26) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayStandalone();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_32SiteA_12SiteA_35SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_48SiteA_12SiteA_35SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_28_36SiteA_35SiteA_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayMinimal("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteA_24_12SiteA_35SiteA_24_26) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayStandalone();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_33SiteA_12SiteA_35SiteA_24_26) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayStandalone();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteA_12SiteA_35SiteA_24_26) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayStandalone();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_32SiteA_11SiteA_51SiteA_35SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SetOpenInWindow("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_51SiteA_12SiteA_35SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SetOpenInWindow("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_48SiteA_11SiteA_51SiteA_35SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppTabbedShortcut("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SetOpenInWindow("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteC_12SiteC_35SiteC_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.LaunchFromLaunchIcon("SiteC");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_33SiteC_12SiteC_35SiteC_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedNoShortcut("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.LaunchFromLaunchIcon("SiteC");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteB_35SiteB_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteB");
-  helper_.LaunchFromLaunchIcon("SiteB");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteB_35SiteB_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteB");
-  helper_.LaunchFromLaunchIcon("SiteB");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_33SiteB_35SiteB_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedNoShortcut("SiteB");
-  helper_.LaunchFromLaunchIcon("SiteB");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteB_35SiteB_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedShortcut("SiteB");
-  helper_.LaunchFromLaunchIcon("SiteB");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteB_35SiteB_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteB");
-  helper_.LaunchFromLaunchIcon("SiteB");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteC_12SiteC_35SiteC_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedShortcut("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.LaunchFromLaunchIcon("SiteC");
-  helper_.CheckWindowCreated();
-}
-
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest, WebAppIntegration_38_17) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
@@ -1801,710 +2722,6 @@
   helper_.CheckInstallIconNotShown();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteA_24_12SiteA_39SiteB_16_27_14) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigatePwaSiteATo("SiteB");
-  helper_.CheckCustomToolbar();
-  helper_.CloseCustomToolbar();
-  helper_.CheckAppNavigationIsStartUrl();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteA_24_12SiteA_39SiteB_16_27_14) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigatePwaSiteATo("SiteB");
-  helper_.CheckCustomToolbar();
-  helper_.CloseCustomToolbar();
-  helper_.CheckAppNavigationIsStartUrl();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteA_24_12SiteA_39SiteB_16_27_14) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigatePwaSiteATo("SiteB");
-  helper_.CheckCustomToolbar();
-  helper_.CloseCustomToolbar();
-  helper_.CheckAppNavigationIsStartUrl();
-}
-
-// TODO(https://crbug.com/1306779) test is flaky
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    DISABLED_WebAppIntegration_33SiteA_12SiteA_39SiteB_27_14) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigatePwaSiteATo("SiteB");
-  helper_.CloseCustomToolbar();
-  helper_.CheckAppNavigationIsStartUrl();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    DISABLED_WebAppIntegration_49SiteA_12SiteA_39SiteB_27_14) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigatePwaSiteATo("SiteB");
-  helper_.CloseCustomToolbar();
-  helper_.CheckAppNavigationIsStartUrl();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_10SiteA_15SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_10SiteA_15SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_10SiteA_15SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_10SiteA_15SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.UninstallFromList("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteC_12SiteC_10SiteC_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.UninstallFromList("SiteC");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_29SiteC_11SiteC_10SiteC_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteC");
-  helper_.CheckAppInListTabbed("SiteC");
-  helper_.UninstallFromList("SiteC");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_28_70SiteA_35SiteA_94_24_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayBrowser("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckTabNotCreated();
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_28_70SiteA_34SiteA_94_24_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayBrowser("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckTabNotCreated();
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_28_70SiteA_35SiteA_94_24_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayBrowser("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckTabNotCreated();
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_28_70SiteA_34SiteA_94_24_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayBrowser("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckTabNotCreated();
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_28_70SiteA_35SiteA_94_24_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayBrowser("SiteA");
-  helper_.LaunchFromLaunchIcon("SiteA");
-  helper_.CheckTabNotCreated();
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_28_70SiteA_34SiteA_94_24_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayBrowser("SiteA");
-  helper_.LaunchFromChromeApps("SiteA");
-  helper_.CheckTabNotCreated();
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteA_24_12SiteA_39SiteB_16_71_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigatePwaSiteATo("SiteB");
-  helper_.CheckCustomToolbar();
-  helper_.OpenInChrome();
-  helper_.CheckTabCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteA_24_12SiteA_71_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.OpenInChrome();
-  helper_.CheckTabCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteA_24_12SiteA_39SiteB_16_71_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigatePwaSiteATo("SiteB");
-  helper_.CheckCustomToolbar();
-  helper_.OpenInChrome();
-  helper_.CheckTabCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteA_24_12SiteA_71_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.OpenInChrome();
-  helper_.CheckTabCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteA_24_12SiteA_39SiteB_16_71_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.NavigatePwaSiteATo("SiteB");
-  helper_.CheckCustomToolbar();
-  helper_.OpenInChrome();
-  helper_.CheckTabCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteA_24_12SiteA_71_22) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.OpenInChrome();
-  helper_.CheckTabCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_32SiteA_12SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_48SiteA_12SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_28_70SiteA_69SiteA_94_24_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayBrowser("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckTabNotCreated();
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_30SiteA_24_12SiteA_28_36SiteA_69SiteA_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayMinimal("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteA_24_12SiteA_69SiteA_24_26) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayStandalone();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_32SiteA_12SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_48SiteA_12SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_28_70SiteA_69SiteA_94_24_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayBrowser("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckTabNotCreated();
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_31SiteA_24_12SiteA_28_36SiteA_69SiteA_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayMinimal("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteA_24_12SiteA_69SiteA_24_26) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayStandalone();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_32SiteA_12SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_48SiteA_12SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.InstallPolicyAppTabbedShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_28_70SiteA_69SiteA_94_24_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayBrowser("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckTabNotCreated();
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_47SiteA_24_12SiteA_28_36SiteA_69SiteA_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.ClosePwa();
-  helper_.ManifestUpdateDisplayMinimal("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteA_24_12SiteA_69SiteA_24_26) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayStandalone();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTest,
-    WebAppIntegration_29SiteA_11SiteA_51SiteA_12SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutTabbed("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SetOpenInWindow("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_33SiteA_12SiteA_69SiteA_24_26) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayStandalone();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteA_12SiteA_69SiteA_24_26) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedShortcut("SiteA");
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckWindowDisplayStandalone();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_32SiteA_11SiteA_51SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SetOpenInWindow("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_48SiteA_11SiteA_51SiteA_69SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppTabbedShortcut("SiteA");
-  helper_.CheckAppInListTabbed("SiteA");
-  helper_.SetOpenInWindow("SiteA");
-  helper_.LaunchFromMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteC_12SiteC_69SiteC_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.LaunchFromMenuOption("SiteC");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_33SiteC_12SiteC_69SiteC_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedNoShortcut("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.LaunchFromMenuOption("SiteC");
-  helper_.CheckWindowCreated();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_30SiteB_69SiteB_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteB");
-  helper_.LaunchFromMenuOption("SiteB");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_31SiteB_69SiteB_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteB");
-  helper_.LaunchFromMenuOption("SiteB");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_33SiteB_69SiteB_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedNoShortcut("SiteB");
-  helper_.LaunchFromMenuOption("SiteB");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteB_69SiteB_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedShortcut("SiteB");
-  helper_.LaunchFromMenuOption("SiteB");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_47SiteB_69SiteB_25) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteB");
-  helper_.LaunchFromMenuOption("SiteB");
-  helper_.CheckWindowDisplayMinimal();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTest,
-                       WebAppIntegration_49SiteC_12SiteC_69SiteC_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallPolicyAppWindowedShortcut("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.LaunchFromMenuOption("SiteC");
-  helper_.CheckWindowCreated();
-}
-
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTest,
     WebAppIntegration_30SiteAFoo_28_8SiteA_37SiteABar_17_20) {
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
index ec5d0d6..302b423 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
@@ -153,132 +153,16 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_31SiteA_24_12SiteA_43SiteA_15SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromMenu("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_47SiteA_24_12SiteA_43SiteA_15SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromMenu("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_30SiteA_24_12SiteA_43SiteA_15SiteA_37SiteA_18_19) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_1SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromMenu("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_30SiteC_12SiteC_43SiteC_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.UninstallFromMenu("SiteC");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_30SiteA_24_12SiteA_98SiteA_15SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromAppSettings("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_31SiteA_24_12SiteA_98SiteA_15SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallOmniboxIcon("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromAppSettings("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_47SiteA_24_12SiteA_98SiteA_15SiteA_37SiteA_18_19) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallMenuOption("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
-  helper_.UninstallFromAppSettings("SiteA");
-  helper_.CheckAppNotInList("SiteA");
-  helper_.NavigateBrowser("SiteA");
-  helper_.CheckInstallIconShown();
-  helper_.CheckLaunchIconNotShown();
-}
-
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_30SiteC_12SiteC_98SiteC_15SiteA) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteC");
-  helper_.CheckAppInListWindowed("SiteC");
-  helper_.UninstallFromAppSettings("SiteC");
-  helper_.CheckAppNotInList("SiteA");
-}
-
-IN_PROC_BROWSER_TEST_F(
-    WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_30SiteA_24_12SiteA_32SiteA_12SiteA_1SiteA_24) {
-  // Test contents are generated by script. Please do not modify!
-  // See `chrome/test/webapps/README.md` for more info.
-  // Sheriffs: Disabling this test is supported.
-  helper_.InstallCreateShortcutWindowed("SiteA");
-  helper_.CheckWindowCreated();
-  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowCreated();
@@ -286,13 +170,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_30SiteA_24_12SiteA_48SiteA_12SiteA_1SiteA_24) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_1SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
@@ -301,13 +186,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_30SiteA_24_12SiteA_28_70SiteA_1SiteA_94_24_25) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_28_70SiteA_1SiteA_94_24_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.ClosePwa();
   helper_.ManifestUpdateDisplayBrowser("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
@@ -318,27 +204,30 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_30SiteA_24_12SiteA_28_36SiteA_1SiteA_25) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_28_36SiteA_1SiteA_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.ClosePwa();
   helper_.ManifestUpdateDisplayMinimal("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowDisplayMinimal();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_30SiteA_24_12SiteA_1SiteA_24_26) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_1SiteA_24_26) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckWindowDisplayStandalone();
@@ -346,13 +235,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_30SiteA_24_12SiteA_50SiteA_11SiteA_1SiteA_22) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_50SiteA_11SiteA_1SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
@@ -361,14 +251,50 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_31SiteA_24_12SiteA_32SiteA_12SiteA_1SiteA_24) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_43SiteA_15SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.UninstallFromMenu("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_98SiteA_15SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.UninstallFromAppSettings("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_1SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowCreated();
@@ -376,13 +302,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_31SiteA_24_12SiteA_48SiteA_12SiteA_1SiteA_24) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_1SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
@@ -391,13 +318,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_31SiteA_24_12SiteA_28_70SiteA_1SiteA_94_24_25) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_28_70SiteA_1SiteA_94_24_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.ClosePwa();
   helper_.ManifestUpdateDisplayBrowser("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
@@ -408,27 +336,30 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_31SiteA_24_12SiteA_28_36SiteA_1SiteA_25) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_28_36SiteA_1SiteA_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.ClosePwa();
   helper_.ManifestUpdateDisplayMinimal("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowDisplayMinimal();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_31SiteA_24_12SiteA_1SiteA_24_26) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_1SiteA_24_26) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckWindowDisplayStandalone();
@@ -436,13 +367,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_31SiteA_24_12SiteA_50SiteA_11SiteA_1SiteA_22) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_50SiteA_11SiteA_1SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
@@ -451,14 +383,50 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_47SiteA_24_12SiteA_32SiteA_12SiteA_1SiteA_24) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_43SiteA_15SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.UninstallFromMenu("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_98SiteA_15SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallOmniboxIcon("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.UninstallFromAppSettings("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_32SiteA_7SiteA_12SiteA_1SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowCreated();
@@ -466,13 +434,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_47SiteA_24_12SiteA_48SiteA_12SiteA_1SiteA_24) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_48SiteA_12SiteA_1SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
@@ -481,13 +450,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_47SiteA_24_12SiteA_28_70SiteA_1SiteA_94_24_25) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_28_70SiteA_1SiteA_94_24_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.ClosePwa();
   helper_.ManifestUpdateDisplayBrowser("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
@@ -498,27 +468,30 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_47SiteA_24_12SiteA_28_36SiteA_1SiteA_25) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_28_36SiteA_1SiteA_25) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.ClosePwa();
   helper_.ManifestUpdateDisplayMinimal("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowDisplayMinimal();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_47SiteA_24_12SiteA_1SiteA_24_26) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_1SiteA_24_26) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckWindowDisplayStandalone();
@@ -526,13 +499,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_47SiteA_24_12SiteA_50SiteA_11SiteA_1SiteA_22) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_50SiteA_11SiteA_1SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
@@ -541,13 +515,49 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_29SiteA_11SiteA_33SiteA_11SiteA_1SiteA_22) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_43SiteA_15SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.UninstallFromMenu("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_98SiteA_15SiteA_37SiteA_18_19) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallMenuOption("SiteA");
+  helper_.CheckWindowCreated();
+  helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
+  helper_.UninstallFromAppSettings("SiteA");
+  helper_.CheckAppNotInList("SiteA");
+  helper_.NavigateBrowser("SiteA");
+  helper_.CheckInstallIconShown();
+  helper_.CheckLaunchIconNotShown();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_33SiteA_7SiteA_11SiteA_1SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutTabbed("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppWindowedNoShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckTabCreated();
@@ -555,13 +565,15 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_29SiteA_11SiteA_49SiteA_11SiteA_1SiteA_22) {
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_49SiteA_7SiteA_11SiteA_1SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutTabbed("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckTabCreated();
@@ -569,12 +581,13 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestMacWinLinux,
-    WebAppIntegration_29SiteA_11SiteA_51SiteA_12SiteA_1SiteA_24) {
+    WebAppIntegration_29SiteA_11SiteA_7SiteA_51SiteA_12SiteA_1SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutTabbed("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInWindow("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
@@ -606,24 +619,27 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_49SiteA_12SiteA_1SiteA_24_26) {
+                       WebAppIntegration_49SiteA_12SiteA_7SiteA_1SiteA_24_26) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckWindowDisplayStandalone();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_49SiteA_12SiteA_50SiteA_1SiteA_22) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_49SiteA_12SiteA_7SiteA_50SiteA_1SiteA_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppWindowedShortcut("SiteA");
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInTab("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckTabCreated();
@@ -641,40 +657,70 @@
   helper_.CheckWindowCreated();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_48SiteA_11SiteA_51SiteA_1SiteA_24) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_48SiteA_11SiteA_7SiteA_51SiteA_1SiteA_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppTabbedShortcut("SiteA");
   helper_.CheckAppInListTabbed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.SetOpenInWindow("SiteA");
   helper_.LaunchFromPlatformShortcut("SiteA");
   helper_.CheckWindowCreated();
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_29SiteC_11SiteC_1SiteC_22) {
+                       WebAppIntegration_29SiteC_11SiteC_7SiteC_1SiteC_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutTabbed("SiteC");
   helper_.CheckAppInListTabbed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.LaunchFromPlatformShortcut("SiteC");
   helper_.CheckTabCreated();
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_30SiteC_12SiteC_1SiteC_24) {
+                       WebAppIntegration_30SiteC_12SiteC_7SiteC_1SiteC_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteC");
   helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.LaunchFromPlatformShortcut("SiteC");
   helper_.CheckWindowCreated();
 }
 
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_30SiteC_12SiteC_7SiteC_43SiteC_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.UninstallFromMenu("SiteC");
+  helper_.CheckAppNotInList("SiteA");
+}
+
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestMacWinLinux,
+    WebAppIntegration_30SiteC_12SiteC_7SiteC_98SiteC_15SiteA) {
+  // Test contents are generated by script. Please do not modify!
+  // See `chrome/test/webapps/README.md` for more info.
+  // Sheriffs: Disabling this test is supported.
+  helper_.InstallCreateShortcutWindowed("SiteC");
+  helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
+  helper_.UninstallFromAppSettings("SiteC");
+  helper_.CheckAppNotInList("SiteA");
+}
+
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
                        WebAppIntegration_33SiteC_12SiteC_1SiteC_24) {
   // Test contents are generated by script. Please do not modify!
@@ -698,12 +744,13 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_48SiteC_11SiteC_1SiteC_22) {
+                       WebAppIntegration_48SiteC_11SiteC_7SiteC_1SiteC_22) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppTabbedShortcut("SiteC");
   helper_.CheckAppInListTabbed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.LaunchFromPlatformShortcut("SiteC");
   helper_.CheckTabCreated();
 }
@@ -759,12 +806,13 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestMacWinLinux,
-                       WebAppIntegration_49SiteC_12SiteC_1SiteC_24) {
+                       WebAppIntegration_49SiteC_12SiteC_7SiteC_1SiteC_24) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallPolicyAppWindowedShortcut("SiteC");
   helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.LaunchFromPlatformShortcut("SiteC");
   helper_.CheckWindowCreated();
 }
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_win.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_win.cc
index 78e21f3..da23d614 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_win.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_win.cc
@@ -23,13 +23,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestWin,
-    WebAppIntegration_30SiteA_24_12SiteA_87SiteA_15SiteA_37SiteA_18_19) {
+    WebAppIntegration_30SiteA_24_12SiteA_7SiteA_87SiteA_15SiteA_37SiteA_18_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.UninstallFromOs("SiteA");
   helper_.CheckAppNotInList("SiteA");
   helper_.NavigateBrowser("SiteA");
@@ -39,13 +40,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestWin,
-    WebAppIntegration_31SiteA_24_12SiteA_87SiteA_15SiteA_37SiteA_18_19) {
+    WebAppIntegration_31SiteA_24_12SiteA_7SiteA_87SiteA_15SiteA_37SiteA_18_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallOmniboxIcon("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.UninstallFromOs("SiteA");
   helper_.CheckAppNotInList("SiteA");
   helper_.NavigateBrowser("SiteA");
@@ -55,13 +57,14 @@
 
 IN_PROC_BROWSER_TEST_F(
     WebAppIntegrationBrowserTestWin,
-    WebAppIntegration_47SiteA_24_12SiteA_87SiteA_15SiteA_37SiteA_18_19) {
+    WebAppIntegration_47SiteA_24_12SiteA_7SiteA_87SiteA_15SiteA_37SiteA_18_19) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallMenuOption("SiteA");
   helper_.CheckWindowCreated();
   helper_.CheckAppInListWindowed("SiteA");
+  helper_.CheckPlatformShortcutAndIcon("SiteA");
   helper_.UninstallFromOs("SiteA");
   helper_.CheckAppNotInList("SiteA");
   helper_.NavigateBrowser("SiteA");
@@ -69,13 +72,15 @@
   helper_.CheckLaunchIconNotShown();
 }
 
-IN_PROC_BROWSER_TEST_F(WebAppIntegrationBrowserTestWin,
-                       WebAppIntegration_30SiteC_12SiteC_87SiteC_15SiteA) {
+IN_PROC_BROWSER_TEST_F(
+    WebAppIntegrationBrowserTestWin,
+    WebAppIntegration_30SiteC_12SiteC_7SiteC_87SiteC_15SiteA) {
   // Test contents are generated by script. Please do not modify!
   // See `chrome/test/webapps/README.md` for more info.
   // Sheriffs: Disabling this test is supported.
   helper_.InstallCreateShortcutWindowed("SiteC");
   helper_.CheckAppInListWindowed("SiteC");
+  helper_.CheckPlatformShortcutAndIcon("SiteC");
   helper_.UninstallFromOs("SiteC");
   helper_.CheckAppNotInList("SiteA");
 }
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
index 401075a..2c12c1fe 100644
--- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
@@ -2245,10 +2245,12 @@
       shortcut_override_->desktop.GetPath().Append(shortcut_filename);
   if (base::PathExists(desktop_shortcut_path))
     is_shortcut_and_icon_correct = IconManagerCheckIconTopLeftColor(
-        provider()->icon_manager(), id, {192, 48}, expected_icon_pxiel_color);
+        provider()->icon_manager(), id, {kLauncherIconSize, kInstallIconSize},
+        expected_icon_pxiel_color);
 #elif BUILDFLAG(IS_CHROMEOS)
   is_shortcut_and_icon_correct = IconManagerCheckIconTopLeftColor(
-      provider()->icon_manager(), id, {192, 48}, expected_icon_pxiel_color);
+      provider()->icon_manager(), id, {kLauncherIconSize, kInstallIconSize},
+      expected_icon_pxiel_color);
 #endif
   return is_shortcut_and_icon_correct;
 }
diff --git a/chrome/browser/ui/webui/extensions/extension_basic_info.cc b/chrome/browser/ui/webui/extensions/extension_basic_info.cc
index 7be55d6..452810d 100644
--- a/chrome/browser/ui/webui/extensions/extension_basic_info.cc
+++ b/chrome/browser/ui/webui/extensions/extension_basic_info.cc
@@ -33,26 +33,23 @@
 
 void GetExtensionBasicInfo(const Extension* extension,
                            bool enabled,
-                           base::DictionaryValue* info) {
-  info->SetStringKey(kInfoIdKey, extension->id());
-  info->SetStringKey(kInfoNameKey, extension->name());
-  info->SetBoolKey(kEnabledKey, enabled);
-  info->SetBoolKey(kKioskEnabledKey, KioskModeInfo::IsKioskEnabled(extension));
-  info->SetBoolKey(kKioskOnlyKey, KioskModeInfo::IsKioskOnly(extension));
-  info->SetBoolKey(kOfflineEnabledKey,
-                   OfflineEnabledInfo::IsOfflineEnabled(extension));
-  info->SetStringKey(kInfoVersionKey, extension->GetVersionForDisplay());
-  info->SetStringKey(kDescriptionKey, extension->description());
-  info->SetStringKey(
-      kOptionsUrlKey,
-      OptionsPageInfo::GetOptionsPage(extension).possibly_invalid_spec());
-  info->SetStringKey(
-      kHomepageUrlKey,
-      ManifestURL::GetHomepageURL(extension).possibly_invalid_spec());
-  info->SetStringKey(
-      kDetailsUrlKey,
-      ManifestURL::GetDetailsURL(extension).possibly_invalid_spec());
-  info->SetBoolKey(kPackagedAppKey, extension->is_platform_app());
+                           base::Value::Dict* info) {
+  info->Set(kInfoIdKey, extension->id());
+  info->Set(kInfoNameKey, extension->name());
+  info->Set(kEnabledKey, enabled);
+  info->Set(kKioskEnabledKey, KioskModeInfo::IsKioskEnabled(extension));
+  info->Set(kKioskOnlyKey, KioskModeInfo::IsKioskOnly(extension));
+  info->Set(kOfflineEnabledKey,
+            OfflineEnabledInfo::IsOfflineEnabled(extension));
+  info->Set(kInfoVersionKey, extension->GetVersionForDisplay());
+  info->Set(kDescriptionKey, extension->description());
+  info->Set(kOptionsUrlKey,
+            OptionsPageInfo::GetOptionsPage(extension).possibly_invalid_spec());
+  info->Set(kHomepageUrlKey,
+            ManifestURL::GetHomepageURL(extension).possibly_invalid_spec());
+  info->Set(kDetailsUrlKey,
+            ManifestURL::GetDetailsURL(extension).possibly_invalid_spec());
+  info->Set(kPackagedAppKey, extension->is_platform_app());
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/ui/webui/extensions/extension_basic_info.h b/chrome/browser/ui/webui/extensions/extension_basic_info.h
index 51069ea6..912b2e8 100644
--- a/chrome/browser/ui/webui/extensions/extension_basic_info.h
+++ b/chrome/browser/ui/webui/extensions/extension_basic_info.h
@@ -5,9 +5,7 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_EXTENSIONS_EXTENSION_BASIC_INFO_H_
 #define CHROME_BROWSER_UI_WEBUI_EXTENSIONS_EXTENSION_BASIC_INFO_H_
 
-namespace base {
-class DictionaryValue;
-}
+#include "base/values.h"
 
 namespace extensions {
 
@@ -17,7 +15,7 @@
 // |enabled| is injected for easier testing.
 void GetExtensionBasicInfo(const Extension* extension,
                            bool enabled,
-                           base::DictionaryValue* info);
+                           base::Value::Dict* info);
 
 }  // namespace extensions
 
diff --git a/chrome/browser/ui/webui/history/foreign_session_handler.cc b/chrome/browser/ui/webui/history/foreign_session_handler.cc
index 66a7b27..2381f53 100644
--- a/chrome/browser/ui/webui/history/foreign_session_handler.cc
+++ b/chrome/browser/ui/webui/history/foreign_session_handler.cc
@@ -82,19 +82,19 @@
   if (!tab_url.is_valid() || tab_url.spec() == chrome::kChromeUINewTabURL)
     return base::Value();
 
-  base::Value dictionary(base::Value::Type::DICTIONARY);
+  base::Value::Dict dictionary;
   NewTabUI::SetUrlTitleAndDirection(&dictionary, current_navigation.title(),
                                     tab_url);
-  dictionary.SetStringKey("remoteIconUrlForUma",
-                          current_navigation.favicon_url().spec());
-  dictionary.SetStringKey("type", "tab");
-  dictionary.SetDoubleKey("timestamp",
-                          static_cast<double>(tab.timestamp.ToInternalValue()));
+  dictionary.Set("remoteIconUrlForUma",
+                 current_navigation.favicon_url().spec());
+  dictionary.Set("type", "tab");
+  dictionary.Set("timestamp",
+                 static_cast<double>(tab.timestamp.ToInternalValue()));
   // TODO(jeremycho): This should probably be renamed to tabId to avoid
   // confusion with the ID corresponding to a session.  Investigate all the
   // places (C++ and JS) where this is being used.  (http://crbug.com/154865).
-  dictionary.SetIntKey("sessionId", tab.tab_id.id());
-  return dictionary;
+  dictionary.Set("sessionId", tab.tab_id.id());
+  return base::Value(std::move(dictionary));
 }
 
 // Helper for initializing a boilerplate SessionWindow JSON compatible object.
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom b/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom
index 3388d613..c5f29ac 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page.mojom
@@ -259,6 +259,8 @@
   // Returns the order of modules or an empty array if the user has not
   // reordered them before.
   GetModulesOrder() => (array<string> module_ids);
+  // Increment the number of times the user has seen modules.
+  IncrementModulesShownCount();
   // If |visible| Modular NTP Desktop v1 First Run Experience will be shown.
   SetModulesFreVisible(bool visible);
   // Triggers a call to |SetModulesFreVisibility|.
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
index 8c603a56..4126faf 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.cc
@@ -6,6 +6,9 @@
 
 #include <algorithm>
 #include <iterator>
+#include <memory>
+#include <string>
+#include <utility>
 
 #include "base/base64.h"
 #include "base/bind.h"
@@ -286,45 +289,46 @@
     if (parts) {
       std::vector<new_tab_page::mojom::PromoPartPtr> mojom_parts;
       for (const base::Value& part : parts->GetListDeprecated()) {
-        if (part.FindKey("image")) {
+        const base::Value::Dict& part_dict = part.GetDict();
+        if (part_dict.Find("image")) {
           auto mojom_image = new_tab_page::mojom::PromoImagePart::New();
-          auto* image_url = part.FindStringPath("image.image_url");
+          auto* image_url = part_dict.FindStringByDottedPath("image.image_url");
           if (!image_url || image_url->empty()) {
             continue;
           }
           mojom_image->image_url = GURL(*image_url);
-          auto* target = part.FindStringPath("image.target");
+          auto* target = part_dict.FindStringByDottedPath("image.target");
           if (target && !target->empty()) {
             mojom_image->target = GURL(*target);
           }
           mojom_parts.push_back(
               new_tab_page::mojom::PromoPart::NewImage(std::move(mojom_image)));
-        } else if (part.FindKey("link")) {
+        } else if (part_dict.Find("link")) {
           auto mojom_link = new_tab_page::mojom::PromoLinkPart::New();
-          auto* url = part.FindStringPath("link.url");
+          auto* url = part_dict.FindStringByDottedPath("link.url");
           if (!url || url->empty()) {
             continue;
           }
           mojom_link->url = GURL(*url);
-          auto* text = part.FindStringPath("link.text");
+          auto* text = part_dict.FindStringByDottedPath("link.text");
           if (!text || text->empty()) {
             continue;
           }
           mojom_link->text = *text;
-          auto* color = part.FindStringPath("link.color");
+          auto* color = part_dict.FindStringByDottedPath("link.color");
           if (color && !color->empty()) {
             mojom_link->color = *color;
           }
           mojom_parts.push_back(
               new_tab_page::mojom::PromoPart::NewLink(std::move(mojom_link)));
-        } else if (part.FindKey("text")) {
+        } else if (part_dict.Find("text")) {
           auto mojom_text = new_tab_page::mojom::PromoTextPart::New();
-          auto* text = part.FindStringPath("text.text");
+          auto* text = part_dict.FindStringByDottedPath("text.text");
           if (!text || text->empty()) {
             continue;
           }
           mojom_text->text = *text;
-          auto* color = part.FindStringPath("text.color");
+          auto* color = part_dict.FindStringByDottedPath("text.color");
           if (color && !color->empty()) {
             mojom_text->color = *color;
           }
@@ -399,6 +403,8 @@
   registry->RegisterListPref(prefs::kNtpDisabledModules, true);
   registry->RegisterListPref(prefs::kNtpModulesOrder, true);
   registry->RegisterBooleanPref(prefs::kNtpModulesVisible, true);
+  registry->RegisterIntegerPref(prefs::kNtpModulesShownCount, 0);
+  registry->RegisterTimePref(prefs::kNtpModulesFirstShownTime, base::Time());
   registry->RegisterBooleanPref(prefs::kNtpModulesFreVisible, true);
   registry->RegisterIntegerPref(prefs::kNtpModulesFreShownCount, 0);
   registry->RegisterTimePref(prefs::kNtpModulesFreFirstShownTime, base::Time());
@@ -655,6 +661,18 @@
   std::move(callback).Run(std::move(module_ids));
 }
 
+void NewTabPageHandler::IncrementModulesShownCount() {
+  const auto ntp_modules_shown_count =
+      profile_->GetPrefs()->GetInteger(prefs::kNtpModulesShownCount);
+
+  if (ntp_modules_shown_count == 0) {
+    profile_->GetPrefs()->SetTime(prefs::kNtpModulesFirstShownTime,
+                                  base::Time::Now());
+  }
+  profile_->GetPrefs()->SetInteger(prefs::kNtpModulesShownCount,
+                                   ntp_modules_shown_count + 1);
+}
+
 void NewTabPageHandler::UpdateModulesFreVisibility() {
   const auto ntp_modules_fre_first_shown_time =
       profile_->GetPrefs()->GetTime(prefs::kNtpModulesFreFirstShownTime);
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.h b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.h
index 3de74ce2..bfe82db 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.h
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.h
@@ -106,6 +106,7 @@
   void OnModulesLoadedWithData() override;
   void SetModulesOrder(const std::vector<std::string>& module_ids) override;
   void GetModulesOrder(GetModulesOrderCallback callback) override;
+  void IncrementModulesShownCount() override;
   void UpdateModulesFreVisibility() override;
   void SetModulesFreVisible(bool visible) override;
   void OnAppRendered(double time) override;
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc
index 02d9a99..22e08ee 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_handler_unittest.cc
@@ -735,3 +735,17 @@
 
   mock_page_.FlushForTesting();
 }
+
+TEST_F(NewTabPageHandlerTest, IncrementModulesShownCount) {
+  EXPECT_EQ(profile_->GetPrefs()->GetInteger(prefs::kNtpModulesShownCount), 0);
+  EXPECT_EQ(profile_->GetPrefs()->GetTime(prefs::kNtpModulesFirstShownTime),
+            base::Time());
+
+  handler_->IncrementModulesShownCount();
+
+  EXPECT_EQ(profile_->GetPrefs()->GetInteger(prefs::kNtpModulesShownCount), 1);
+  EXPECT_NE(profile_->GetPrefs()->GetTime(prefs::kNtpModulesFirstShownTime),
+            base::Time());
+
+  mock_page_.FlushForTesting();
+}
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 902ed75..9d19a57 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -149,15 +149,15 @@
 
 void GetWebAppBasicInfo(const web_app::AppId& app_id,
                         const web_app::WebAppRegistrar& app_registrar,
-                        base::DictionaryValue* info) {
-  info->SetStringKey(kInfoIdKey, app_id);
-  info->SetStringKey(kInfoNameKey, app_registrar.GetAppShortName(app_id));
-  info->SetBoolKey(kEnabledKey, true);
-  info->SetBoolKey(kKioskEnabledKey, false);
-  info->SetBoolKey(kKioskOnlyKey, false);
-  info->SetBoolKey(kOfflineEnabledKey, true);
-  info->SetStringKey(kDescriptionKey, app_registrar.GetAppDescription(app_id));
-  info->SetBoolKey(kPackagedAppKey, false);
+                        base::Value::Dict* info) {
+  info->Set(kInfoIdKey, app_id);
+  info->Set(kInfoNameKey, app_registrar.GetAppShortName(app_id));
+  info->Set(kEnabledKey, true);
+  info->Set(kKioskEnabledKey, false);
+  info->Set(kKioskOnlyKey, false);
+  info->Set(kOfflineEnabledKey, true);
+  info->Set(kDescriptionKey, app_registrar.GetAppDescription(app_id));
+  info->Set(kPackagedAppKey, false);
 }
 
 bool HasMatchingOrGreaterThanIcon(const SortedSizesPx& downloaded_icon_sizes,
@@ -194,37 +194,36 @@
   extension_uninstall_dialog_.reset();
 }
 
-void AppLauncherHandler::CreateWebAppInfo(const web_app::AppId& app_id,
-                                          base::DictionaryValue* value) {
-  // The items which are to be written into |value| are also described in
+base::Value::Dict AppLauncherHandler::CreateWebAppInfo(
+    const web_app::AppId& app_id) {
+  // The items which are to be in the returned Value::Dict are also described in
   // chrome/browser/resources/ntp4/page_list_view.js in @typedef for AppInfo.
   // Please update it whenever you add or remove any keys here.
-  value->DictClear();
+  base::Value::Dict dict;
 
   // Communicate the kiosk flag so the apps page can disable showing the
   // context menu in kiosk mode.
-  value->SetBoolKey(
-      "kioskMode",
-      base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode));
+  dict.Set("kioskMode", base::CommandLine::ForCurrentProcess()->HasSwitch(
+                            switches::kKioskMode));
 
   auto& registrar = web_app_provider_->registrar();
 
   std::u16string name = base::UTF8ToUTF16(registrar.GetAppShortName(app_id));
-  NewTabUI::SetUrlTitleAndDirection(value, name,
+  NewTabUI::SetUrlTitleAndDirection(&dict, name,
                                     registrar.GetAppStartUrl(app_id));
-  NewTabUI::SetFullNameAndDirection(name, value);
+  NewTabUI::SetFullNameAndDirection(name, &dict);
 
-  GetWebAppBasicInfo(app_id, registrar, value);
+  GetWebAppBasicInfo(app_id, registrar, &dict);
 
-  value->SetBoolKey(
+  dict.Set(
       "mayDisable",
       web_app_provider_->install_finalizer().CanUserUninstallWebApp(app_id));
   bool is_locally_installed = registrar.IsLocallyInstalled(app_id);
-  value->SetBoolKey("mayChangeLaunchType", is_locally_installed);
+  dict.Set("mayChangeLaunchType", is_locally_installed);
 
   // Any locally installed app can have shortcuts created.
-  value->SetBoolKey("mayCreateShortcuts", is_locally_installed);
-  value->SetBoolKey("isLocallyInstalled", is_locally_installed);
+  dict.Set("mayCreateShortcuts", is_locally_installed);
+  dict.Set("isLocallyInstalled", is_locally_installed);
 
   absl::optional<std::string> icon_big;
   absl::optional<std::string> icon_small;
@@ -245,19 +244,18 @@
             .spec();
   }
 
-  value->SetBoolKey("icon_big_exists", icon_big.has_value());
-  value->SetStringKey("icon_big", icon_big.value_or(GURL().spec()));
-  value->SetBoolKey("icon_small_exists", icon_small.has_value());
-  value->SetStringKey("icon_small", icon_small.value_or(GURL().spec()));
+  dict.Set("icon_big_exists", icon_big.has_value());
+  dict.Set("icon_big", icon_big.value_or(GURL().spec()));
+  dict.Set("icon_small_exists", icon_small.has_value());
+  dict.Set("icon_small", icon_small.value_or(GURL().spec()));
 
   extensions::LaunchContainerAndType result =
       extensions::GetLaunchContainerAndTypeFromDisplayMode(
           registrar.GetAppUserDisplayMode(app_id));
-  value->SetIntKey("launch_container",
-                   static_cast<int>(result.launch_container));
-  value->SetIntKey("launch_type", result.launch_type);
-  value->SetBoolKey("is_component", false);
-  value->SetBoolKey("is_webstore", false);
+  dict.Set("launch_container", static_cast<int>(result.launch_container));
+  dict.Set("launch_type", result.launch_type);
+  dict.Set("is_component", false);
+  dict.Set("is_webstore", false);
 
   // TODO(https://crbug.com/1061586): Figure out a way to keep the AppSorting
   // system compatible with web apps.
@@ -270,8 +268,7 @@
     page_ordinal = sorting->GetNaturalAppPageOrdinal();
     sorting->SetPageOrdinal(app_id, page_ordinal);
   }
-  value->SetIntKey("page_index",
-                   sorting->PageStringOrdinalAsInteger(page_ordinal));
+  dict.Set("page_index", sorting->PageStringOrdinalAsInteger(page_ordinal));
 
   syncer::StringOrdinal app_launch_ordinal =
       sorting->GetAppLaunchOrdinal(app_id);
@@ -281,42 +278,40 @@
     app_launch_ordinal = sorting->CreateNextAppLaunchOrdinal(page_ordinal);
     sorting->SetAppLaunchOrdinal(app_id, app_launch_ordinal);
   }
-  value->SetStringKey("app_launch_ordinal",
-                      app_launch_ordinal.ToInternalValue());
+  dict.Set("app_launch_ordinal", app_launch_ordinal.ToInternalValue());
 
   // Only show the Run on OS Login menu item for locally installed web apps
-  value->SetBoolKey(
-      "mayShowRunOnOsLoginMode",
-      base::FeatureList::IsEnabled(features::kDesktopPWAsRunOnOsLogin) &&
-          is_locally_installed);
+  dict.Set("mayShowRunOnOsLoginMode",
+           base::FeatureList::IsEnabled(features::kDesktopPWAsRunOnOsLogin) &&
+               is_locally_installed);
 
   const auto login_mode = registrar.GetAppRunOnOsLoginMode(app_id);
-  value->SetBoolKey("mayToggleRunOnOsLoginMode", login_mode.user_controllable);
-  value->SetStringKey("runOnOsLoginMode",
-                      (login_mode.value == web_app::RunOnOsLoginMode::kNotRun)
-                          ? kRunOnOsLoginModeNotRun
-                          : kRunOnOsLoginModeWindowed);
+  dict.Set("mayToggleRunOnOsLoginMode", login_mode.user_controllable);
+  dict.Set("runOnOsLoginMode",
+           (login_mode.value == web_app::RunOnOsLoginMode::kNotRun)
+               ? kRunOnOsLoginModeNotRun
+               : kRunOnOsLoginModeWindowed);
 
   // Show settings instead of App info for locally installed web apps.
   if (base::FeatureList::IsEnabled(features::kDesktopPWAsWebAppSettingsPage) &&
       is_locally_installed) {
-    value->SetStringKey("settingsMenuItemOverrideText",
-                        l10n_util::GetStringUTF16(IDS_WEB_APP_SETTINGS_LINK));
+    dict.Set("settingsMenuItemOverrideText",
+             l10n_util::GetStringUTF16(IDS_WEB_APP_SETTINGS_LINK));
   }
+  return dict;
 }
 
-void AppLauncherHandler::CreateExtensionInfo(const Extension* extension,
-                                             base::DictionaryValue* value) {
-  // The items which are to be written into |value| are also described in
-  // chrome/browser/resources/ntp4/page_list_view.js in @typedef for AppInfo.
-  // Please update it whenever you add or remove any keys here.
-  value->DictClear();
+base::Value::Dict AppLauncherHandler::CreateExtensionInfo(
+    const Extension* extension) {
+  // The items which are to be written into the returned dict are also
+  // described in chrome/browser/resources/ntp4/page_list_view.js in @typedef
+  // for AppInfo. Please update it whenever you add or remove any keys here.
+  base::Value::Dict dict;
 
   // Communicate the kiosk flag so the apps page can disable showing the
   // context menu in kiosk mode.
-  value->SetBoolKey(
-      "kioskMode",
-      base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode));
+  dict.Set("kioskMode", base::CommandLine::ForCurrentProcess()->HasSwitch(
+                            switches::kKioskMode));
 
   bool is_deprecated_app = false;
   auto* context = extension_service_->GetBrowserContext();
@@ -325,15 +320,14 @@
   is_deprecated_app =
       extensions::IsExtensionUnsupportedDeprecatedApp(context, extension->id());
 #endif
-  value->SetBoolKey("is_deprecated_app", is_deprecated_app);
+  dict.Set("is_deprecated_app", is_deprecated_app);
 
   // The Extension class 'helpfully' wraps bidi control characters that
   // impede our ability to determine directionality.
   std::u16string short_name = base::UTF8ToUTF16(extension->short_name());
   base::i18n::UnadjustStringForLocaleDirection(&short_name);
   NewTabUI::SetUrlTitleAndDirection(
-      value,
-      short_name,
+      &dict, short_name,
       extensions::AppLaunchInfo::GetFullLaunchURL(extension));
 
   std::u16string name = base::UTF8ToUTF16(extension->name());
@@ -343,30 +337,29 @@
     name = l10n_util::GetStringFUTF16(IDS_APPS_PAGE_DEPRECATED_APP_TITLE, name);
     deprecated_app_ids_.insert(extension->id());
   }
-  NewTabUI::SetFullNameAndDirection(name, value);
+  NewTabUI::SetFullNameAndDirection(name, &dict);
 
   bool enabled = extension_service_->IsExtensionEnabled(extension->id()) &&
                  !extensions::ExtensionRegistry::Get(
                       extension_service_->GetBrowserContext())
                       ->terminated_extensions()
                       .GetByID(extension->id());
-  extensions::GetExtensionBasicInfo(extension, enabled, value);
+  extensions::GetExtensionBasicInfo(extension, enabled, &dict);
 
-  value->SetBoolKey(
-      "mayDisable",
-      extensions::ExtensionSystem::Get(extension_service_->profile())
-          ->management_policy()
-          ->UserMayModifySettings(extension, nullptr));
+  dict.Set("mayDisable",
+           extensions::ExtensionSystem::Get(extension_service_->profile())
+               ->management_policy()
+               ->UserMayModifySettings(extension, nullptr));
 
   bool is_locally_installed =
       !extension->is_hosted_app() ||
       BookmarkAppIsLocallyInstalled(extension_service_->profile(), extension);
-  value->SetBoolKey("mayChangeLaunchType",
-                    !extension->is_platform_app() && is_locally_installed);
+  dict.Set("mayChangeLaunchType",
+           !extension->is_platform_app() && is_locally_installed);
 
   // Any locally installed app can have shortcuts created.
-  value->SetBoolKey("mayCreateShortcuts", is_locally_installed);
-  value->SetBoolKey("isLocallyInstalled", is_locally_installed);
+  dict.Set("mayCreateShortcuts", is_locally_installed);
+  dict.Set("isLocallyInstalled", is_locally_installed);
 
   auto icon_size = extension_misc::EXTENSION_ICON_LARGE;
   auto match_type = ExtensionIconSet::MATCH_BIGGER;
@@ -375,8 +368,8 @@
            .is_empty();
   GURL large_icon = extensions::ExtensionIconSource::GetIconURL(
       extension, icon_size, match_type, false);
-  value->SetStringKey("icon_big", large_icon.spec());
-  value->SetBoolKey("icon_big_exists", has_non_default_large_icon);
+  dict.Set("icon_big", large_icon.spec());
+  dict.Set("icon_big_exists", has_non_default_large_icon);
 
   icon_size = extension_misc::EXTENSION_ICON_BITTY;
   bool has_non_default_small_icon =
@@ -384,20 +377,17 @@
            .is_empty();
   GURL small_icon = extensions::ExtensionIconSource::GetIconURL(
       extension, icon_size, match_type, false);
-  value->SetStringKey("icon_small", small_icon.spec());
-  value->SetBoolKey("icon_small_exists", has_non_default_small_icon);
+  dict.Set("icon_small", small_icon.spec());
+  dict.Set("icon_small_exists", has_non_default_small_icon);
 
-  value->SetIntKey(
-      "launch_container",
-      static_cast<int>(
-          extensions::AppLaunchInfo::GetLaunchContainer(extension)));
+  dict.Set("launch_container",
+           static_cast<int>(
+               extensions::AppLaunchInfo::GetLaunchContainer(extension)));
   ExtensionPrefs* prefs = ExtensionPrefs::Get(extension_service_->profile());
-  value->SetIntKey("launch_type", extensions::GetLaunchType(prefs, extension));
-  value->SetBoolKey(
-      "is_component",
-      extension->location() == extensions::mojom::ManifestLocation::kComponent);
-  value->SetBoolKey("is_webstore",
-                    extension->id() == extensions::kWebStoreAppId);
+  dict.Set("launch_type", extensions::GetLaunchType(prefs, extension));
+  dict.Set("is_component", extension->location() ==
+                               extensions::mojom::ManifestLocation::kComponent);
+  dict.Set("is_webstore", extension->id() == extensions::kWebStoreAppId);
 
   AppSorting* sorting =
       ExtensionSystem::Get(extension_service_->profile())->app_sorting();
@@ -410,8 +400,7 @@
         sorting->GetNaturalAppPageOrdinal();
     sorting->SetPageOrdinal(extension->id(), page_ordinal);
   }
-  value->SetIntKey("page_index",
-                   sorting->PageStringOrdinalAsInteger(page_ordinal));
+  dict.Set("page_index", sorting->PageStringOrdinalAsInteger(page_ordinal));
 
   syncer::StringOrdinal app_launch_ordinal =
       sorting->GetAppLaunchOrdinal(extension->id());
@@ -424,12 +413,12 @@
         sorting->CreateNextAppLaunchOrdinal(page_ordinal);
     sorting->SetAppLaunchOrdinal(extension->id(), app_launch_ordinal);
   }
-  value->SetStringKey("app_launch_ordinal",
-                      app_launch_ordinal.ToInternalValue());
+  dict.Set("app_launch_ordinal", app_launch_ordinal.ToInternalValue());
 
   // Run on OS Login is not implemented for extension/bookmark apps.
-  value->SetBoolKey("mayShowRunOnOsLoginMode", false);
-  value->SetBoolKey("mayToggleRunOnOsLoginMode", false);
+  dict.Set("mayShowRunOnOsLoginMode", false);
+  dict.Set("mayToggleRunOnOsLoginMode", false);
+  return dict;
 }
 
 // static
@@ -496,6 +485,10 @@
       "runOnOsLogin",
       base::BindRepeating(&AppLauncherHandler::HandleRunOnOsLogin,
                           base::Unretained(this)));
+  web_ui()->RegisterDeprecatedMessageCallback(
+      "deprecatedDialogLinkClicked",
+      base::BindRepeating(&AppLauncherHandler::HandleLaunchDeprecatedAppDialog,
+                          base::Unretained(this)));
 }
 
 void AppLauncherHandler::OnAppsReordered(
@@ -504,9 +497,9 @@
     return;
 
   if (extension_id) {
-    base::DictionaryValue app_info;
+    base::Value::Dict app_info;
     if (web_app_provider_->registrar().IsInstalled(*extension_id)) {
-      CreateWebAppInfo(*extension_id, &app_info);
+      app_info = CreateWebAppInfo(*extension_id);
     } else {
       const Extension* extension =
           ExtensionRegistry::Get(extension_service_->profile())
@@ -516,9 +509,10 @@
         return;
       }
 
-      CreateExtensionInfo(extension, &app_info);
+      app_info = CreateExtensionInfo(extension);
     }
-    web_ui()->CallJavascriptFunctionUnsafe("ntp.appMoved", app_info);
+    web_ui()->CallJavascriptFunctionUnsafe("ntp.appMoved",
+                                           base::Value(std::move(app_info)));
   } else {
     HandleGetApps(nullptr);
   }
@@ -530,13 +524,10 @@
   if (!ShouldShow(extension))
     return;
 
-  std::unique_ptr<base::DictionaryValue> app_info(GetExtensionInfo(extension));
-  if (!app_info.get())
-    return;
-
   visible_apps_.insert(extension->id());
-  web_ui()->CallJavascriptFunctionUnsafe("ntp.appAdded", *app_info,
-                                         /*highlight=*/base::Value(false));
+  web_ui()->CallJavascriptFunctionUnsafe(
+      "ntp.appAdded", base::Value(GetExtensionInfo(extension)),
+      /*highlight=*/base::Value(false));
 }
 
 void AppLauncherHandler::OnExtensionUnloaded(
@@ -554,10 +545,6 @@
 }
 
 void AppLauncherHandler::OnWebAppInstalled(const web_app::AppId& app_id) {
-  std::unique_ptr<base::DictionaryValue> app_info(GetWebAppInfo(app_id));
-  if (!app_info.get())
-    return;
-
   if (attempting_web_app_install_page_ordinal_.has_value()) {
     AppSorting* sorting =
         ExtensionSystem::Get(Profile::FromWebUI(web_ui()))->app_sorting();
@@ -568,7 +555,8 @@
   visible_apps_.insert(app_id);
   base::Value highlight(attempting_web_app_install_page_ordinal_.has_value());
   attempting_web_app_install_page_ordinal_ = absl::nullopt;
-  web_ui()->CallJavascriptFunctionUnsafe("ntp.appAdded", *app_info, highlight);
+  web_ui()->CallJavascriptFunctionUnsafe(
+      "ntp.appAdded", base::Value(CreateWebAppInfo(app_id)), highlight);
 }
 
 void AppLauncherHandler::OnWebAppInstallTimeChanged(
@@ -576,20 +564,19 @@
     const base::Time& time) {
   // Use the appAdded to update the app icon's color to no longer be
   // greyscale.
-  std::unique_ptr<base::DictionaryValue> app_info = GetWebAppInfo(app_id);
-  if (app_info)
-    web_ui()->CallJavascriptFunctionUnsafe("ntp.appAdded", *app_info);
+  web_ui()->CallJavascriptFunctionUnsafe("ntp.appAdded",
+                                         base::Value(CreateWebAppInfo(app_id)));
 }
 
 void AppLauncherHandler::OnWebAppWillBeUninstalled(
     const web_app::AppId& app_id) {
-  std::unique_ptr<base::DictionaryValue> app_info =
-      std::make_unique<base::DictionaryValue>();
-  // Since |isUninstall| is true below, the only item needed in the app_info
+  base::Value::Dict app_info;
+  // Since `isUninstall` is true below, the only item needed in the app_info
   // dictionary is the id.
-  app_info->SetStringKey(kInfoIdKey, app_id);
+  app_info.Set(kInfoIdKey, app_id);
   web_ui()->CallJavascriptFunctionUnsafe(
-      "ntp.appRemoved", *app_info, /*isUninstall=*/base::Value(true),
+      "ntp.appRemoved", base::Value(std::move(app_info)),
+      /*isUninstall=*/base::Value(true),
       base::Value(!extension_id_prompting_.empty()));
 }
 
@@ -599,22 +586,20 @@
   // an app. In this state, the app is still in the registry, but the
   // |OnWebAppWillBeUninstalled| event has already been sent. Thus we also
   // listen to this event, to ensure that the app is removed.
-  std::unique_ptr<base::DictionaryValue> app_info =
-      std::make_unique<base::DictionaryValue>();
-  // Since |isUninstall| is true below, the only item needed in the app_info
+  base::Value::Dict app_info;
+  // Since `isUninstall` is true below, the only item needed in the app_info
   // dictionary is the id.
-  app_info->SetStringKey(kInfoIdKey, app_id);
+  app_info.Set(kInfoIdKey, app_id);
   web_ui()->CallJavascriptFunctionUnsafe(
-      "ntp.appRemoved", *app_info, /*isUninstall=*/base::Value(true),
+      "ntp.appRemoved", base::Value(std::move(app_info)),
+      /*isUninstall=*/base::Value(true),
       base::Value(!extension_id_prompting_.empty()));
 }
 
 void AppLauncherHandler::OnWebAppRunOnOsLoginModeChanged(
     const web_app::AppId& app_id,
     web_app::RunOnOsLoginMode run_on_os_login_mode) {
-  std::unique_ptr<base::DictionaryValue> app_info = GetWebAppInfo(app_id);
-  if (app_info)
-    CallJavascriptFunction("ntp.appAdded", *app_info);
+  CallJavascriptFunction("ntp.appAdded", base::Value(CreateWebAppInfo(app_id)));
 }
 
 void AppLauncherHandler::OnWebAppSettingsPolicyChanged() {
@@ -631,11 +616,11 @@
   install_manager_observation_.Reset();
 }
 
-void AppLauncherHandler::FillAppDictionary(base::DictionaryValue* dictionary) {
+void AppLauncherHandler::FillAppDictionary(base::Value::Dict* dictionary) {
   // CreateExtensionInfo and ClearOrdinals can change the extension prefs.
   base::AutoReset<bool> auto_reset(&ignore_changes_, true);
 
-  auto installed_extensions = std::make_unique<base::ListValue>();
+  base::Value::List installed_extensions;
   Profile* profile = Profile::FromWebUI(web_ui());
   PrefService* prefs = profile->GetPrefs();
 
@@ -647,8 +632,7 @@
     // TODO(crbug.com/1065748): Remove this hack once the youtube app is fixed.
     if (IsYoutubeExtension(web_app_id))
       continue;
-    installed_extensions->Append(
-        base::Value::FromUniquePtrValue(GetWebAppInfo(web_app_id)));
+    installed_extensions.Append(base::Value(CreateWebAppInfo(web_app_id)));
     web_app_ids.insert(web_app_id);
   }
 
@@ -660,43 +644,38 @@
     const Extension* extension = registry->GetInstalledExtension(*it);
     if (extension &&
         extensions::ui_util::ShouldDisplayInNewTabPage(extension, profile)) {
-      installed_extensions->Append(
-          base::Value::FromUniquePtrValue(GetExtensionInfo(extension)));
+      installed_extensions.Append(base::Value(GetExtensionInfo(extension)));
     }
   }
 
   dictionary->Set("apps", std::move(installed_extensions));
+  if (deprecated_app_ids_.size() > 0)
+    dictionary->Set(
+        "deprecatedAppsDialogLinkText",
+        l10n_util::GetPluralStringFUTF16(IDS_DEPRECATED_APPS_DELETION_LINK,
+                                         deprecated_app_ids_.size()));
 
   const base::Value* app_page_names = prefs->GetList(prefs::kNtpAppPageNames);
   if (!app_page_names || !app_page_names->GetListDeprecated().size()) {
     ListPrefUpdate update(prefs, prefs::kNtpAppPageNames);
     base::Value* list = update.Get();
     list->Append(l10n_util::GetStringUTF16(IDS_APP_DEFAULT_PAGE_NAME));
-    dictionary->SetKey("appPageNames", list->Clone());
+    dictionary->Set("appPageNames", list->Clone());
   } else {
-    dictionary->SetKey("appPageNames", app_page_names->Clone());
+    dictionary->Set("appPageNames", app_page_names->Clone());
   }
 }
 
-std::unique_ptr<base::DictionaryValue> AppLauncherHandler::GetExtensionInfo(
+base::Value::Dict AppLauncherHandler::GetExtensionInfo(
     const Extension* extension) {
-  std::unique_ptr<base::DictionaryValue> app_info(new base::DictionaryValue());
   // CreateExtensionInfo can change the extension prefs.
   base::AutoReset<bool> auto_reset(&ignore_changes_, true);
-  CreateExtensionInfo(extension, app_info.get());
-  return app_info;
-}
-
-std::unique_ptr<base::DictionaryValue> AppLauncherHandler::GetWebAppInfo(
-    const web_app::AppId& app_id) {
-  std::unique_ptr<base::DictionaryValue> app_info(new base::DictionaryValue());
-  CreateWebAppInfo(app_id, app_info.get());
-  return app_info;
+  return CreateExtensionInfo(extension);
 }
 
 void AppLauncherHandler::HandleGetApps(const base::ListValue* args) {
   AllowJavascript();
-  base::DictionaryValue dictionary;
+  base::Value::Dict dictionary;
 
   // Tell the client whether to show the promo for this view. We don't do this
   // in the case of PREF_CHANGED because:
@@ -732,7 +711,8 @@
   }
 
   FillAppDictionary(&dictionary);
-  web_ui()->CallJavascriptFunctionUnsafe("ntp.getAppsCallback", dictionary);
+  web_ui()->CallJavascriptFunctionUnsafe("ntp.getAppsCallback",
+                                         base::Value(std::move(dictionary)));
 
   // First time we get here we set up the observer so that we can tell update
   // the apps as they change.
@@ -1233,6 +1213,13 @@
       &web_app_provider_->sync_bridge(), app_id, mode);
 }
 
+void AppLauncherHandler::HandleLaunchDeprecatedAppDialog(
+    const base::ListValue* args) {
+  TabDialogs::FromWebContents(web_ui()->GetWebContents())
+      ->ShowDeprecatedAppsDialog(deprecated_app_ids_,
+                                 web_ui()->GetWebContents());
+}
+
 void AppLauncherHandler::OnFaviconForAppInstallFromLink(
     std::unique_ptr<AppInstallInfo> install_info,
     const favicon_base::FaviconImageResult& image_result) {
@@ -1276,10 +1263,10 @@
 }
 
 void AppLauncherHandler::OnExtensionPreferenceChanged() {
-  base::DictionaryValue dictionary;
+  base::Value::Dict dictionary;
   FillAppDictionary(&dictionary);
   web_ui()->CallJavascriptFunctionUnsafe("ntp.appsPrefChangeCallback",
-                                         dictionary);
+                                         base::Value(std::move(dictionary)));
 }
 
 void AppLauncherHandler::CleanupAfterUninstall() {
@@ -1365,13 +1352,11 @@
   if (!ShouldShow(extension))
     return;
 
-  std::unique_ptr<base::DictionaryValue> app_info(GetExtensionInfo(extension));
-  if (!app_info.get())
-    return;
+  base::Value::Dict app_info(GetExtensionInfo(extension));
 
   web_ui()->CallJavascriptFunctionUnsafe(
-      "ntp.appRemoved", *app_info, base::Value(is_uninstall),
-      base::Value(!extension_id_prompting_.empty()));
+      "ntp.appRemoved", base::Value(std::move(app_info)),
+      base::Value(is_uninstall), base::Value(!extension_id_prompting_.empty()));
 }
 
 bool AppLauncherHandler::ShouldShow(const Extension* extension) {
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.h b/chrome/browser/ui/webui/ntp/app_launcher_handler.h
index 7256608..b2d9d67 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.h
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.h
@@ -74,11 +74,9 @@
 
   ~AppLauncherHandler() override;
 
-  void CreateWebAppInfo(const web_app::AppId& app_id,
-                        base::DictionaryValue* value);
+  base::Value::Dict CreateWebAppInfo(const web_app::AppId& app_id);
 
-  void CreateExtensionInfo(const extensions::Extension* extension,
-                           base::DictionaryValue* value);
+  base::Value::Dict CreateExtensionInfo(const extensions::Extension* extension);
 
   // Registers values (strings etc.) for the page.
   static void RegisterLoadTimeData(Profile* profile,
@@ -120,15 +118,13 @@
   void OnWebAppSettingsPolicyChanged() override;
 
   // Populate the given dictionary with all installed app info.
-  void FillAppDictionary(base::DictionaryValue* value);
+  void FillAppDictionary(base::Value::Dict* value);
 
   // Create a dictionary value for the given extension.
-  std::unique_ptr<base::DictionaryValue> GetExtensionInfo(
-      const extensions::Extension* extension);
+  base::Value::Dict GetExtensionInfo(const extensions::Extension* extension);
 
   // Create a dictionary value for the given web app.
-  std::unique_ptr<base::DictionaryValue> GetWebAppInfo(
-      const web_app::AppId& app_id);
+  base::Value::Dict GetWebAppInfo(const web_app::AppId& app_id);
 
   // Populate the given dictionary with the web store promo content.
   void FillPromoDictionary(base::DictionaryValue* value);
@@ -183,6 +179,9 @@
   // Handles "runOnOsLogin" message with |args| containing [app_id, mode]
   void HandleRunOnOsLogin(const base::ListValue* args);
 
+  // Handles "deprecatedDialogLinkClicked" message with no |args|
+  void HandleLaunchDeprecatedAppDialog(const base::ListValue* args);
+
  private:
   FRIEND_TEST_ALL_PREFIXES(AppLauncherHandlerTest,
                            HandleClosedWhileUninstallingExtension);
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.cc b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
index f168aee..ca7b065 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.cc
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/feature_list.h"
@@ -102,10 +103,10 @@
 }
 
 // static
-void NewTabUI::SetUrlTitleAndDirection(base::Value* dictionary,
+void NewTabUI::SetUrlTitleAndDirection(base::Value::Dict* dictionary,
                                        const std::u16string& title,
                                        const GURL& gurl) {
-  dictionary->SetStringKey("url", gurl.spec());
+  dictionary->Set("url", gurl.spec());
 
   bool using_url_as_the_title = false;
   std::u16string title_to_set(title);
@@ -131,16 +132,15 @@
   else
     direction = GetHtmlTextDirection(title);
 
-  dictionary->SetStringKey("title", title_to_set);
-  dictionary->SetStringKey("direction", direction);
+  dictionary->Set("title", title_to_set);
+  dictionary->Set("direction", direction);
 }
 
 // static
 void NewTabUI::SetFullNameAndDirection(const std::u16string& full_name,
-                                       base::DictionaryValue* dictionary) {
-  dictionary->SetStringKey("full_name", full_name);
-  dictionary->SetStringKey("full_name_direction",
-                           GetHtmlTextDirection(full_name));
+                                       base::Value::Dict* dictionary) {
+  dictionary->Set("full_name", full_name);
+  dictionary->Set("full_name_direction", GetHtmlTextDirection(full_name));
 }
 
 Profile* NewTabUI::GetProfile() const {
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.h b/chrome/browser/ui/webui/ntp/new_tab_ui.h
index 70bf1ca..b812ddb0 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.h
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.h
@@ -8,17 +8,13 @@
 #include <string>
 
 #include "base/memory/raw_ptr.h"
+#include "base/values.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_ui_controller.h"
 
 class GURL;
 class Profile;
 
-namespace base {
-class DictionaryValue;
-class Value;
-}
-
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
@@ -44,13 +40,13 @@
 
   // Adds "url", "title", and "direction" keys on incoming dictionary, setting
   // title as the url as a fallback on empty title.
-  static void SetUrlTitleAndDirection(base::Value* dictionary,
+  static void SetUrlTitleAndDirection(base::Value::Dict* dictionary,
                                       const std::u16string& title,
                                       const GURL& gurl);
 
   // Adds "full_name" and "full_name_direction" keys on incoming dictionary.
   static void SetFullNameAndDirection(const std::u16string& full_name,
-                                      base::DictionaryValue* dictionary);
+                                      base::Value::Dict* dictionary);
 
  private:
   class NewTabHTMLSource : public content::URLDataSource {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
index 716bed9..c25c79e 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
@@ -148,8 +148,10 @@
 
 UserActionBuckets GetUserActionForPrinterType(mojom::PrinterType type) {
   switch (type) {
-    case mojom::PrinterType::kPrivet:
-      return UserActionBuckets::kPrintWithPrivet;
+    case mojom::PrinterType::kPrivetDeprecated:
+      NOTREACHED();
+      // Return value doesn't matter.
+      return UserActionBuckets::kPrintToPrinter;
     case mojom::PrinterType::kExtension:
       return UserActionBuckets::kPrintWithExtension;
     case mojom::PrinterType::kPdf:
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_metrics.h b/chrome/browser/ui/webui/print_preview/print_preview_metrics.h
index 69b7d01..9914b8d 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_metrics.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_metrics.h
@@ -65,7 +65,7 @@
   // kInitiatorCrashed = 6,  // no longer used
   kInitiatorClosed = 7,
   kPrintWithCloudPrint = 8,
-  kPrintWithPrivet = 9,
+  // kPrintWithPrivet = 9,  // no longer used
   kPrintWithExtension = 10,
   kOpenInMacPreview = 11,
   kPrintToGoogleDrive = 12,
diff --git a/chrome/browser/ui/webui/read_later/side_panel/read_anything/read_anything_toolbar_view.cc b/chrome/browser/ui/webui/read_later/side_panel/read_anything/read_anything_toolbar_view.cc
index 55e328f..c139c82 100644
--- a/chrome/browser/ui/webui/read_later/side_panel/read_anything/read_anything_toolbar_view.cc
+++ b/chrome/browser/ui/webui/read_later/side_panel/read_anything/read_anything_toolbar_view.cc
@@ -43,6 +43,8 @@
                           weak_pointer_factory_.GetWeakPtr());
   auto settings_button =
       views::CreateVectorImageButton(std::move(settings_callback));
+  // TODO(1266555): This is placeholder text, remove for final UI.
+  settings_button->SetTooltipText(u"Settings");
   views::SetImageFromVectorIcon(settings_button.get(),
                                 vector_icons::kSettingsIcon, kIconSize,
                                 SK_ColorBLACK);
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/BUILD.gn b/chrome/browser/ui/webui/settings/chromeos/constants/BUILD.gn
index f3a31510..24ae25d 100644
--- a/chrome/browser/ui/webui/settings/chromeos/constants/BUILD.gn
+++ b/chrome/browser/ui/webui/settings/chromeos/constants/BUILD.gn
@@ -5,7 +5,7 @@
 import("//build/config/chromeos/ui_mode.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 
-assert(is_chromeos_ash || is_chromeos_lacros)
+assert(is_chromeos)
 
 mojom("mojom") {
   sources = [
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 34663f0..988d160 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -176,7 +176,7 @@
     "web_launch_params_helper.h",
   ]
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [
       "os_integration/web_app_run_on_os_login_chromeos.cc",
       "os_integration/web_app_shortcut_chromeos.cc",
@@ -541,7 +541,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [ "system_web_apps/test/system_web_app_manager_unittest.cc" ]
   }
 
@@ -650,7 +650,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [
       "policy/web_app_policy_manager_browsertest.cc",
       "system_web_apps/test/system_web_app_manager_browsertest.cc",
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 032075b2..d0f2f22 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1648641295-f30dffaa596def0938cb84c44564286e059323c2.profdata
+chrome-mac-arm-main-1648663201-9213dc330dbba935a0c87313bc668ea48151b54a.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 87c7bd9..73ce129 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1648641295-7aa5b80d8c79d0767329212546548814a91d97a2.profdata
+chrome-mac-main-1648663201-ff158ea04e14738165acabb765bc7b23caac5cc5.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index e9e752d..d5b55fbe 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1648652301-51151b175caff5d75f9cde6bf03d11a1ff904184.profdata
+chrome-win32-main-1648663201-5c163365937a17e237d6c061db3bdef1b7c4378b.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index bc5f99f..b738faf 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1648652301-f7d00113743c8e2bae8f2eddf74ead050253eae4.profdata
+chrome-win64-main-1648673977-83cc95cfc73acbe8de8911aff70527fdb30e60e1.profdata
diff --git a/chrome/common/extensions/api/BUILD.gn b/chrome/common/extensions/api/BUILD.gn
index bd52a16..65b9f44 100644
--- a/chrome/common/extensions/api/BUILD.gn
+++ b/chrome/common/extensions/api/BUILD.gn
@@ -57,7 +57,7 @@
     "tts.json",
     "tts_engine.json",
   ]
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [ "file_browser_handler.json" ]
   }
   if (!is_chromeos_ash) {
diff --git a/chrome/common/features.gni b/chrome/common/features.gni
index 282b8cc7..5b4d72b 100644
--- a/chrome/common/features.gni
+++ b/chrome/common/features.gni
@@ -65,7 +65,7 @@
 
   # Enables supervision for Family Link users.
   # Supervision is only supported on Chrome OS and Android.
-  enable_supervised_users = is_chromeos_ash || is_chromeos_lacros || is_android
+  enable_supervised_users = is_chromeos || is_android
 
   # Enables usage of the system-provided notification center.
   enable_system_notifications =
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index bb86b93c..6345cbbf 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1930,6 +1930,10 @@
 const char kNtpModulesOrder[] = "NewTabPage.ModulesOrder";
 // Whether NTP modules are visible.
 const char kNtpModulesVisible[] = "NewTabPage.ModulesVisible";
+// Number of times user has seen an NTP module.
+const char kNtpModulesShownCount[] = "NewTabPage.ModulesShownCount";
+// Time modules were first shown to user.
+const char kNtpModulesFirstShownTime[] = "NewTabPage.ModulesFirstShownTime";
 // Time Modular NTP Desktop v1 First Run Experience was first shown to user.
 const char kNtpModulesFreFirstShownTime[] =
     "NewTabPage.ModulesFreFirstShownTime";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 42fc5c6..050a65d4 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -645,6 +645,8 @@
 extern const char kNtpDisabledModules[];
 extern const char kNtpModulesOrder[];
 extern const char kNtpModulesVisible[];
+extern const char kNtpModulesShownCount[];
+extern const char kNtpModulesFirstShownTime[];
 extern const char kNtpModulesFreFirstShownTime[];
 extern const char kNtpModulesFreVisible[];
 extern const char kNtpModulesFreShownCount[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index abba276..1c35721 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1224,6 +1224,7 @@
       "//components/cast_channel",
       "//components/cbor",
       "//components/certificate_transparency",
+      "//components/certificate_transparency:proto",
       "//components/commerce/core:feature_list",
       "//components/constrained_window",
       "//components/content_settings/browser",
@@ -1646,6 +1647,7 @@
       "../browser/chrome_worker_browsertest.cc",
       "../browser/client_hints/client_hints_browsertest.cc",
       "../browser/component_updater/component_patcher_operation_browsertest.cc",
+      "../browser/component_updater/pki_metadata_component_installer_browsertest.cc",
       "../browser/content_index/content_index_browsertest.cc",
       "../browser/content_language/content_language_browsertest.cc",
       "../browser/content_settings/mixed_content_settings_tab_helper_browsertest.cc",
@@ -6536,6 +6538,7 @@
       "../browser/ui/toolbar/toolbar_actions_model_unittest.cc",
       "../browser/ui/user_education/active_tab_tracker_unittest.cc",
       "../browser/ui/user_education/help_bubble_factory_registry_unittest.cc",
+      "../browser/ui/user_education/interaction_sequence_browser_util_unittest.cc",
       "../browser/ui/user_education/mock_feature_promo_controller.cc",
       "../browser/ui/user_education/mock_feature_promo_controller.h",
       "../browser/ui/user_education/reopen_tab_in_product_help_trigger_unittest.cc",
@@ -7727,7 +7730,7 @@
 
       deps += [ "//components/enterprise:test_support" ]
     }
-    if (!is_chromeos_ash && !is_chromeos_lacros && !is_fuchsia) {
+    if (!is_chromeos && !is_fuchsia) {
       sources += [
         "../browser/extensions/api/messaging/native_message_process_host_unittest.cc",
         "../browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc",
@@ -9957,7 +9960,7 @@
   # and only works on Google Chrome branded builds.
   # The connectors file system interactive tests are not supported on
   # ASH and LaCros.
-  if (is_chrome_branded && !is_chromeos_ash && !is_chromeos_lacros) {
+  if (is_chrome_branded && !is_chromeos) {
     test("enterprise_connector_file_system_interactive_tests") {
       use_xvfb = use_xvfb_in_this_config
       sources = [
diff --git a/chrome/test/data/extensions/api_test/favicon/extension/test.js b/chrome/test/data/extensions/api_test/favicon/extension/test.js
index f5676b5..00b1af2 100644
--- a/chrome/test/data/extensions/api_test/favicon/extension/test.js
+++ b/chrome/test/data/extensions/api_test/favicon/extension/test.js
@@ -2,20 +2,37 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+let url;
+
 window.onload = function() {
-  chrome.test.runTests([async function favicon() {
-    const img = document.createElement('img');
-    document.body.appendChild(img);
-    const config = await chrome.test.getConfig();
-    const port = config.testServer.port;
-    const id = chrome.runtime.id;
-    const pageUrl =
-        `http://chromium.org:{port}/extensions/favicon/test_file.html`;
-    // TODO(solomonkinard): Currently, fetching favicons in this way isn't
-    // supported. Adjust this test once it is. In the meantime, we verify that
-    // the load fails as expected.
-    img.onload = () => chrome.test.fail('Image loaded unexpectedly!');
-    img.onerror = () => chrome.test.succeed();
-    img.src = `chrome-extension://${id}/_favicon/?page_url=${pageUrl}`;
-  }]);
+  chrome.test.runTests([
+    async function init() {
+      const config = await chrome.test.getConfig();
+      const port = config.testServer.port;
+      const id = chrome.runtime.id;
+      const pageUrl =
+          `http://chromium.org:${port}/extensions/favicon/test_file.html`;
+      url = `chrome-extension://${id}/_favicon/?page_url=${pageUrl}`;
+      chrome.test.succeed();
+    },
+    function image() {
+      const img = document.createElement('img');
+      document.body.appendChild(img);
+      // TODO(solomonkinard): Currently, fetching favicons in this way isn't
+      // supported. Adjust this test once it is. In the meantime, we verify that
+      // the load fails as expected.
+      img.onload = () => chrome.test.fail('Image loaded unexpectedly!');
+      img.onerror = () => chrome.test.succeed();
+      img.src = url;
+    },
+    async function path() {
+      const response = await fetch(url);
+      const text = await response.text();
+      // TODO(solomonkinard): This case extension can be removed once the
+      // _favicon endpoint returns the image bits. This test exists for now
+      // to prove that the _favicon endpoint is being reached.
+      chrome.test.assertEq('Favicon', text);
+      chrome.test.succeed();
+    }
+  ]);
 };
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 036b01b..94ececd8f 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -318,13 +318,7 @@
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/guest_os_shared_usb_devices_test.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/input_method_options_page_test.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/input_page_test.m.js",
-        "$root_gen_dir/chrome/test/data/webui/settings/chromeos/internet_config_test.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/onc_mojo_test.m.js",
-        "$root_gen_dir/chrome/test/data/webui/settings/chromeos/internet_detail_menu_test.m.js",
-        "$root_gen_dir/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.m.js",
-        "$root_gen_dir/chrome/test/data/webui/settings/chromeos/internet_known_networks_page_tests.m.js",
-        "$root_gen_dir/chrome/test/data/webui/settings/chromeos/internet_subpage_tests.m.js",
-        "$root_gen_dir/chrome/test/data/webui/settings/chromeos/internet_page_tests.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/kerberos_accounts_test.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/kerberos_page_test.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/keyboard_shortcut_banner_test.m.js",
@@ -371,7 +365,6 @@
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_cups_printers_browser_proxy.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_guest_os_browser_proxy.m.js",
-        "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_internet_page_browser_proxy.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_os_languages_browser_proxy.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_kerberos_accounts_browser_proxy.m.js",
         "$root_gen_dir/chrome/test/data/webui/settings/chromeos/test_os_languages_metrics_proxy.m.js",
diff --git a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
index eb14243..195b380 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/ambient_subpage_element_test.ts
@@ -76,10 +76,56 @@
     personalizationStore.notifyObservers();
     await waitAfterNextRender(ambientSubpageElement);
 
-    let spinner =
-        ambientSubpageElement.shadowRoot!.querySelector('paper-spinner-lite');
-    assertTrue(!!spinner, 'paper-spinner-lite element exists');
-    assertTrue(spinner.active, 'paper-spinner-lite is active');
+    // Preview element should show placeholders for preview images, preview
+    // album info and preview album collage.
+    const ambientPreview =
+        ambientSubpageElement.shadowRoot!.querySelector('ambient-preview');
+    assertTrue(!!ambientPreview, 'ambient-preview element exists');
+
+    const previewImagePlaceholder =
+        ambientPreview.shadowRoot!.querySelector('#imagePlaceholder');
+    assertTrue(!!previewImagePlaceholder);
+
+    const previewTextPlaceholder =
+        ambientPreview.shadowRoot!.querySelector('#textPlaceholder');
+    assertTrue(!!previewTextPlaceholder);
+
+    const previewItemPlaceholders =
+        ambientPreview.shadowRoot!.querySelectorAll('.placeholder');
+    assertEquals(5, previewItemPlaceholders!.length);
+
+    // Should show image placeholders for the 3 theme items.
+    const animationThemePlaceholder =
+        ambientSubpageElement.shadowRoot!.querySelector(
+            '#animationThemePlaceholder');
+    assertTrue(!!animationThemePlaceholder);
+
+    const animationItemPlaceholders =
+        ambientSubpageElement!.shadowRoot!.querySelectorAll(
+            '.animation-placeholder-container:not([hidden])');
+    assertEquals(3, animationItemPlaceholders!.length);
+
+    // Should show placeholders for the 2 topic source radio buttons.
+    const topicSourcePlaceholder =
+        ambientSubpageElement.shadowRoot!.querySelector(
+            '#topicSourcePlaceholder');
+    assertTrue(!!topicSourcePlaceholder);
+
+    const topicSourceItemPlaceholders =
+        ambientSubpageElement.shadowRoot!.querySelectorAll(
+            '#topicSourceTextPlaceholder:not([hidden])');
+    assertEquals(2, topicSourceItemPlaceholders!.length);
+
+    // Should show placeholders for 2 weather unit radio buttons.
+    const weatherUnitPlaceholder =
+        ambientSubpageElement.shadowRoot!.querySelector(
+            '#weatherUnitPlaceholder');
+    assertTrue(!!weatherUnitPlaceholder);
+
+    const weatherUnitItemPlaceholders =
+        ambientSubpageElement.shadowRoot!.querySelectorAll(
+            '#weatherUnitTextPlaceholder:not([hidden])');
+    assertEquals(2, weatherUnitItemPlaceholders!.length);
 
     personalizationStore.data.ambient.albums = ambientProvider.albums;
     personalizationStore.data.ambient.topicSource = TopicSource.kGooglePhotos;
@@ -88,18 +134,22 @@
     personalizationStore.notifyObservers();
     await waitAfterNextRender(ambientSubpageElement);
 
-    spinner =
-        ambientSubpageElement.shadowRoot!.querySelector('paper-spinner-lite');
-    assertTrue(!!spinner, 'paper-spinner-lite still exists');
-    assertEquals(getComputedStyle(spinner).display, 'none');
+    // Placeholders will be hidden for preview, animation theme, topic source
+    // and temperature unit elements.
+    assertTrue(!!previewImagePlaceholder);
+    assertEquals(getComputedStyle(previewImagePlaceholder).display, 'none');
 
-    const topicSource =
-        ambientSubpageElement.shadowRoot!.querySelector('topic-source-list');
-    assertTrue(!!topicSource, 'topic-source-list element exists');
+    assertTrue(!!previewTextPlaceholder);
+    assertEquals(getComputedStyle(previewTextPlaceholder).display, 'none');
 
-    const weatherUnit =
-        ambientSubpageElement.shadowRoot!.querySelector('ambient-weather-unit');
-    assertTrue(!!weatherUnit);
+    assertTrue(!!animationThemePlaceholder);
+    assertEquals(getComputedStyle(animationThemePlaceholder).display, 'none');
+
+    assertTrue(!!topicSourcePlaceholder);
+    assertEquals(getComputedStyle(topicSourcePlaceholder).display, 'none');
+
+    assertTrue(!!weatherUnitPlaceholder);
+    assertEquals(getComputedStyle(weatherUnitPlaceholder).display, 'none');
   });
 
   test('sets ambient mode enabled in store on first load', async () => {
diff --git a/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts b/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts
index a0515e7..011cada 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/test_wallpaper_interface_provider.ts
@@ -42,12 +42,20 @@
       {
         id: 'id_0',
         name: 'zero',
-        preview: {url: 'https://collections.googleusercontent.com/0'}
+        previews: [{url: 'https://collections.googleusercontent.com/0'}]
       },
       {
         id: 'id_1',
         name: 'one',
-        preview: {url: 'https://collections.googleusercontent.com/1'}
+        previews: [{url: 'https://collections.googleusercontent.com/1'}]
+      },
+      {
+        id: 'id_2',
+        name: 'dark-light',
+        previews: [
+          {url: 'https://collections.googleusercontent.com/2'},
+          {url: 'https://collections.googleusercontent.com/3'}
+        ]
       },
     ];
 
diff --git a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.ts b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.ts
index 6aec1ab..39d3253 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.ts
+++ b/chrome/test/data/webui/chromeos/personalization_app/wallpaper_collections_element_test.ts
@@ -287,6 +287,7 @@
           images: {
             'id_0': wallpaperProvider.images,
             'id_1': wallpaperProvider.images,
+            'id_2': wallpaperProvider.images,
           },
         },
         personalizationStore.data.wallpaper.backdrop,
@@ -299,6 +300,7 @@
           images: {
             'id_0': false,
             'id_1': false,
+            'id_2': false,
           },
         },
         personalizationStore.data.wallpaper.loading,
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index 6182fc8..db6bd233 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -130,7 +130,7 @@
   "zoom_levels_tests.ts",
 ]
 
-if (!is_chromeos_ash && !is_chromeos_lacros) {
+if (!is_chromeos) {
   non_preprocessed_files += [
     "default_browser_test.ts",
     "import_data_dialog_test.ts",
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn
index 79841a0..d86928c0 100644
--- a/chrome/test/data/webui/settings/chromeos/BUILD.gn
+++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -88,12 +88,6 @@
     "guest_os_shared_usb_devices_test.js",
     "input_method_options_page_test.js",
     "input_page_test.js",
-    "internet_config_test.js",
-    "internet_detail_menu_test.js",
-    "internet_detail_page_tests.js",
-    "internet_known_networks_page_tests.js",
-    "internet_page_tests.js",
-    "internet_subpage_tests.js",
     "kerberos_accounts_test.js",
     "kerberos_page_test.js",
     "keyboard_shortcut_banner_test.js",
@@ -143,7 +137,6 @@
     "test_device_name_browser_proxy.js",
     "test_guest_os_browser_proxy.js",
     "test_kerberos_accounts_browser_proxy.js",
-    "test_internet_page_browser_proxy.js",
     "test_os_languages_browser_proxy.js",
     "test_os_languages_metrics_proxy.js",
     "test_os_lifetime_browser_proxy.js",
diff --git a/chrome/test/data/webui/settings/chromeos/internet_config_test.js b/chrome/test/data/webui/settings/chromeos/internet_config_test.js
index 7af0bb4..ca53830 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_config_test.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_config_test.js
@@ -2,16 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// clang-format off
-// #import 'chrome://os-settings/chromeos/os_settings.js';
+import {setUserActionRecorderForTesting} from 'chrome://os-settings/chromeos/os_settings.js';
+import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
+import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
 
-// #import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
-// #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
-// #import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
-// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-// #import {FakeUserActionRecorder} from './fake_user_action_recorder.m.js';
-// #import {setUserActionRecorderForTesting} from 'chrome://os-settings/chromeos/os_settings.js';
-// clang-format on
+import {FakeUserActionRecorder} from './fake_user_action_recorder.m.js';
 
 suite('InternetConfig', function() {
   /** @type {!InternetConfig|undefined} */
@@ -25,7 +22,7 @@
 
   suiteSetup(function() {
     mojoApi_ = new FakeNetworkConfig();
-    network_config.MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
+    MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
   });
 
   setup(function() {
@@ -33,10 +30,10 @@
     internetConfig.type = OncMojo.getNetworkTypeString(
         chromeos.networkConfig.mojom.NetworkType.kWiFi);
     document.body.appendChild(internetConfig);
-    Polymer.dom.flush();
+    flush();
 
-    userActionRecorder = new settings.FakeUserActionRecorder();
-    settings.setUserActionRecorderForTesting(userActionRecorder);
+    userActionRecorder = new FakeUserActionRecorder();
+    setUserActionRecorderForTesting(userActionRecorder);
   });
 
   test('Cancel button closes the dialog', function() {
@@ -50,11 +47,11 @@
   test('Connect button click increments settings change count', function() {
     internetConfig.open();
     internetConfig.showConnect = true;
-    Polymer.dom.flush();
+    flush();
 
     const connectBtn = internetConfig.$$('#connectButton');
     connectBtn.disabled = false;
-    Polymer.dom.flush();
+    flush();
 
     assertFalse(connectBtn.disabled);
     assertEquals(userActionRecorder.settingChangeCount, 0);
@@ -65,11 +62,11 @@
   test('Save button click increments settings change count', function() {
     internetConfig.open();
     internetConfig.showConnect = false;
-    Polymer.dom.flush();
+    flush();
 
     const saveBtn = internetConfig.$$('#saveButton');
     saveBtn.disabled = false;
-    Polymer.dom.flush();
+    flush();
 
     assertFalse(saveBtn.disabled);
     assertEquals(userActionRecorder.settingChangeCount, 0);
diff --git a/chrome/test/data/webui/settings/chromeos/internet_detail_menu_test.js b/chrome/test/data/webui/settings/chromeos/internet_detail_menu_test.js
index 45b0017..20ce1d8 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_detail_menu_test.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_detail_menu_test.js
@@ -2,20 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// clang-format off
-// #import 'chrome://os-settings/chromeos/os_settings.js';
+import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {setESimManagerRemoteForTesting} from 'chrome://resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.m.js';
+import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
+import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
+import {FakeESimManagerRemote} from 'chrome://test/cr_components/chromeos/cellular_setup/fake_esim_manager_remote.m.js';
+import {eventToPromise, flushTasks, waitAfterNextRender} from 'chrome://test/test_util.js';
 
-// #import {routes, Router} from 'chrome://os-settings/chromeos/os_settings.js';
-// #import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
-// #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
-// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-// #import {assertEquals, assertTrue} from '../../chai_assert.js';
-// #import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
-// #import {eventToPromise, flushTasks, waitAfterNextRender} from 'chrome://test/test_util.js';
-// #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
-// #import {setESimManagerRemoteForTesting} from 'chrome://resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.m.js';
-// #import {FakeESimManagerRemote} from 'chrome://test/cr_components/chromeos/cellular_setup/fake_esim_manager_remote.m.js';
-// clang-format on
+import {assertEquals, assertTrue} from '../../chai_assert.js';
 
 suite('InternetDetailMenu', function() {
   let internetDetailMenu;
@@ -25,11 +22,11 @@
 
   setup(function() {
     mojoApi_ = new FakeNetworkConfig();
-    network_config.MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
+    MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
     mojoApi_.resetForTest();
 
-    eSimManagerRemote = new cellular_setup.FakeESimManagerRemote();
-    cellular_setup.setESimManagerRemoteForTesting(eSimManagerRemote);
+    eSimManagerRemote = new FakeESimManagerRemote();
+    setESimManagerRemoteForTesting(eSimManagerRemote);
 
     mojom = chromeos.networkConfig.mojom;
     mojoApi_.setNetworkTypeEnabledState(mojom.NetworkType.kCellular, true);
@@ -53,8 +50,7 @@
 
     const params = new URLSearchParams;
     params.append('guid', 'cellular_guid');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
     internetDetailMenu =
         document.createElement('settings-internet-detail-menu');
@@ -86,10 +82,9 @@
     const params = new URLSearchParams;
     params.append('guid', 'cellular_guid');
     params.append('settingId', deepLinkId);
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
-    await test_util.waitAfterNextRender(internetDetailMenu);
+    await waitAfterNextRender(internetDetailMenu);
     const actionMenu =
         internetDetailMenu.shadowRoot.querySelector('cr-action-menu');
     assertTrue(!!actionMenu);
@@ -97,12 +92,12 @@
     const deepLinkElement = actionMenu.querySelector(`#${elementId}`);
     assertTrue(!!deepLinkElement);
 
-    await test_util.waitAfterNextRender(deepLinkElement);
+    await waitAfterNextRender(deepLinkElement);
     assertEquals(deepLinkElement, getDeepActiveElement());
   }
 
   function flushAsync() {
-    Polymer.dom.flush();
+    flush();
     // Use setTimeout to wait for the next macrotask.
     return new Promise(resolve => setTimeout(resolve));
   }
@@ -130,8 +125,7 @@
 
     const params = new URLSearchParams;
     params.append('guid', 'cellular_guid');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
     await flushAsync();
     tripleDot = internetDetailMenu.$$('#moreNetworkDetail');
@@ -149,8 +143,7 @@
 
     const params = new URLSearchParams;
     params.append('guid', 'cellular_guid');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
     await flushAsync();
     tripleDot = internetDetailMenu.$$('#moreNetworkDetail');
@@ -163,8 +156,7 @@
 
     const params = new URLSearchParams;
     params.append('guid', 'cellular_guid');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
     await flushAsync();
 
     // Has ICCID and EID, but not shown since the user is in guest mode.
@@ -177,8 +169,7 @@
 
     const params = new URLSearchParams;
     params.append('guid', 'cellular_guid');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
     await flushAsync();
     const tripleDot = internetDetailMenu.$$('#moreNetworkDetail');
@@ -195,10 +186,10 @@
     const renameBtn = actionMenu.querySelector('#renameBtn');
     assertTrue(!!renameBtn);
 
-    const renameProfilePromise = test_util.eventToPromise(
-        'show-esim-profile-rename-dialog', internetDetailMenu);
+    const renameProfilePromise =
+        eventToPromise('show-esim-profile-rename-dialog', internetDetailMenu);
     renameBtn.click();
-    await Promise.all([renameProfilePromise, test_util.flushTasks()]);
+    await Promise.all([renameProfilePromise, flushTasks()]);
 
     assertFalse(actionMenu.open);
   });
@@ -209,8 +200,7 @@
 
     const params = new URLSearchParams;
     params.append('guid', 'cellular_guid');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
     await flushAsync();
     const tripleDot = internetDetailMenu.$$('#moreNetworkDetail');
@@ -227,10 +217,10 @@
     const removeBtn = actionMenu.querySelector('#removeBtn');
     assertTrue(!!removeBtn);
 
-    const removeProfilePromise = test_util.eventToPromise(
-        'show-esim-remove-profile-dialog', internetDetailMenu);
+    const removeProfilePromise =
+        eventToPromise('show-esim-remove-profile-dialog', internetDetailMenu);
     removeBtn.click();
-    await Promise.all([removeProfilePromise, test_util.flushTasks()]);
+    await Promise.all([removeProfilePromise, flushTasks()]);
 
     assertFalse(actionMenu.open);
   });
@@ -241,8 +231,7 @@
 
     const params = new URLSearchParams;
     params.append('guid', 'cellular_guid');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
     await flushAsync();
     const tripleDot = internetDetailMenu.$$('#moreNetworkDetail');
@@ -271,8 +260,7 @@
 
     const params = new URLSearchParams;
     params.append('guid', 'cellular_guid');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
     await flushAsync();
     const tripleDot = internetDetailMenu.$$('#moreNetworkDetail');
@@ -318,7 +306,7 @@
         const renameBtn = actionMenu.querySelector('#renameBtn');
         assertTrue(!!renameBtn);
 
-        const renameProfilePromise = test_util.eventToPromise(
+        const renameProfilePromise = eventToPromise(
             'show-esim-profile-rename-dialog', internetDetailMenu);
         renameBtn.click();
         const event = await renameProfilePromise;
diff --git a/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js b/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js
index 5fa3cb1..9fb50821 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_detail_page_tests.js
@@ -2,19 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// clang-format off
-// #import 'chrome://os-settings/chromeos/os_settings.js';
+import {InternetPageBrowserProxyImpl, Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
+import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
+import {eventToPromise, waitAfterNextRender} from 'chrome://test/test_util.js';
 
-// #import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
-// #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
-// #import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
-// #import {TestInternetPageBrowserProxy} from './test_internet_page_browser_proxy.m.js';
-// #import {InternetPageBrowserProxyImpl} from 'chrome://os-settings/chromeos/os_settings.js';
-// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-// #import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
-// #import {waitAfterNextRender, eventToPromise} from 'chrome://test/test_util.js';
-// #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
-// clang-format on
+import {TestInternetPageBrowserProxy} from './test_internet_page_browser_proxy.js';
 
 suite('InternetDetailPage', function() {
   /** @type {InternetDetailPageElement} */
@@ -63,14 +59,14 @@
 
   suiteSetup(function() {
     mojoApi_ = new FakeNetworkConfig();
-    network_config.MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
+    MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
 
     // Disable animations so sub-pages open within one event loop.
     testing.Test.disableAnimationsAndTransitions();
   });
 
   function flushAsync() {
-    Polymer.dom.flush();
+    flush();
     // Use setTimeout to wait for the next macrotask.
     return new Promise(resolve => setTimeout(resolve));
   }
@@ -135,8 +131,7 @@
     params.append('type', 'Cellular');
     params.append('name', 'cellular');
     params.append('settingId', '14');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
     return flushAsync();
   }
@@ -161,7 +156,7 @@
     mojoApi_.resetForTest();
 
     browserProxy = new TestInternetPageBrowserProxy();
-    settings.InternetPageBrowserProxyImpl.instance_ = browserProxy;
+    InternetPageBrowserProxyImpl.instance_ = browserProxy;
 
     return flushAsync();
   });
@@ -171,7 +166,7 @@
       internetDetailPage.close();
       internetDetailPage.remove();
       internetDetailPage = null;
-      settings.Router.getInstance().resetRouteForTesting();
+      Router.getInstance().resetRouteForTesting();
     });
   });
 
@@ -395,15 +390,14 @@
       params.append('type', 'WiFi');
       params.append('name', 'wifi_device');
       params.append('settingId', '11');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.NETWORK_DETAIL, params);
+      Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
       await flushAsync();
 
       const deepLinkElement = internetDetailPage.$$('network-proxy-section')
                                   .$$('#allowShared')
                                   .shadowRoot.querySelector('#control');
-      await test_util.waitAfterNextRender(deepLinkElement);
+      await waitAfterNextRender(deepLinkElement);
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
           'Allow shared proxy toggle should be focused for settingId=11.');
@@ -761,7 +755,7 @@
     test('Deep link to disconnect button', async () => {
       // Add listener for popstate event fired when the dialog closes and the
       // router navigates backwards.
-      const popStatePromise = test_util.eventToPromise('popstate', window);
+      const popStatePromise = eventToPromise('popstate', window);
 
       init();
       const mojom = chromeos.networkConfig.mojom;
@@ -776,14 +770,13 @@
       params.append('type', 'Cellular');
       params.append('name', 'cellular');
       params.append('settingId', '17');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.NETWORK_DETAIL, params);
+      Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
       await flushAsync();
 
       const deepLinkElement =
           getButton('connectDisconnect').shadowRoot.querySelector('cr-button');
-      await test_util.waitAfterNextRender(deepLinkElement);
+      await waitAfterNextRender(deepLinkElement);
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
           'Disconnect network button should be focused for settingId=17.');
@@ -827,15 +820,14 @@
       params.append('type', 'Cellular');
       params.append('name', 'cellular');
       params.append('settingId', '15');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.NETWORK_DETAIL, params);
+      Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
       await flushAsync();
 
       const deepLinkElement =
           internetDetailPage.$$('cellular-roaming-toggle-button')
               .getCellularRoamingToggle();
-      await test_util.waitAfterNextRender(deepLinkElement);
+      await waitAfterNextRender(deepLinkElement);
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
           'Cellular roaming toggle button should be focused for settingId=15.');
@@ -848,8 +840,8 @@
 
       // In this rare case, wait after next render twice due to focus behavior
       // of the siminfo component.
-      await test_util.waitAfterNextRender(simInfo);
-      await test_util.waitAfterNextRender(simInfo);
+      await waitAfterNextRender(simInfo);
+      await waitAfterNextRender(simInfo);
       assertEquals(
           simInfo.$$('#simLockButton'), getDeepActiveElement(),
           'Sim lock toggle should be focused for settingId=14.');
@@ -862,8 +854,8 @@
 
       // In this rare case, wait after next render twice due to focus behavior
       // of the siminfo component.
-      await test_util.waitAfterNextRender(simInfo);
-      await test_util.waitAfterNextRender(simInfo);
+      await waitAfterNextRender(simInfo);
+      await waitAfterNextRender(simInfo);
       assertEquals(
           simInfo.$$('#unlockPinButton'), getDeepActiveElement(),
           'Sim unlock button should be focused for settingId=14.');
@@ -1271,13 +1263,12 @@
       params.append('type', 'Ethernet');
       params.append('name', 'eth1');
       params.append('settingId', '0');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.NETWORK_DETAIL, params);
+      Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
       await flushAsync();
 
       const deepLinkElement = getButton('configureButton');
-      await test_util.waitAfterNextRender(deepLinkElement);
+      await waitAfterNextRender(deepLinkElement);
 
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
@@ -1337,14 +1328,13 @@
       params.append('type', 'Tether');
       params.append('name', 'tether1');
       params.append('settingId', '23');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.NETWORK_DETAIL, params);
+      Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
 
       await flushAsync();
 
       const deepLinkElement =
           getButton('connectDisconnect').shadowRoot.querySelector('cr-button');
-      await test_util.waitAfterNextRender(deepLinkElement);
+      await waitAfterNextRender(deepLinkElement);
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
           'Disconnect tether button should be focused for settingId=23.');
diff --git a/chrome/test/data/webui/settings/chromeos/internet_known_networks_page_tests.js b/chrome/test/data/webui/settings/chromeos/internet_known_networks_page_tests.js
index 2958711..f3cf216 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_known_networks_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_known_networks_page_tests.js
@@ -2,18 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// clang-format off
-// #import 'chrome://os-settings/chromeos/os_settings.js';
-
-// #import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
-// #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
-// #import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
-// #import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
-// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-// #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-// #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
-// #import {waitAfterNextRender} from 'chrome://test/test_util.js';
-// clang-format on
+import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
+import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
+import {waitAfterNextRender} from 'chrome://test/test_util.js';
 
 suite('InternetKnownNetworksPage', function() {
   /** @type {?SettingsInternetKnownNetworksPageElement} */
@@ -36,14 +32,14 @@
     });
 
     mojoApi_ = new FakeNetworkConfig();
-    network_config.MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
+    MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
 
     // Disable animations so sub-pages open within one event loop.
     testing.Test.disableAnimationsAndTransitions();
   });
 
   function flushAsync() {
-    Polymer.dom.flush();
+    flush();
     // Use setTimeout to wait for the next macrotask.
     return new Promise(resolve => setTimeout(resolve));
   }
@@ -66,7 +62,7 @@
   teardown(function() {
     internetKnownNetworksPage.remove();
     internetKnownNetworksPage = null;
-    settings.Router.getInstance().resetRouteForTesting();
+    Router.getInstance().resetRouteForTesting();
   });
 
   suite('KnownNetworksPage', function() {
@@ -86,8 +82,7 @@
 
       const params = new URLSearchParams;
       params.append('settingId', '7');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.KNOWN_NETWORKS, params);
+      Router.getInstance().navigateTo(routes.KNOWN_NETWORKS, params);
 
       await flushAsync();
 
@@ -102,7 +97,7 @@
       const deepLinkElement =
           preferredElems[0].shadowRoot.querySelector('#icon');
       assertTrue(!!deepLinkElement);
-      await test_util.waitAfterNextRender();
+      await waitAfterNextRender();
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
           'Preferred list elem should be focused for settingId=7.');
@@ -126,8 +121,7 @@
 
       const params = new URLSearchParams;
       params.append('settingId', '7');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.KNOWN_NETWORKS, params);
+      Router.getInstance().navigateTo(routes.KNOWN_NETWORKS, params);
 
       await flushAsync();
 
diff --git a/chrome/test/data/webui/settings/chromeos/internet_page_tests.js b/chrome/test/data/webui/settings/chromeos/internet_page_tests.js
index 63ea8e32e..3d25e3bb 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_page_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_page_tests.js
@@ -2,20 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// clang-format off
-// #import 'chrome://os-settings/chromeos/os_settings.js';
-
-// #import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
-// #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
-// #import {setESimManagerRemoteForTesting} from 'chrome://resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.m.js';
-// #import {FakeESimManagerRemote} from 'chrome://test/cr_components/chromeos/cellular_setup/fake_esim_manager_remote.m.js';
-// #import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
-// #import {CellularSetupPageName} from 'chrome://resources/cr_components/chromeos/cellular_setup/cellular_types.m.js';
-// #import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
-// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-// #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
-// #import {isVisible, waitAfterNextRender} from 'chrome://test/test_util.js';
-// clang-format on
+import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {CellularSetupPageName} from 'chrome://resources/cr_components/chromeos/cellular_setup/cellular_types.m.js';
+import {setESimManagerRemoteForTesting} from 'chrome://resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.m.js';
+import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
+import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
+import {FakeESimManagerRemote} from 'chrome://test/cr_components/chromeos/cellular_setup/fake_esim_manager_remote.m.js';
+import {isVisible, waitAfterNextRender} from 'chrome://test/test_util.js';
 
 suite('InternetPage', function() {
   /** @type {?InternetPageElement} */
@@ -36,7 +32,7 @@
   });
 
   function flushAsync() {
-    Polymer.dom.flush();
+    flush();
     // Use setTimeout to wait for the next macrotask.
     return new Promise(resolve => setTimeout(resolve));
   }
@@ -63,10 +59,8 @@
 
     // Pretend that we initially started on the INTERNET_NETWORKS route with the
     // params.
-    settings.Router.getInstance().navigateTo(
-        settings.routes.INTERNET_NETWORKS, params);
-    internetPage.currentRouteChanged(
-        settings.routes.INTERNET_NETWORKS, undefined);
+    Router.getInstance().navigateTo(routes.INTERNET_NETWORKS, params);
+    internetPage.currentRouteChanged(routes.INTERNET_NETWORKS, undefined);
 
     // Update the device state here to trigger an
     // attemptShowCellularSetupDialog_() call.
@@ -127,8 +121,7 @@
 
     const params = new URLSearchParams;
     params.append('guid', cellularNetwork.guid);
-    settings.Router.getInstance().navigateTo(
-        settings.routes.NETWORK_DETAIL, params);
+    Router.getInstance().navigateTo(routes.NETWORK_DETAIL, params);
     return flushAsync();
   }
 
@@ -164,9 +157,9 @@
     });
 
     mojoApi_ = new FakeNetworkConfig();
-    network_config.MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
-    eSimManagerRemote = new cellular_setup.FakeESimManagerRemote();
-    cellular_setup.setESimManagerRemoteForTesting(eSimManagerRemote);
+    MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
+    eSimManagerRemote = new FakeESimManagerRemote();
+    setESimManagerRemoteForTesting(eSimManagerRemote);
 
     PolymerTest.clearBody();
   });
@@ -182,7 +175,7 @@
     }
     internetPage.remove();
     internetPage = null;
-    settings.Router.getInstance().resetRouteForTesting();
+    Router.getInstance().resetRouteForTesting();
   });
 
   suite('MainPage', function() {
@@ -252,15 +245,14 @@
 
       const params = new URLSearchParams;
       params.append('settingId', '4');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.INTERNET, params);
+      Router.getInstance().navigateTo(routes.INTERNET, params);
 
       await flushAsync();
 
       const deepLinkElement =
           networkSummary_.$$('#WiFi').$$('#deviceEnabledButton');
       assertTrue(!!deepLinkElement);
-      await test_util.waitAfterNextRender(deepLinkElement);
+      await waitAfterNextRender(deepLinkElement);
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
           'Toggle WiFi should be focused for settingId=4.');
@@ -331,8 +323,7 @@
             });
 
             return flushAsync().then(() => {
-              assertTrue(
-                  test_util.isVisible(internetPage.$$('#add-vpn-label')));
+              assertTrue(isVisible(internetPage.$$('#add-vpn-label')));
             });
           });
 
@@ -352,10 +343,9 @@
             });
 
             return flushAsync().then(() => {
+              assertTrue(isVisible(internetPage.$$('#vpnPolicyIndicator')));
               assertTrue(
-                  test_util.isVisible(internetPage.$$('#vpnPolicyIndicator')));
-              assertTrue(test_util.isVisible(
-                  networkSummary_.$$('#VPN').$$('#policyIndicator')));
+                  isVisible(networkSummary_.$$('#VPN').$$('#policyIndicator')));
             });
           });
 
@@ -375,10 +365,9 @@
             });
 
             return flushAsync().then(() => {
+              assertFalse(isVisible(internetPage.$$('#vpnPolicyIndicator')));
               assertFalse(
-                  test_util.isVisible(internetPage.$$('#vpnPolicyIndicator')));
-              assertFalse(test_util.isVisible(
-                  networkSummary_.$$('#VPN').$$('#policyIndicator')));
+                  isVisible(networkSummary_.$$('#VPN').$$('#policyIndicator')));
             });
           });
     });
@@ -391,15 +380,14 @@
 
       const params = new URLSearchParams;
       params.append('settingId', '13');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.INTERNET, params);
+      Router.getInstance().navigateTo(routes.INTERNET, params);
 
       await flushAsync();
 
       const deepLinkElement =
           networkSummary_.$$('#Cellular').$$('#deviceEnabledButton');
       assertTrue(!!deepLinkElement);
-      await test_util.waitAfterNextRender(deepLinkElement);
+      await waitAfterNextRender(deepLinkElement);
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
           'Toggle mobile on/off should be focused for settingId=13.');
@@ -606,10 +594,8 @@
 
     // Pretend that we initially started on the INTERNET_NETWORKS route with the
     // params.
-    settings.Router.getInstance().navigateTo(
-        settings.routes.INTERNET_NETWORKS, params);
-    internetPage.currentRouteChanged(
-        settings.routes.INTERNET_NETWORKS, undefined);
+    Router.getInstance().navigateTo(routes.INTERNET_NETWORKS, params);
+    internetPage.currentRouteChanged(routes.INTERNET_NETWORKS, undefined);
 
     // Update the device state here to trigger an onDeviceStatesChanged_() call.
     mojoApi_.setDeviceStateForTest({
@@ -640,9 +626,9 @@
         assertFalse(internetPage.$.errorToast.open);
 
         // Send event, toast should show, dialog hidden.
-        const event = new CustomEvent('show-cellular-setup', {
-          detail: {pageName: cellularSetup.CellularSetupPageName.ESIM_FLOW_UI}
-        });
+        const event = new CustomEvent(
+            'show-cellular-setup',
+            {detail: {pageName: CellularSetupPageName.ESIM_FLOW_UI}});
         internetPage.dispatchEvent(event);
         await flushAsync();
         assertTrue(internetPage.$.errorToast.open);
@@ -724,10 +710,8 @@
 
         // Navigate straight to Known Networks while passing in parameters
         // with an empty type.
-        settings.Router.getInstance().navigateTo(
-            settings.routes.KNOWN_NETWORKS, params);
-        internetPage.currentRouteChanged(
-            settings.routes.KNOWN_NETWORKS, undefined);
+        Router.getInstance().navigateTo(routes.KNOWN_NETWORKS, params);
+        internetPage.currentRouteChanged(routes.KNOWN_NETWORKS, undefined);
 
         const knownNetworksPage =
             internetPage.$$('settings-internet-known-networks-page');
diff --git a/chrome/test/data/webui/settings/chromeos/internet_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/internet_subpage_tests.js
index 121c2b6..82a3332b 100644
--- a/chrome/test/data/webui/settings/chromeos/internet_subpage_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/internet_subpage_tests.js
@@ -2,20 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// clang-format off
-// #import 'chrome://os-settings/chromeos/os_settings.js';
-
-// #import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
-// #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
-// #import {setESimManagerRemoteForTesting} from 'chrome://resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.m.js';
-// #import {FakeESimManagerRemote} from 'chrome://test/cr_components/chromeos/cellular_setup/fake_esim_manager_remote.m.js';
-// #import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
-// #import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
-// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-// #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
-// #import {eventToPromise, flushTasks, waitAfterNextRender} from 'chrome://test/test_util.js';
-// #import {assert} from 'chrome://resources/js/assert.m.js';
-// clang-format on
+import {Router, routes} from 'chrome://os-settings/chromeos/os_settings.js';
+import {setESimManagerRemoteForTesting} from 'chrome://resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.m.js';
+import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
+import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
+import {FakeESimManagerRemote} from 'chrome://test/cr_components/chromeos/cellular_setup/fake_esim_manager_remote.m.js';
+import {waitAfterNextRender} from 'chrome://test/test_util.js';
 
 suite('InternetSubpage', function() {
   /** @type {?SettingsInternetSubpageElement} */
@@ -41,17 +37,17 @@
     });
 
     mojoApi_ = new FakeNetworkConfig();
-    network_config.MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
+    MojoInterfaceProviderImpl.getInstance().remote_ = mojoApi_;
 
-    eSimManagerRemote = new cellular_setup.FakeESimManagerRemote();
-    cellular_setup.setESimManagerRemoteForTesting(eSimManagerRemote);
+    eSimManagerRemote = new FakeESimManagerRemote();
+    setESimManagerRemoteForTesting(eSimManagerRemote);
 
     // Disable animations so sub-pages open within one event loop.
     testing.Test.disableAnimationsAndTransitions();
   });
 
   function flushAsync() {
-    Polymer.dom.flush();
+    flush();
     // Use setTimeout to wait for the next macrotask.
     return new Promise(resolve => setTimeout(resolve));
   }
@@ -102,7 +98,7 @@
   teardown(function() {
     internetSubpage.remove();
     internetSubpage = null;
-    settings.Router.getInstance().resetRouteForTesting();
+    Router.getInstance().resetRouteForTesting();
   });
 
   suite('SubPage', function() {
@@ -134,14 +130,13 @@
 
       const params = new URLSearchParams;
       params.append('settingId', '4');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.INTERNET_NETWORKS, params);
+      Router.getInstance().navigateTo(routes.INTERNET_NETWORKS, params);
 
       await flushAsync();
 
       const deepLinkElement = internetSubpage.$$('#deviceEnabledButton');
       assertTrue(!!deepLinkElement);
-      await test_util.waitAfterNextRender(deepLinkElement);
+      await waitAfterNextRender(deepLinkElement);
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
           'Toggle WiFi should be focused for settingId=4.');
@@ -183,14 +178,13 @@
 
       const params = new URLSearchParams;
       params.append('settingId', '22');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.INTERNET_NETWORKS, params);
+      Router.getInstance().navigateTo(routes.INTERNET_NETWORKS, params);
 
       await flushAsync();
 
       const deepLinkElement = internetSubpage.$$('#deviceEnabledButton');
       assertTrue(!!deepLinkElement);
-      await test_util.waitAfterNextRender(deepLinkElement);
+      await waitAfterNextRender(deepLinkElement);
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
           'Device enabled should be focused for settingId=22.');
@@ -215,15 +209,14 @@
 
       const params = new URLSearchParams;
       params.append('settingId', '26');
-      settings.Router.getInstance().navigateTo(
-          settings.routes.INTERNET_NETWORKS, params);
+      Router.getInstance().navigateTo(routes.INTERNET_NETWORKS, params);
 
       await flushAsync();
       assertTrue(!!cellularNetworkList);
 
       const deepLinkElement = cellularNetworkList.getAddEsimButton();
       assertTrue(!!deepLinkElement);
-      await test_util.waitAfterNextRender(deepLinkElement);
+      await waitAfterNextRender(deepLinkElement);
       assertEquals(
           deepLinkElement, getDeepActiveElement(),
           'Add cellular button should be focused for settingId=26.');
@@ -261,10 +254,9 @@
         params.append('guid', 'cellular1_guid');
         params.append('type', 'Cellular');
         params.append('name', 'cellular1');
-        settings.Router.getInstance().navigateTo(
-            settings.routes.INTERNET_NETWORKS, params);
+        Router.getInstance().navigateTo(routes.INTERNET_NETWORKS, params);
         internetSubpage.currentRouteChanged(
-            settings.routes.INTERNET_NETWORKS, undefined);
+            routes.INTERNET_NETWORKS, undefined);
       });
     });
 
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
index 17b57ab..ca7ecb2 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
@@ -392,12 +392,12 @@
  ['GuestOsSharedUsbDevices', 'guest_os_shared_usb_devices_test.m.js'],
  ['InputMethodOptionPage', 'input_method_options_page_test.m.js'],
  ['InputPage', 'input_page_test.m.js'],
- ['InternetConfig', 'internet_config_test.m.js'],
- ['InternetDetailMenu', 'internet_detail_menu_test.m.js'],
- ['InternetDetailPage', 'internet_detail_page_tests.m.js'],
- ['InternetKnownNetworksPage', 'internet_known_networks_page_tests.m.js'],
- ['InternetSubpage', 'internet_subpage_tests.m.js'],
- ['InternetPage', 'internet_page_tests.m.js'],
+ ['InternetConfig', 'internet_config_test.js'],
+ ['InternetDetailMenu', 'internet_detail_menu_test.js'],
+ ['InternetDetailPage', 'internet_detail_page_tests.js'],
+ ['InternetKnownNetworksPage', 'internet_known_networks_page_tests.js'],
+ ['InternetSubpage', 'internet_subpage_tests.js'],
+ ['InternetPage', 'internet_page_tests.js'],
  ['KerberosAccounts', 'kerberos_accounts_test.m.js'],
  ['KerberosPage', 'kerberos_page_test.m.js'],
  ['KeyboardShortcutBanner', 'keyboard_shortcut_banner_test.m.js'],
diff --git a/chrome/test/data/webui/settings/chromeos/test_internet_page_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_internet_page_browser_proxy.js
index df91549..c296c2dc 100644
--- a/chrome/test/data/webui/settings/chromeos/test_internet_page_browser_proxy.js
+++ b/chrome/test/data/webui/settings/chromeos/test_internet_page_browser_proxy.js
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// clang-format off
-// #import {TestBrowserProxy} from '../../test_browser_proxy.js';
-// clang-format on
+import {TestBrowserProxy} from '../../test_browser_proxy.js';
 
 /**
- * @implements {settings.InternetPageBrowserProxy}
+ * @implements {InternetPageBrowserProxy}
  */
-/* #export */ class TestInternetPageBrowserProxy extends TestBrowserProxy {
+export class TestInternetPageBrowserProxy extends TestBrowserProxy {
   constructor() {
     super([
       'showCarrierAccountDetail', 'showCellularSetupUI',
diff --git a/chrome/test/webapps/coverage/coverage_cros.tsv b/chrome/test/webapps/coverage/coverage_cros.tsv
index 68d35c6..a0abfda7 100644
--- a/chrome/test/webapps/coverage/coverage_cros.tsv
+++ b/chrome/test/webapps/coverage/coverage_cros.tsv
@@ -1,5 +1,5 @@
 # This is a generated file.
-# Full coverage: 56%, with partial coverage: 74%
+# Full coverage: 56%, with partial coverage: 76%
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_menu_option_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_launch_icon_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_chrome_apps_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
@@ -53,12 +53,12 @@
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_window_created🌕
 install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_window_created🌕
 install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_window_created🌕
@@ -72,14 +72,14 @@
 install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_not_exists_SiteA🌑
 install_policy_app_windowed_no_shortcut_SiteC🌓	check_platform_shortcut_not_exists_SiteC🌑
 install_policy_app_tabbed_no_shortcut_SiteC🌓	check_platform_shortcut_not_exists_SiteC🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
 install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
@@ -157,16 +157,16 @@
 install_create_shortcut_windowed_SiteC🌕	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
 install_policy_app_windowed_no_shortcut_SiteC🌓	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
 install_policy_app_windowed_shortcut_SiteC🌓	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
-install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_windowed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
-install_policy_app_tabbed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_windowed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_tabbed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌑
+install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_windowed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌓
+install_policy_app_tabbed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌓
+install_create_shortcut_windowed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌓
+install_create_shortcut_tabbed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_menu_option_SiteA🌕	check_window_created🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_launch_icon_SiteA🌕	check_window_created🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_chrome_apps_SiteA🌓	check_window_created🌕
@@ -486,10 +486,10 @@
 install_omnibox_icon_SiteA🌕	switch_incognito_profile🌑	navigate_browser_SiteA🌑	check_launch_icon_not_shown🌑
 install_menu_option_SiteA🌕	switch_incognito_profile🌑	navigate_browser_SiteA🌑	check_launch_icon_not_shown🌑
 switch_incognito_profile🌑	navigate_browser_SiteA🌑	check_install_icon_not_shown🌑
-install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	check_app_in_list_windowed_SiteA🌓
 install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	check_app_in_list_windowed_SiteA🌓
@@ -504,7 +504,7 @@
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_menu_SiteA🌑	sync_turn_on🌑	check_app_in_list_tabbed_SiteA🌑
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_os_SiteA🌑	sync_turn_on🌑	check_app_in_list_tabbed_SiteA🌑
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_app_settings_SiteA🌑	sync_turn_on🌑	check_app_in_list_tabbed_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_list_SiteA🌕	sync_turn_on🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_list_SiteA🌕	sync_turn_on🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_menu_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_os_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_app_settings_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
@@ -520,15 +520,15 @@
 install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_menu_SiteA🌑	sync_turn_on🌑	check_app_in_list_windowed_SiteA🌑
 install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_os_SiteA🌑	sync_turn_on🌑	check_app_in_list_windowed_SiteA🌑
 install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_app_settings_SiteA🌑	sync_turn_on🌑	check_app_in_list_windowed_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_list_SiteA🌕	sync_turn_on🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_list_SiteA🌕	sync_turn_on🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_menu_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
 install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_os_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
 install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_app_settings_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_list_SiteA🌕	sync_turn_on🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_list_SiteA🌕	sync_turn_on🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_menu_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
 install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_os_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
 install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_app_settings_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_list_SiteA🌕	sync_turn_on🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_list_SiteA🌕	sync_turn_on🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_menu_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
 install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_os_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
 install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	sync_turn_off🌕	uninstall_from_app_settings_SiteA🌑	sync_turn_on🌑	check_platform_shortcut_and_icon_SiteA🌑
@@ -564,10 +564,10 @@
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
@@ -580,18 +580,18 @@
 install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
 install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
@@ -608,9 +608,9 @@
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
diff --git a/chrome/test/webapps/coverage/coverage_linux.tsv b/chrome/test/webapps/coverage/coverage_linux.tsv
index 285c8e4b..7654f21 100644
--- a/chrome/test/webapps/coverage/coverage_linux.tsv
+++ b/chrome/test/webapps/coverage/coverage_linux.tsv
@@ -1,5 +1,5 @@
 # This is a generated file.
-# Full coverage: 57%, with partial coverage: 77%
+# Full coverage: 57%, with partial coverage: 79%
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_menu_option_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_launch_icon_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_chrome_apps_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
@@ -53,12 +53,12 @@
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_window_created🌕
 install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_window_created🌕
 install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_window_created🌕
@@ -68,10 +68,10 @@
 install_create_shortcut_windowed_SiteA🌕	check_window_created🌕
 install_omnibox_icon_SiteA🌕	check_window_created🌕
 install_menu_option_SiteA🌕	check_window_created🌕
-install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	navigate_browser_SiteA🌕	check_install_icon_shown🌕
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	navigate_browser_SiteA🌕	check_launch_icon_not_shown🌕
@@ -89,20 +89,20 @@
 install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_app_in_list_windowed_SiteC🌓
 install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	navigate_browser_SiteC🌕	check_install_icon_not_shown🌕
 install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
-install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_tabbed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
+install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌓
+install_create_shortcut_tabbed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌓
 install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_not_exists_SiteA🌑
 install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_not_exists_SiteA🌑
 install_policy_app_windowed_no_shortcut_SiteC🌓	check_platform_shortcut_not_exists_SiteC🌑
 install_policy_app_tabbed_no_shortcut_SiteC🌓	check_platform_shortcut_not_exists_SiteC🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
 install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
@@ -180,16 +180,16 @@
 install_create_shortcut_windowed_SiteC🌕	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
 install_policy_app_windowed_no_shortcut_SiteC🌓	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
 install_policy_app_windowed_shortcut_SiteC🌓	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
-install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_windowed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
-install_policy_app_tabbed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_windowed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_tabbed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌑
+install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_windowed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌓
+install_policy_app_tabbed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌓
+install_create_shortcut_windowed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌓
+install_create_shortcut_tabbed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_menu_option_SiteA🌕	check_window_created🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_launch_icon_SiteA🌕	check_window_created🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_chrome_apps_SiteA🌓	check_window_created🌕
@@ -651,10 +651,10 @@
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
@@ -667,18 +667,18 @@
 install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
 install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
@@ -695,12 +695,12 @@
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	open_app_settings_from_chrome_apps_SiteA🌑	check_browser_navigation_is_app_settings_SiteA🌑
 install_create_shortcut_windowed_SiteA🌕	open_app_settings_from_app_window_SiteA🌑	check_browser_navigation_is_app_settings_SiteA🌑
 install_omnibox_icon_SiteA🌕	open_app_settings_from_chrome_apps_SiteA🌑	check_browser_navigation_is_app_settings_SiteA🌑
diff --git a/chrome/test/webapps/coverage/coverage_mac.tsv b/chrome/test/webapps/coverage/coverage_mac.tsv
index 2a2e589..a81e6ff 100644
--- a/chrome/test/webapps/coverage/coverage_mac.tsv
+++ b/chrome/test/webapps/coverage/coverage_mac.tsv
@@ -1,5 +1,5 @@
 # This is a generated file.
-# Full coverage: 50%, with partial coverage: 68%
+# Full coverage: 52%, with partial coverage: 70%
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_menu_option_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_launch_icon_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_chrome_apps_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
@@ -53,12 +53,12 @@
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
 install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_window_created🌕
 install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_window_created🌕
 install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_window_created🌕
@@ -71,7 +71,7 @@
 install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌑	install_locally_SiteA🌑	check_platform_shortcut_and_icon_SiteA🌑
 install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌑	install_locally_SiteA🌑	check_platform_shortcut_and_icon_SiteA🌑
 install_menu_option_SiteA🌕	switch_profile_clients_Client2🌑	install_locally_SiteA🌑	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	navigate_browser_SiteA🌕	check_install_icon_shown🌕
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	navigate_browser_SiteA🌕	check_launch_icon_not_shown🌕
@@ -90,19 +90,19 @@
 install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌑	install_locally_SiteC🌑	navigate_browser_SiteC🌑	check_install_icon_not_shown🌑
 install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌑	install_locally_SiteC🌑	navigate_browser_SiteC🌑	check_launch_icon_shown🌑
 install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌑	install_locally_SiteC🌑	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_tabbed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
+install_create_shortcut_tabbed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌕
 install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_not_exists_SiteA🌑
 install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_not_exists_SiteA🌑
 install_policy_app_windowed_no_shortcut_SiteC🌓	check_platform_shortcut_not_exists_SiteC🌑
 install_policy_app_tabbed_no_shortcut_SiteC🌓	check_platform_shortcut_not_exists_SiteC🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
+install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
+install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
 install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
@@ -180,16 +180,16 @@
 install_create_shortcut_windowed_SiteC🌕	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
 install_policy_app_windowed_no_shortcut_SiteC🌓	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
 install_policy_app_windowed_shortcut_SiteC🌓	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
-install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_windowed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
-install_policy_app_tabbed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_windowed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_tabbed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌑
+install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_tabbed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_windowed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌕
+install_policy_app_tabbed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌕
+install_create_shortcut_windowed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌕
+install_create_shortcut_tabbed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_menu_option_SiteA🌕	check_window_created🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_launch_icon_SiteA🌕	check_window_created🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_chrome_apps_SiteA🌓	check_window_created🌕
@@ -651,10 +651,10 @@
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
@@ -667,18 +667,18 @@
 install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
 install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
 install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
@@ -695,12 +695,12 @@
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌕
 install_create_shortcut_windowed_SiteA🌕	open_app_settings_from_chrome_apps_SiteA🌑	check_browser_navigation_is_app_settings_SiteA🌑
 install_create_shortcut_windowed_SiteA🌕	open_app_settings_from_app_window_SiteA🌑	check_browser_navigation_is_app_settings_SiteA🌑
 install_omnibox_icon_SiteA🌕	open_app_settings_from_chrome_apps_SiteA🌑	check_browser_navigation_is_app_settings_SiteA🌑
diff --git a/chrome/test/webapps/coverage/coverage_win.tsv b/chrome/test/webapps/coverage/coverage_win.tsv
index 8b5c161..ea2c72f 100644
--- a/chrome/test/webapps/coverage/coverage_win.tsv
+++ b/chrome/test/webapps/coverage/coverage_win.tsv
@@ -1,5 +1,5 @@
 # This is a generated file.
-# Full coverage: 58%, with partial coverage: 79%
+# Full coverage: 58%, with partial coverage: 80%
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_menu_option_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_launch_icon_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
 install_create_shortcut_windowed_SiteA🌕	manifest_update_title_SiteA🌑	accept_app_id_update_dialog🌑	close_pwa🌑	launch_from_chrome_apps_SiteA🌑	check_app_title_site_a_is_SiteAUpdated🌑
@@ -53,12 +53,12 @@
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	check_window_created🌕
 install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	check_window_created🌕
 install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	check_window_created🌕
@@ -68,10 +68,10 @@
 install_create_shortcut_windowed_SiteA🌕	check_window_created🌕
 install_omnibox_icon_SiteA🌕	check_window_created🌕
 install_menu_option_SiteA🌕	check_window_created🌕
-install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_windowed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	navigate_browser_SiteA🌕	check_install_icon_shown🌕
 install_create_shortcut_tabbed_SiteA🌕	switch_profile_clients_Client2🌕	install_locally_SiteA🌓	navigate_browser_SiteA🌕	check_launch_icon_not_shown🌕
@@ -89,20 +89,20 @@
 install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_app_in_list_windowed_SiteC🌓
 install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	navigate_browser_SiteC🌕	check_install_icon_not_shown🌕
 install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
-install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_tabbed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
+install_create_shortcut_windowed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌓
+install_create_shortcut_tabbed_SiteC🌕	switch_profile_clients_Client2🌕	install_locally_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌓
 install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_not_exists_SiteA🌑
 install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_not_exists_SiteA🌑
 install_policy_app_windowed_no_shortcut_SiteC🌓	check_platform_shortcut_not_exists_SiteC🌑
 install_policy_app_tabbed_no_shortcut_SiteC🌓	check_platform_shortcut_not_exists_SiteC🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
 install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	check_app_in_list_windowed_SiteA🌓
@@ -180,16 +180,16 @@
 install_create_shortcut_windowed_SiteC🌕	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
 install_policy_app_windowed_no_shortcut_SiteC🌓	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
 install_policy_app_windowed_shortcut_SiteC🌓	navigate_browser_SiteC🌕	check_launch_icon_shown🌕
-install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_windowed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
-install_policy_app_tabbed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_windowed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌑
-install_create_shortcut_tabbed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌑
+install_policy_app_windowed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_windowed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌓
+install_policy_app_tabbed_shortcut_SiteC🌓	check_platform_shortcut_and_icon_SiteC🌓
+install_create_shortcut_windowed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌓
+install_create_shortcut_tabbed_SiteC🌕	check_platform_shortcut_and_icon_SiteC🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_menu_option_SiteA🌕	check_window_created🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_launch_icon_SiteA🌕	check_window_created🌕
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	launch_from_chrome_apps_SiteA🌓	check_window_created🌕
@@ -651,10 +651,10 @@
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
 install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_tabbed_SiteA🌓
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_tabbed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
@@ -667,18 +667,18 @@
 install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_create_shortcut_windowed_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_omnibox_icon_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_menu_option_SiteA🌕	install_policy_app_tabbed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_policy_app_windowed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
 install_policy_app_windowed_shortcut_SiteA🌓	uninstall_policy_app_SiteA🌕	check_app_not_in_list_SiteA🌓
@@ -695,12 +695,12 @@
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
 install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_app_in_list_windowed_SiteA🌓
-install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
-install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌑
+install_policy_app_tabbed_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_create_shortcut_windowed_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_omnibox_icon_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
+install_policy_app_tabbed_no_shortcut_SiteA🌓	install_menu_option_SiteA🌕	uninstall_policy_app_SiteA🌕	check_platform_shortcut_and_icon_SiteA🌓
 install_create_shortcut_windowed_SiteA🌕	open_app_settings_from_chrome_apps_SiteA🌑	check_browser_navigation_is_app_settings_SiteA🌑
 install_create_shortcut_windowed_SiteA🌕	open_app_settings_from_app_window_SiteA🌑	check_browser_navigation_is_app_settings_SiteA🌑
 install_omnibox_icon_SiteA🌕	open_app_settings_from_chrome_apps_SiteA🌑	check_browser_navigation_is_app_settings_SiteA🌑
diff --git a/chrome/test/webapps/data/actions.csv b/chrome/test/webapps/data/actions.csv
index 676bee8..6eacc0a 100644
--- a/chrome/test/webapps/data/actions.csv
+++ b/chrome/test/webapps/data/actions.csv
@@ -1,109 +1,109 @@
-# Action base name,Mode (* = default mode),Output Actions,Unique Identifier (next: 111),Deprecated,Deprecated,Deprecated,Deprecated,Status,Description,"Metadata, implementation bug, etc"
-launch_from_platform_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,1,,,,,Implemented,Lauch an app from a platform shortcut on the user's desktop or start menu.,"cliffordcheng@, P0"
-check_app_badge_empty,SiteA* | SiteB,,2,,,,,Awaiting Platform Integration,Check that the 'badge' on the app icon is empty,
-check_app_badge_has_value,SiteA* | SiteB,,3,,,,,Awaiting Platform Integration,Check that the 'badge' on the app icon has a value,
-clear_app_badge,SiteA* | SiteB,,4,,,,,Awaiting Platform Integration,The WebApp clears the 'badge' value from it's icon,
-drag_url_to_apps_list,,,5,,,,,Awaiting Platform Integration,"Open chrome://apps in a separage window, and drag a url (highlight & drag url from the omnibox) to the chrome://apps page",
-set_app_badge,SiteA* | SiteB,,6,,,,,Awaiting Platform Integration,Set the app badge for the given site to a value.,
-check_platform_shortcut_and_icon,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,7,,,,,Implemented,The icon of the platform shortcut (on the desktop) is correct,"cliffordcheng@, doc"
-manifest_update_scope_site_a_foo_to,SiteA* | SiteAFoo | SiteABar,,8,,,,,Awaiting Script Processing,"Update the scope of site a/foo/, to the given scope",
-navigate_pwa_site_a_foo_to,SiteA* | SiteAFoo | SiteABar | SiteB,,9,,,,,Awaiting Script Processing,Navigates the PWA window of the SiteAFoo pwa to a given site.,
-uninstall_from_list,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,10,,,,,Implemented,"Uninstall the webapp from wherever apps are listed by chrome. On WML, this is from chrome://apps, and on ChromeOS, this is from the 'launcher'",
-check_app_in_list_tabbed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,11,,,,,Implemented,"Find the app in the app list (on desktop, this is chrome://apps, and on ChromeOS, this is the app drawer). Check that the app opens in a window by right clicking on it to see if the ""open in window"" option is checked, and by launching it to see if it opens in a separate window.",
-check_app_in_list_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,12,,,,,Implemented,"Find the app in the app list (on desktop, this is chrome://apps, and on ChromeOS, this is the app drawer). Check that the app opens in a tab by right clicking on it to see if the ""open in window"" option is unchecked, and by launching it to see if it opens in a browser tab (and not a window).",
-check_app_list_empty,,,13,,,,,Implemented,"The app list is empty (on desktop, this is chrome://apps, and on ChromeOS, this is the app drawer).",
-check_app_navigation_is_start_url,,,14,,,,,Implemented,,
-check_app_not_in_list,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,15,,,,,Implemented,"Check that the given app is NOT in the app list. On desktop, this is chrome://apps, and on ChromeOS, this is the app drawer.",
-check_custom_toolbar,,,16,,,,,Implemented,Check that the PWA window has a custom toolbar to show the out-of-scope url.,
-check_install_icon_not_shown,,,17,,,,,Implemented,"Check that the ""Install"" icon in the omnibox is not shown",
-check_install_icon_shown,,,18,,,,,Implemented,"Check that the ""Install"" icon in the omnibox is shown",
-check_launch_icon_not_shown,,,19,,,,,Implemented,,
-check_launch_icon_shown,,,20,,,,,Implemented,,
-check_no_toolbar,,,21,,,,,Implemented,,
-check_tab_created,,,22,,,,,Implemented,A tab was created in a chrome browser window,
-check_window_closed,,,23,,,,,Implemented,The window was closed,
-check_window_created,,,24,,,,,Implemented,A window was created.,
-check_window_display_minimal,,,25,,,,,Implemented,"Check that the window is a PWA window, and has minimal browser controls.",
-check_window_display_standalone,,,26,,,,,Implemented,"Check that the window is a PWA window, and has no browser controls.",
-close_custom_toolbar,,,27,,,,,Implemented,Press the 'x' button on the custom toolbar that is towards the top of the WebApp window.,
-close_pwa,,,28,,,,,Implemented,Close the WebApp window.,
-install_create_shortcut_tabbed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,29,,,,,Implemented,"Install the given app using the""Create Shortcut"" menu option (3-dot->""More Tools""->""Create Shortcut), and de-selecting the ""Open in a window"" checkbox.",
-install_create_shortcut_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,30,,,,,Implemented,"Install the given app using the""Create Shortcut"" menu option (3-dot->""More Tools""->""Create Shortcut), and selecting the ""Open in a window"" checkbox.",
-install_omnibox_icon,SiteA* | SiteAFoo | SiteABar | SiteB,,31,,,,,Implemented,,
-install_policy_app_tabbed_no_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,32,,,,,Implemented,"Add a force-installed enterprise policy app to the user profile (must be managed profile). tabbed, no platform shortcut",
-install_policy_app_windowed_no_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,33,,,,,Implemented,"Add a force-installed enterprise policy app to the user profile (must be managed profile). windowed, no platform shortcut",
-launch_from_chrome_apps,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,34,,,,,Implemented,"Launch the web app by navigating to chrome://apps, and then clicking on the app icon.",
-launch_from_launch_icon,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,35,,,,,Implemented,"Launch the web app by navigating the browser to the web app, and selecting the launch icon in the omnibox (intent picker),",
-manifest_update_display_minimal,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,36,,,,,Implemented,Updates the display property of the manifest to 'minimal' on the given site's manifest,
-navigate_browser,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,37,,,,,Implemented,Navigate the browser to one of the static sites provided by the testing framework.,
-navigate_notfound_url,,,38,,,,,Implemented,Navigate to a url that returns a 404 server error.,
-navigate_pwa_site_a_to,SiteA* | SiteAFoo | SiteABar | SiteB,,39,,,,,Implemented,Navigates the PWA window of the SiteA pwa to a given site.,
-switch_profile_clients,Client2* | Client1,,40,,,,,Implemented,Switch to a different instance of chrome signed in to the same profile,
-sync_turn_off,,,41,,,,,Implemented,"Turn chrome sync off for ""Apps"": chrome://settings/syncSetup/advanced",
-sync_turn_on,,,42,,,,,Implemented,"Turn chrome sync on for ""Apps"": chrome://settings/syncSetup/advanced",
-uninstall_from_menu,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,43,,,,,Implemented,Uninstall the webapp from the 3-dot menu in the webapp window,
-uninstall_policy_app,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,44,,,,,Implemented,Remove a force-installed policy app to the user profile (must be managed profile),
-check_app_in_list_not_locally_installed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,45,,,,,Internal Impl,"Find the app in the app list (chrome://apps) and check that the given app is in the app list and is not installed. This means the icon is grey, and right clicking on it provides an 'install' option. Win/Mac/Linux only.",
-install_locally,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,46,,,,,Internal Impl,Find the app in the app list (chrome://apps) and install it by right-clicking on the app and selecting the 'install' option. Win/Mac/Linux only.,
-install_menu_option,SiteA* | SiteAFoo | SiteABar | SiteB,,47,,,,,Internal Impl,,
-install_policy_app_tabbed_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,48,,,,,Internal Impl,"Add a force-installed enterprise policy app to the user profile (must be managed profile). tabbed, with platform shortcut",
-install_policy_app_windowed_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,49,,,,,Internal Impl,"Add a force-installed enterprise policy app to the user profile (must be managed profile). windowed, with platform shortcut",
-set_open_in_tab,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,50,,,,,Internal Impl,"Uncheck the ""open in window"" checkbox in the right-click menu of the app icon, in the app list page",
-set_open_in_window,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,51,,,,,Internal Impl,"Check the ""open in window"" checkbox in the right-click menu of the app icon, in the app list page",
-install,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_windowed & install_omnibox_icon & install_policy_app_windowed_no_shortcut & install_policy_app_windowed_shortcut & install_menu_option & install_create_shortcut_tabbed & install_policy_app_tabbed_shortcut & install_policy_app_tabbed_no_shortcut,52,,,,,N/A (Parameterized Action),,
-install_by_user,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_windowed & install_omnibox_icon & install_menu_option & install_create_shortcut_tabbed,53,,,,,N/A (Parameterized Action),,
-install_by_user_tabbed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_tabbed,54,,,,,N/A (Parameterized Action),"Install the web app configured to open in a tab. This is done by the selecting the Tools->""Create Shortcut..."" menu option in the 3-dot menu, and deselecting the ""open in a window"" checkbox",
-install_by_user_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_windowed & install_omnibox_icon & install_menu_option,55,,,,,N/A (Parameterized Action),"Install the web app configured to open in a window. This is done in 3 different ways: 1) Clicking on the install icon in the omnibox, 2) Selecting the ""Install _"" menu option in the 3-dot menu, or 3) Selecting the Tools->""Create Shortcut..."" menu option in the 3-dot menu and checking the ""Open in a window"" checkbox",
-install_no_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_windowed_no_shortcut & install_policy_app_tabbed_no_shortcut,56,,,,,N/A (Parameterized Action),,
-install_policy_app,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_windowed_no_shortcut & install_policy_app_tabbed_no_shortcut & install_policy_app_windowed_shortcut & install_policy_app_tabbed_shortcut,57,,,,,N/A (Parameterized Action),,
-install_policy_app_no_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_tabbed_no_shortcut & install_policy_app_windowed_no_shortcut,58,,,,,N/A (Parameterized Action),,
-install_policy_app_tabbed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_tabbed_shortcut & install_policy_app_tabbed_no_shortcut,59,,,,,N/A (Parameterized Action),,
-install_policy_app_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_windowed_no_shortcut & install_policy_app_windowed_shortcut,60,,,,,N/A (Parameterized Action),,
-install_tabbed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_tabbed & install_policy_app_tabbed_shortcut & install_policy_app_tabbed_no_shortcut,61,,,,,N/A (Parameterized Action),All installation methods that result in a tabbed webapp.,
-install_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_windowed & install_omnibox_icon & install_policy_app_windowed_no_shortcut & install_policy_app_windowed_shortcut & install_menu_option,62,,,,,N/A (Parameterized Action),All installation methods that result in a windowed webapp.,
-install_with_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_windowed_shortcut & install_policy_app_tabbed_shortcut & install_create_shortcut_windowed & install_omnibox_icon & install_menu_option & install_create_shortcut_tabbed,63,,,,,N/A (Parameterized Action),,
-launch,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,launch_from_menu_option & launch_from_launch_icon & launch_from_chrome_apps & launch_from_platform_shortcut,64,,,,,N/A (Parameterized Action),,
-launch_from_browser,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,launch_from_menu_option & launch_from_launch_icon & launch_from_chrome_apps,65,,,,,N/A (Parameterized Action),,
-launch_from_shortcut_or_list,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,launch_from_chrome_apps & launch_from_platform_shortcut,66,,,,,N/A (Parameterized Action),All ways to launch an app that are still available for 'browser' apps.,
-uninstall_by_user,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,uninstall_from_list & uninstall_from_menu & uninstall_from_os & uninstall_from_app_settings,67,,,,,N/A (Parameterized Action),,
-manifest_update_icons,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,68,,,,,Implemented,Updates the icon field in the manifest of the website.,finnur@
-launch_from_menu_option,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,69,,,,,Implemented,"Launch the web app by navigating the browser to the web app, and selecting the ""Launch _"" menu option in the 3-dot menu.","cliffordcheng@, P1"
-manifest_update_display_browser,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,70,,,,,Implemented,Updates the display property of the manifest to 'browser' on the given site's manifest,"cliffordcheng@, P1"
-check_tab_not_created,,,94,,,,,Implemented,A tab was not created by the last state change action,"cliffordcheng@, P1"
-open_in_chrome,,,71,,,,,Implemented,Click on the 'open in chrome' link in the 3-dot menu of the app window,"cliffordcheng@, P1"
-create_shortcuts,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,72,,,,,Not Yet Implemented,"""create shortcuts"" in chrome://apps",P2
-switch_incognito_profile,,,73,,,,,Not Yet Implemented,Switch to using incognito mode,P2
-delete_platform_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,74,,,,,Not Yet Implemented,Delete the shortcut that lives on the operating system,P2
-check_app_in_list_icon_correct,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,75,,,,,Not Yet Implemented,"Find the app in the app list (on desktop, this is chrome://apps, and on ChromeOS, this is the app drawer). Check that the icon for the given app in the app list is correct.",P2 (dmurph modified - should be easy to fetch icon using web request for chrome://app-icon/<app-id>/<dip> I believe)
-check_theme_color,SiteA* | SiteAFoo | SiteABar | SiteB,,76,,,,,Not Yet Implemented,Asserts that the theme color of the given app window is correct.,P3
-check_window_color_correct,,,77,,,,,Not Yet Implemented,The color of the window is correct.,P3
-check_window_icon_correct,,,78,,,,,Not Yet Implemented,,P3
-manifest_update_colors,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,80,,,,,Not Yet Implemented,The website updates it's manifest.json to change the 'theme' color,P3
-navigate_crashed_url,,,81,,,,,Not Yet Implemented,"Navigate to a page that crashes, or simulates a crashed renderer. chrome://crash",P3
-navigate_link_target_blank,,,82,,,,,Not Yet Implemented,"Click on a href link on the current page, where the target of the link is ""_blank""",P3
-delete_profile,,,83,,,,,Not Yet Implemented,Delete the user profile.,P4
-check_platform_shortcut_not_exists,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,84,,,,,WIP,The desktop platform shortcut has been removed.,"cliffordcheng@, doc"
-check_create_shortcut_not_shown,,,85,,,,,WIP,"Check that the ""Create Shortcut"" menu option (3-dot->""More Tools""->""Create Shortcut) is greyed out",
-check_create_shortcut_shown,,,86,,,,,WIP,"Check that the ""Create Shortcut"" menu option (3-dot->""More Tools""->""Create Shortcut) is shown",
-uninstall_from_os,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,87,,,,,WIP,Uninstalls the app from OS integration - e.g. Windows Control Panel / Start menu,
-check_window_title_site_a_is,SiteA | SiteAUpdated,,79,,,,,Implemented,Check that the window title is correct,finnur@
-manifest_update_title,SiteA,,88,,,,,Implemented,The website updates it's manifest.json to change the 'title',finnur@
-check_app_icon_site_a_is,SiteA | SiteAUpdated,,110,,,,,Implemented,Check that the app icon color is correct,finnur@
-accept_app_update_dialog,,,91,,,,,WIP,Click Accept in the App Identity Update dialog,finnur@
-check_update_dialog_not_shown,,,92,,,,,WIP,,finnur@
-deny_app_update_dialog,,,93,,,,,WIP,,finnue@
-open_app_settings,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,open_app_settings_from_chrome_apps & open_app_settings_from_app_window,95,,,,,N/A (Parameterized Action),Launch chrome://app-settings/<app-id> page,phillis@
-open_app_settings_from_chrome_apps,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,96,,,,,Implemented,,phillis@
-open_app_settings_from_app_window,,,97,,,,,Implemented,,phillis@
-uninstall_from_app_settings,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,98,,,,,Implemented,"uninstall an app from app settings page, the app has to be locally installed.",phillis@
-uninstall_not_locally_installed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,uninstall_from_list & uninstall_from_menu & uninstall_from_os,99,,,,,N/A (Parameterized Action),"Uninstall an app by user, the app can be not locally installed.",
-apply_run_on_os_login_policy_allowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,100,,,,,Implemented,Apply WebAppSettings policy for run_on_os_login to be allowed,phillis@
-apply_run_on_os_login_policy_blocked,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,101,,,,,Implemented,Apply WebAppSettings policy for run_on_os_login to be blocked,phillis@
-apply_run_on_os_login_policy_run_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,102,,,,,Implemented,Apply WebAppSettings policy for run_on_os_login to be run_windowed,phillis@
-remove_run_on_os_login_policy,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,103,,,,,Implemented,Remove  run_on_os_login policy for the app in WebAppSettings policy.,phillis@
-enable_run_on_os_login,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,104,,,,,Implemented,Enable run on os login from app settings page,phillis@
-disable_run_on_os_login,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,105,,,,,Implemented,Disable run on os login from app settings page,phillis@
-check_run_on_os_login_enabled,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,106,,,,,Implemented,Check run on os login is enabled.,phillis@
-check_run_on_os_login_disabled,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,107,,,,,Implemented,Check run on os login is disabled.,phillis@
-check_app_settings_app_state,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,108,,,,,Implemented,Check the app shown on app settings page matches the current app state.,phillis@
-check_browser_navigation_is_app_settings,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,109,,,,,Implemented,Check the current browser naviagtion is chrome://app-settings/<app-id>,phillis@
\ No newline at end of file
+# Action base name,Mode (* = default mode) (old),Output Actions (old),Unique Identifier (next: 111),Deprecated,Deprecated,Deprecated,Deprecated,Status,Argument Types,Output Actions,Description,"Metadata, implementation bug, etc"
+check_create_shortcut_not_shown,,,85,,,,,WIP,,,"Check that the ""Create Shortcut"" menu option (3-dot->""More Tools""->""Create Shortcut) is greyed out",
+check_create_shortcut_shown,,,86,,,,,WIP,,,"Check that the ""Create Shortcut"" menu option (3-dot->""More Tools""->""Create Shortcut) is shown",
+check_platform_shortcut_not_exists,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,84,,,,,WIP,Site,,The desktop platform shortcut has been removed.,"cliffordcheng@, doc"
+check_update_dialog_not_shown,,,92,,,,,WIP,,,,finnur@
+deny_app_update_dialog,,,93,,,,,WIP,,,,finnue@
+uninstall_from_os,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,87,,,,,WIP,Site,,Uninstalls the app from OS integration - e.g. Windows Control Panel / Start menu,
+check_app_in_list_icon_correct,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,75,,,,,Not Yet Implemented,Site,,"Find the app in the app list (on desktop, this is chrome://apps, and on ChromeOS, this is the app drawer). Check that the icon for the given app in the app list is correct.",P2 (dmurph modified - should be easy to fetch icon using web request for chrome://app-icon/<app-id>/<dip> I believe)
+check_theme_color,SiteA* | SiteAFoo | SiteABar | SiteB,,76,,,,,Not Yet Implemented,Site,,Asserts that the theme color of the given app window is correct.,P3
+check_window_color_correct,,,77,,,,,Not Yet Implemented,Site,,The color of the window is correct.,P3
+check_window_icon_correct,,,78,,,,,Not Yet Implemented,,,,P3
+create_shortcuts,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,72,,,,,Not Yet Implemented,Site,,"""create shortcuts"" in chrome://apps",P2
+delete_platform_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,74,,,,,Not Yet Implemented,Site,,Delete the shortcut that lives on the operating system,P2
+delete_profile,,,83,,,,,Not Yet Implemented,,,Delete the user profile.,P4
+manifest_update_colors,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,80,,,,,Not Yet Implemented,Site,,The website updates it's manifest.json to change the 'theme' color,P3
+navigate_crashed_url,,,81,,,,,Not Yet Implemented,,,"Navigate to a page that crashes, or simulates a crashed renderer. chrome://crash",P3
+navigate_link_target_blank,,,82,,,,,Not Yet Implemented,,,"Click on a href link on the current page, where the target of the link is ""_blank""",P3
+switch_incognito_profile,,,73,,,,,Not Yet Implemented,,,Switch to using incognito mode,P2
+install,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_windowed & install_omnibox_icon & install_policy_app_windowed_no_shortcut & install_policy_app_windowed_shortcut & install_menu_option & install_create_shortcut_tabbed & install_policy_app_tabbed_shortcut & install_policy_app_tabbed_no_shortcut,52,,,,,N/A (Parameterized Action),Site,install_create_shortcut_windowed($1) & install_omnibox_icon($1) & install_policy_app_windowed_no_shortcut($1) & install_policy_app_windowed_shortcut($1) & install_menu_option($1) & install_create_shortcut_tabbed($1) & install_policy_app_tabbed_shortcut($1) & install_policy_app_tabbed_no_shortcut($1),,
+install_by_user,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_windowed & install_omnibox_icon & install_menu_option & install_create_shortcut_tabbed,53,,,,,N/A (Parameterized Action),Site,install_create_shortcut_windowed($1) & install_omnibox_icon($1) & install_menu_option($1) & install_create_shortcut_tabbed($1),,
+install_by_user_tabbed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_tabbed,54,,,,,N/A (Parameterized Action),Site,install_create_shortcut_tabbed($1),"Install the web app configured to open in a tab. This is done by the selecting the Tools->""Create Shortcut..."" menu option in the 3-dot menu, and deselecting the ""open in a window"" checkbox",
+install_by_user_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_windowed & install_omnibox_icon & install_menu_option,55,,,,,N/A (Parameterized Action),Site,install_create_shortcut_windowed($1) & install_omnibox_icon($1) & install_menu_option($1),"Install the web app configured to open in a window. This is done in 3 different ways: 1) Clicking on the install icon in the omnibox, 2) Selecting the ""Install _"" menu option in the 3-dot menu, or 3) Selecting the Tools->""Create Shortcut..."" menu option in the 3-dot menu and checking the ""Open in a window"" checkbox",
+install_no_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_windowed_no_shortcut & install_policy_app_tabbed_no_shortcut,56,,,,,N/A (Parameterized Action),Site,install_policy_app_windowed_no_shortcut($1) & install_policy_app_tabbed_no_shortcut($1),,
+install_policy_app,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_windowed_no_shortcut & install_policy_app_tabbed_no_shortcut & install_policy_app_windowed_shortcut & install_policy_app_tabbed_shortcut,57,,,,,N/A (Parameterized Action),Site,install_policy_app_windowed_no_shortcut($1) & install_policy_app_tabbed_no_shortcut($1) & install_policy_app_windowed_shortcut($1) & install_policy_app_tabbed_shortcut($1),,
+install_policy_app_no_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_tabbed_no_shortcut & install_policy_app_windowed_no_shortcut,58,,,,,N/A (Parameterized Action),Site,install_policy_app_tabbed_no_shortcut($1) & install_policy_app_windowed_no_shortcut($1),,
+install_policy_app_tabbed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_tabbed_shortcut & install_policy_app_tabbed_no_shortcut,59,,,,,N/A (Parameterized Action),Site,install_policy_app_tabbed_shortcut($1) & install_policy_app_tabbed_no_shortcut($1),,
+install_policy_app_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_windowed_no_shortcut & install_policy_app_windowed_shortcut,60,,,,,N/A (Parameterized Action),Site,install_policy_app_windowed_no_shortcut($1) & install_policy_app_windowed_shortcut($1),,
+install_tabbed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_tabbed & install_policy_app_tabbed_shortcut & install_policy_app_tabbed_no_shortcut,61,,,,,N/A (Parameterized Action),Site,install_create_shortcut_tabbed($1) & install_policy_app_tabbed_shortcut($1) & install_policy_app_tabbed_no_shortcut($1),All installation methods that result in a tabbed webapp.,
+install_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_create_shortcut_windowed & install_omnibox_icon & install_policy_app_windowed_no_shortcut & install_policy_app_windowed_shortcut & install_menu_option,62,,,,,N/A (Parameterized Action),Site,install_create_shortcut_windowed($1) & install_omnibox_icon($1) & install_policy_app_windowed_no_shortcut($1) & install_policy_app_windowed_shortcut($1) & install_menu_option($1),All installation methods that result in a windowed webapp.,
+install_with_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,install_policy_app_windowed_shortcut & install_policy_app_tabbed_shortcut & install_create_shortcut_windowed & install_omnibox_icon & install_menu_option & install_create_shortcut_tabbed,63,,,,,N/A (Parameterized Action),Site,install_policy_app_windowed_shortcut($1) & install_policy_app_tabbed_shortcut($1) & install_create_shortcut_windowed($1) & install_omnibox_icon($1) & install_menu_option($1) & install_create_shortcut_tabbed($1),,
+launch,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,launch_from_menu_option & launch_from_launch_icon & launch_from_chrome_apps & launch_from_platform_shortcut,64,,,,,N/A (Parameterized Action),Site,launch_from_menu_option($1) & launch_from_launch_icon($1) & launch_from_chrome_apps($1) & launch_from_platform_shortcut($1),,
+launch_from_browser,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,launch_from_menu_option & launch_from_launch_icon & launch_from_chrome_apps,65,,,,,N/A (Parameterized Action),Site,launch_from_menu_option($1) & launch_from_launch_icon($1) & launch_from_chrome_apps($1),,
+launch_from_shortcut_or_list,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,launch_from_chrome_apps & launch_from_platform_shortcut,66,,,,,N/A (Parameterized Action),Site,launch_from_chrome_apps($1) & launch_from_platform_shortcut($1),All ways to launch an app that are still available for 'browser' apps.,
+open_app_settings,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,open_app_settings_from_chrome_apps & open_app_settings_from_app_window,95,,,,,N/A (Parameterized Action),Site,open_app_settings_from_chrome_apps($1) & open_app_settings_from_app_window($1),Launch chrome://app-settings/<app-id> page,phillis@
+uninstall_by_user,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,uninstall_from_list & uninstall_from_menu & uninstall_from_os & uninstall_from_app_settings,67,,,,,N/A (Parameterized Action),Site,uninstall_from_list($1) & uninstall_from_menu($1) & uninstall_from_os($1) & uninstall_from_app_settings($1),,
+uninstall_not_locally_installed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,uninstall_from_list & uninstall_from_menu & uninstall_from_os,99,,,,,N/A (Parameterized Action),Site,uninstall_from_list($1) & uninstall_from_menu($1) & uninstall_from_os($1),"Uninstall an app by user, the app can be not locally installed.",
+check_app_in_list_not_locally_installed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,45,,,,,Internal Impl,Site,,"Find the app in the app list (chrome://apps) and check that the given app is in the app list and is not installed. This means the icon is grey, and right clicking on it provides an 'install' option. Win/Mac/Linux only.",
+install_menu_option,SiteA* | SiteAFoo | SiteABar | SiteB,,47,,,,,Internal Impl,InstallableSite,,,
+install_policy_app_tabbed_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,48,,,,,Internal Impl,Site,,"Add a force-installed enterprise policy app to the user profile (must be managed profile). tabbed, with platform shortcut",
+install_policy_app_windowed_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,49,,,,,Internal Impl,Site,,"Add a force-installed enterprise policy app to the user profile (must be managed profile). windowed, with platform shortcut",
+accept_app_id_update_dialog,,,91,,,,,Implemented,,,Click Accept in the App Identity Update dialog,finnur@
+apply_run_on_os_login_policy_allowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,100,,,,,Implemented,Site,,Apply WebAppSettings policy for run_on_os_login to be allowed,phillis@
+apply_run_on_os_login_policy_blocked,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,101,,,,,Implemented,Site,,Apply WebAppSettings policy for run_on_os_login to be blocked,phillis@
+apply_run_on_os_login_policy_run_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,102,,,,,Implemented,Site,,Apply WebAppSettings policy for run_on_os_login to be run_windowed,phillis@
+check_app_icon_site_a_is,Green | Red,,110,,,,,Implemented,Color,,Check that the app icon color is correct,finnur@
+check_app_in_list_tabbed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,11,,,,,Implemented,Site,,"Find the app in the app list (on desktop, this is chrome://apps, and on ChromeOS, this is the app drawer). Check that the app opens in a window by right clicking on it to see if the ""open in window"" option is checked, and by launching it to see if it opens in a separate window.",
+check_app_in_list_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,12,,,,,Implemented,Site,,"Find the app in the app list (on desktop, this is chrome://apps, and on ChromeOS, this is the app drawer). Check that the app opens in a tab by right clicking on it to see if the ""open in window"" option is unchecked, and by launching it to see if it opens in a browser tab (and not a window).",
+check_app_list_empty,,,13,,,,,Implemented,,,"The app list is empty (on desktop, this is chrome://apps, and on ChromeOS, this is the app drawer).",
+check_app_navigation_is_start_url,,,14,,,,,Implemented,,,,
+check_app_not_in_list,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,15,,,,,Implemented,Site,,"Check that the given app is NOT in the app list. On desktop, this is chrome://apps, and on ChromeOS, this is the app drawer.",
+check_app_settings_app_state,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,108,,,,,Implemented,Site,,Check the app shown on app settings page matches the current app state.,phillis@
+check_app_title_site_a_is,SiteA | SiteAUpdated,,79,,,,,Implemented,Title,,Check that the app title is correct,finnur@
+check_browser_navigation_is_app_settings,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,109,,,,,Implemented,Site,,Check the current browser naviagtion is chrome://app-settings/<app-id>,phillis@
+check_custom_toolbar,,,16,,,,,Implemented,,,Check that the PWA window has a custom toolbar to show the out-of-scope url.,
+check_install_icon_not_shown,,,17,,,,,Implemented,,,"Check that the ""Install"" icon in the omnibox is not shown",
+check_install_icon_shown,,,18,,,,,Implemented,,,"Check that the ""Install"" icon in the omnibox is shown",
+check_launch_icon_not_shown,,,19,,,,,Implemented,,,,
+check_launch_icon_shown,,,20,,,,,Implemented,,,,
+check_no_toolbar,,,21,,,,,Implemented,,,,
+check_platform_shortcut_and_icon,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,7,,,,,Implemented,Site,,The icon of the platform shortcut (on the desktop) is correct,"cliffordcheng@, doc"
+check_run_on_os_login_disabled,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,107,,,,,Implemented,Site,,Check run on os login is disabled.,phillis@
+check_run_on_os_login_enabled,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,106,,,,,Implemented,Site,,Check run on os login is enabled.,phillis@
+check_tab_created,,,22,,,,,Implemented,,,A tab was created in a chrome browser window,
+check_tab_not_created,,,94,,,,,Implemented,,,A tab was not created by the last state change action,"cliffordcheng@, P1"
+check_window_closed,,,23,,,,,Implemented,,,The window was closed,
+check_window_created,,,24,,,,,Implemented,,,A window was created.,
+check_window_display_minimal,,,25,,,,,Implemented,,,"Check that the window is a PWA window, and has minimal browser controls.",
+check_window_display_standalone,,,26,,,,,Implemented,,,"Check that the window is a PWA window, and has no browser controls.",
+close_custom_toolbar,,,27,,,,,Implemented,,,Press the 'x' button on the custom toolbar that is towards the top of the WebApp window.,
+close_pwa,,,28,,,,,Implemented,,,Close the WebApp window.,
+disable_run_on_os_login,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,105,,,,,Implemented,Site,,Disable run on os login from app settings page,phillis@
+enable_run_on_os_login,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,104,,,,,Implemented,Site,,Enable run on os login from app settings page,phillis@
+install_create_shortcut_tabbed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,29,,,,,Implemented,Site,,"Install the given app using the""Create Shortcut"" menu option (3-dot->""More Tools""->""Create Shortcut), and de-selecting the ""Open in a window"" checkbox.",
+install_create_shortcut_windowed,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,30,,,,,Implemented,Site,,"Install the given app using the""Create Shortcut"" menu option (3-dot->""More Tools""->""Create Shortcut), and selecting the ""Open in a window"" checkbox.",
+install_locally,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,46,,,,,Implemented,Site,,Find the app in the app list (chrome://apps) and install it by right-clicking on the app and selecting the 'install' option. Win/Mac/Linux only.,
+install_omnibox_icon,SiteA* | SiteAFoo | SiteABar | SiteB,,31,,,,,Implemented,InstallableSite,,,
+install_policy_app_tabbed_no_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,32,,,,,Implemented,Site,,"Add a force-installed enterprise policy app to the user profile (must be managed profile). tabbed, no platform shortcut",
+install_policy_app_windowed_no_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,33,,,,,Implemented,Site,,"Add a force-installed enterprise policy app to the user profile (must be managed profile). windowed, no platform shortcut",
+launch_from_chrome_apps,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,34,,,,,Implemented,Site,,"Launch the web app by navigating to chrome://apps, and then clicking on the app icon.",
+launch_from_launch_icon,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,35,,,,,Implemented,Site,,"Launch the web app by navigating the browser to the web app, and selecting the launch icon in the omnibox (intent picker),",
+launch_from_menu_option,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,69,,,,,Implemented,Site,,"Launch the web app by navigating the browser to the web app, and selecting the ""Launch _"" menu option in the 3-dot menu.","cliffordcheng@, P1"
+launch_from_platform_shortcut,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,1,,,,,Implemented,Site,,Lauch an app from a platform shortcut on the user's desktop or start menu.,"cliffordcheng@, P0"
+manifest_update_display_browser,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,70,,,,,Implemented,Site,,Updates the display property of the manifest to 'browser' on the given site's manifest,"cliffordcheng@, P1"
+manifest_update_display_minimal,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,36,,,,,Implemented,Site,,Updates the display property of the manifest to 'minimal' on the given site's manifest,
+manifest_update_icon,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,68,,,,,Implemented,Site,,Updates the launcher icon in the manifest of the website.,finnur@
+manifest_update_title,SiteA,,88,,,,,Implemented,Site,,The website updates it's manifest.json to change the 'title',finnur@
+navigate_browser,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,37,,,,,Implemented,Site,,Navigate the browser to one of the static sites provided by the testing framework.,
+navigate_notfound_url,,,38,,,,,Implemented,,,Navigate to a url that returns a 404 server error.,
+navigate_pwa_site_a_to,SiteA* | SiteAFoo | SiteABar | SiteB,,39,,,,,Implemented,Site,,Navigates the PWA window of the SiteA pwa to a given site.,
+open_app_settings_from_app_window,,,97,,,,,Implemented,Site,,,phillis@
+open_app_settings_from_chrome_apps,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,96,,,,,Implemented,Site,,,phillis@
+open_in_chrome,,,71,,,,,Implemented,,,Click on the 'open in chrome' link in the 3-dot menu of the app window,"cliffordcheng@, P1"
+remove_run_on_os_login_policy,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,103,,,,,Implemented,Site,,Remove  run_on_os_login policy for the app in WebAppSettings policy.,phillis@
+set_open_in_tab,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,50,,,,,Implemented,Site,,"Uncheck the ""open in window"" checkbox in the right-click menu of the app icon, in the app list page",
+set_open_in_window,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,51,,,,,Implemented,Site,,"Check the ""open in window"" checkbox in the right-click menu of the app icon, in the app list page",
+switch_profile_clients,Client2* | Client1,,40,,,,,Implemented,ProfileClient,,Switch to a different instance of chrome signed in to the same profile,
+sync_turn_off,,,41,,,,,Implemented,,,"Turn chrome sync off for ""Apps"": chrome://settings/syncSetup/advanced",
+sync_turn_on,,,42,,,,,Implemented,,,"Turn chrome sync on for ""Apps"": chrome://settings/syncSetup/advanced",
+uninstall_from_app_settings,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,98,,,,,Implemented,Site,,"uninstall an app from app settings page, the app has to be locally installed.",phillis@
+uninstall_from_list,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,10,,,,,Implemented,Site,,"Uninstall the webapp from wherever apps are listed by chrome. On WML, this is from chrome://apps, and on ChromeOS, this is from the 'launcher'",
+uninstall_from_menu,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,43,,,,,Implemented,Site,,Uninstall the webapp from the 3-dot menu in the webapp window,
+uninstall_policy_app,SiteA* | SiteAFoo | SiteABar | SiteB | SiteC,,44,,,,,Implemented,Site,,Remove a force-installed policy app to the user profile (must be managed profile),
+manifest_update_scope_site_a_foo_to,SiteA* | SiteAFoo | SiteABar,,8,,,,,Awaiting Script Processing,Site,,"Update the scope of site a/foo/, to the given scope",
+navigate_pwa_site_a_foo_to,SiteA* | SiteAFoo | SiteABar | SiteB,,9,,,,,Awaiting Script Processing,Site,,Navigates the PWA window of the SiteAFoo pwa to a given site.,
+check_app_badge_empty,SiteA* | SiteB,,2,,,,,Awaiting Platform Integration,Site,,Check that the 'badge' on the app icon is empty,
+check_app_badge_has_value,SiteA* | SiteB,,3,,,,,Awaiting Platform Integration,Site,,Check that the 'badge' on the app icon has a value,
+clear_app_badge,SiteA* | SiteB,,4,,,,,Awaiting Platform Integration,Site,,The WebApp clears the 'badge' value from it's icon,
+drag_url_to_apps_list,,,5,,,,,Awaiting Platform Integration,,,"Open chrome://apps in a separage window, and drag a url (highlight & drag url from the omnibox) to the chrome://apps page",
+set_app_badge,SiteA* | SiteB,,6,,,,,Awaiting Platform Integration,Site,,Set the app badge for the given site to a value.,
\ No newline at end of file
diff --git a/chrome/test/webapps/data/coverage_required.csv b/chrome/test/webapps/data/coverage_required.csv
index 3ffb07ab..faefaf4 100644
--- a/chrome/test/webapps/data/coverage_required.csv
+++ b/chrome/test/webapps/data/coverage_required.csv
@@ -1,12 +1,12 @@
 # Platforms,Affected-by State Setup (for easy readability / categorization) - not parsed!,Affected-by Edge Action/s 1 - not parsed!,Affected-by Edge Action 2 - not parsed!,Test (actually run by framework),,,,,,,
-WMLC,install_by_user,accept_app_update_dialog,check_window_title_site_a_is(SiteAUpdated),install_by_user(SiteA),manifest_update_title(SiteA),accept_app_update_dialog,close_pwa,launch(SiteA),check_window_title_site_a_is(SiteAUpdated),,
+WMLC,install_by_user_windowed,accept_app_id_update_dialog,check_app_title_site_a_is(SiteAUpdated),install_by_user_windowed(SiteA),manifest_update_title(SiteA),accept_app_id_update_dialog,close_pwa,launch(SiteA),check_app_title_site_a_is(SiteAUpdated),,
 WMLC,set_app_badge,clear_app_badge,check_app_badge_empty,install_by_user_windowed,set_app_badge,clear_app_badge,check_app_badge_empty,,,,
 WMLC,install_windowed & navigate_pwa_site_a_to(SiteB),close_custom_toolbar,check_app_navigation_is_start_url,install_windowed,navigate_pwa_site_a_to(SiteB),close_custom_toolbar,check_app_navigation_is_start_url,,,,
 WMLC,install_no_shortcut,create_shortcuts,check_platform_shortcut_and_icon,install_no_shortcut,create_shortcuts,check_platform_shortcut_and_icon,,,,,
 WMLC,install,delete_profile,check_app_list_empty,install,delete_profile,check_app_list_empty,,,,,
 WMLC,install,delete_profile,check_app_not_in_list,install,delete_profile,check_app_not_in_list,,,,,
 WMLC,install_with_shortcut,delete_profile,check_platform_shortcut_not_exists,install_with_shortcut,delete_profile,check_platform_shortcut_not_exists,,,,,
-WMLC,install_by_user,deny_app_update_dialog,check_app_not_in_list,install_by_user(SiteA),manifest_update_title(SiteA),deny_app_update_dialog,check_app_not_in_list,check_platform_shortcut_not_exists,,,
+WMLC,install_by_user_windowed,deny_app_update_dialog,check_app_not_in_list,install_by_user_windowed(SiteA),manifest_update_title(SiteA),deny_app_update_dialog,check_app_not_in_list,check_platform_shortcut_not_exists,,,
 WMLC,install_policy_app_tabbed,install_by_user_windowed,check_app_in_list_windowed,install_policy_app_tabbed,install_by_user_windowed,check_app_in_list_windowed,,,,,
 WMLC,install_policy_app_tabbed,install_by_user_windowed,check_platform_shortcut_and_icon,install_policy_app_tabbed,install_by_user_windowed,check_platform_shortcut_and_icon,,,,,
 WMLC,install_policy_app_tabbed,install_by_user_windowed,check_window_created,install_policy_app_tabbed,install_by_user_windowed,check_window_created,,,,,
@@ -71,11 +71,11 @@
 WMLC,install_tabbed(SiteC),launch_from_shortcut_or_list(SiteC),check_tab_created,install_tabbed(SiteC),launch_from_shortcut_or_list(SiteC),check_tab_created,,,,,
 WMLC,install_windowed(SiteB),launch(SiteB),check_window_display_minimal,install_windowed(SiteB),launch(SiteB),check_window_display_minimal,,,,,
 WMLC,install_windowed(SiteC),launch(SiteC),check_window_created,install_windowed(SiteC),launch(SiteC),check_window_created,,,,,
-WMLC,install_by_user_windowed,manifest_update_icons,check_app_in_list_icon_correct,install_by_user_windowed,close_pwa,manifest_update_icons,check_app_in_list_icon_correct,,,,
-WMLC,install_by_user_windowed,manifest_update_icons,check_platform_shortcut_and_icon,install_by_user_windowed,close_pwa,manifest_update_icons,check_platform_shortcut_and_icon,,,,
+WMLC,install_by_user_windowed,manifest_update_icon,check_app_in_list_icon_correct,install_by_user_windowed,close_pwa,manifest_update_icon,check_app_in_list_icon_correct,,,,
+WMLC,install_by_user_windowed,manifest_update_icon,check_platform_shortcut_and_icon,install_by_user_windowed,close_pwa,manifest_update_icon,check_platform_shortcut_and_icon,,,,
 WMLC,install_by_user_windowed(SiteAFoo),manifest_update_scope_site_a_foo_to(SiteA),check_install_icon_not_shown,install_by_user_windowed(SiteAFoo),manifest_update_scope_site_a_foo_to(SiteA),close_pwa,launch_from_platform_shortcut(SiteAFoo),close_pwa,navigate_browser(SiteA),check_install_icon_not_shown,
 WMLC,install_by_user_windowed(SiteAFoo),manifest_update_scope_site_a_foo_to(SiteA),check_launch_icon_shown,install_by_user_windowed(SiteAFoo),manifest_update_scope_site_a_foo_to(SiteA),close_pwa,launch_from_platform_shortcut(SiteAFoo),close_pwa,navigate_browser(SiteA),check_launch_icon_shown,
-WMLC,install_policy_app,manifest_update_title(SiteA),check_window_title_site_a_is(SiteAUpdated),install_policy_app(SiteA),manifest_update_title(SiteA),check_update_dialog_not_shown,close_pwa,launch(SiteA),check_window_title_site_a_is(SiteAUpdated),,
+WMLC,install_policy_app,manifest_update_title(SiteA),check_app_title_site_a_is(SiteAUpdated),install_policy_app(SiteA),manifest_update_title(SiteA),check_update_dialog_not_shown,close_pwa,launch(SiteA),check_app_title_site_a_is(SiteAUpdated),,
 WMLC,switch_incognito_profile,navigate_browser(SiteA),check_create_shortcut_not_shown,switch_incognito_profile,navigate_browser(SiteA),check_create_shortcut_not_shown,,,,,
 WMLC,,navigate_browser(SiteA),check_app_not_in_list,navigate_browser(SiteA),check_app_not_in_list,,,,,,
 WMLC,,navigate_browser(SiteA),check_create_shortcut_shown,navigate_browser(SiteA),check_create_shortcut_shown,,,,,,
@@ -102,7 +102,7 @@
 WMLC,,navigate_notfound_url,check_install_icon_not_shown,navigate_notfound_url,check_install_icon_not_shown,,,,,,
 WMLC,install_by_user_windowed(SiteAFoo) & manifest_update_scope_site_a_foo_to(SiteA),navigate_pwa_site_a_foo_to(SiteABar),check_no_toolbar,install_by_user_windowed(SiteAFoo),close_pwa,manifest_update_scope_site_a_foo_to(SiteA),launch(SiteAFoo),navigate_pwa_site_a_foo_to(SiteABar),check_no_toolbar,,
 WMLC,install_by_user_windowed,navigate_pwa_site_a_to(SiteB),check_custom_toolbar,install_by_user_windowed,navigate_pwa_site_a_to(SiteB),check_custom_toolbar,,,,,
-WMLC,install_by_user_windowed,navigate_pwa_site_a_to(SiteB),check_window_title_site_a_is(SiteA),install_by_user_windowed,navigate_pwa_site_a_to(SiteB),check_window_title_site_a_is(SiteA),,,,,
+WMLC,install_by_user_windowed,navigate_pwa_site_a_to(SiteB),check_app_title_site_a_is(SiteA),install_by_user_windowed,navigate_pwa_site_a_to(SiteB),check_app_title_site_a_is(SiteA),,,,,
 WMLC,install_by_user_windowed,open_in_chrome,check_tab_created,install_by_user_windowed,open_in_chrome,check_tab_created,,,,,
 WMLC,install_by_user_windowed & navigate_pwa_site_a_to(SiteB),open_in_chrome,check_tab_created,install_by_user_windowed,navigate_pwa_site_a_to(SiteB),open_in_chrome,check_tab_created,,,,
 WMLC,install_by_user_windowed,set_app_badge,check_app_badge_has_value,install_by_user_windowed,set_app_badge,check_app_badge_has_value,,,,,
diff --git a/chrome/test/webapps/data/framework_supported_actions.csv b/chrome/test/webapps/data/framework_supported_actions.csv
index 4be9722..bf999746 100644
--- a/chrome/test/webapps/data/framework_supported_actions.csv
+++ b/chrome/test/webapps/data/framework_supported_actions.csv
@@ -4,15 +4,16 @@
 check_app_in_list_windowed,                            🌓, 🌓,  🌓,   🌓,
 check_app_list_empty,                                  🌓, 🌓,  🌓,   🌓,
 check_app_not_in_list,                                 🌓, 🌓,  🌓,   🌓,
+check_custom_toolbar,                                  🌕, 🌕,  🌕,   🌕,
 check_install_icon_not_shown,                          🌕, 🌕,  🌕,   🌕,
 check_install_icon_shown,                              🌕, 🌕,  🌕,   🌕,
 check_launch_icon_not_shown,                           🌕, 🌕,  🌕,   🌕,
 check_launch_icon_shown,                               🌕, 🌕,  🌕,   🌕,
 check_app_navigation_is_start_url,                     🌕, 🌕,  🌕,   🌕,
 check_no_toolbar,                                      🌕, 🌕,  🌕,   🌕,
+check_platform_shortcut_and_icon,                      🌕, 🌓,  🌓,   🌓,
 check_tab_created,                                     🌕, 🌕,  🌕,   🌕,
 check_tab_not_created,                                 🌕, 🌕,  🌕,   🌕,
-check_custom_toolbar,                                  🌕, 🌕,  🌕,   🌕,
 check_window_closed,                                   🌕, 🌕,  🌕,   🌕,
 check_window_created,                                  🌕, 🌕,  🌕,   🌕,
 check_window_display_minimal,                          🌕, 🌕,  🌕,   🌕,
diff --git a/chrome/updater/test/integration_tests.cc b/chrome/updater/test/integration_tests.cc
index 3400339..d2d02dd 100644
--- a/chrome/updater/test/integration_tests.cc
+++ b/chrome/updater/test/integration_tests.cc
@@ -259,8 +259,8 @@
     test_commands_->ExpectSelfUpdateSequence(test_server);
   }
 
-  void ExpectRegistrationEvent(ScopedServer* test_server,
-                               const std::string& app_id) {
+  void ExpectInstallEvent(ScopedServer* test_server,
+                          const std::string& app_id) {
     test_server->ExpectOnce(
         {base::BindRepeating(
             RequestMatcherRegex,
@@ -344,14 +344,12 @@
 
 TEST_F(IntegrationTest, QualifyUpdater) {
   ScopedServer test_server(test_commands_);
-  ExpectRegistrationEvent(&test_server, kUpdaterAppId);
   Install();
   ExpectInstalled();
   WaitForUpdaterExit();
   SetupFakeUpdaterLowerVersion();
   ExpectVersionNotActive(kUpdaterVersion);
 
-  ExpectRegistrationEvent(&test_server, kQualificationAppId);
   ExpectUpdateSequence(&test_server, kQualificationAppId, "",
                        base::Version("0.1"), base::Version("0.2"));
 
@@ -374,7 +372,6 @@
 
 TEST_F(IntegrationTest, SelfUpdate) {
   ScopedServer test_server(test_commands_);
-  ExpectRegistrationEvent(&test_server, kUpdaterAppId);
   Install();
 
   base::Version next_version(base::StringPrintf("%s1", kUpdaterVersion));
@@ -397,14 +394,11 @@
   base::test::ScopedRunLoopTimeout timeout(FROM_HERE, base::Seconds(18));
 
   ScopedServer test_server(test_commands_);
-  ExpectRegistrationEvent(&test_server, kUpdaterAppId);
   Install();
   ExpectInstalled();
 
-  // Register apps test1 and test2. Expect registration pings for each.
-  ExpectRegistrationEvent(&test_server, "test1");
+  // Register apps test1 and test2. Expect pings for each.
   InstallApp("test1");
-  ExpectRegistrationEvent(&test_server, "test2");
   InstallApp("test2");
 
   // Set test1 to be active and do a background updatecheck.
@@ -432,11 +426,9 @@
 
 TEST_F(IntegrationTest, UpdateApp) {
   ScopedServer test_server(test_commands_);
-  ExpectRegistrationEvent(&test_server, kUpdaterAppId);
   Install();
 
   const std::string kAppId("test");
-  ExpectRegistrationEvent(&test_server, kAppId);
   InstallApp(kAppId);
   base::Version v1("1");
   ExpectUpdateSequence(&test_server, kAppId, "", base::Version("0.1"), v1);
@@ -457,7 +449,6 @@
 
 TEST_F(IntegrationTest, MultipleWakesOneNetRequest) {
   ScopedServer test_server(test_commands_);
-  ExpectRegistrationEvent(&test_server, kUpdaterAppId);
   Install();
 
   // Only one sequence visible to the server despite multiple wakes.
@@ -471,7 +462,6 @@
 
 TEST_F(IntegrationTest, MultipleUpdateAllsMultipleNetRequests) {
   ScopedServer test_server(test_commands_);
-  ExpectRegistrationEvent(&test_server, kUpdaterAppId);
   Install();
 
   ExpectNoUpdateSequence(&test_server, kUpdaterAppId);
@@ -486,11 +476,9 @@
 #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 TEST_F(IntegrationTest, LegacyUpdate3Web) {
   ScopedServer test_server(test_commands_);
-  ExpectRegistrationEvent(&test_server, kUpdaterAppId);
   Install();
 
   const char kAppId[] = "test1";
-  ExpectRegistrationEvent(&test_server, kAppId);
   InstallApp(kAppId);
 
   ExpectNoUpdateSequence(&test_server, kAppId);
@@ -634,7 +622,13 @@
 #if !defined(COMPONENT_BUILD)
 TEST_F(IntegrationTest, SelfUpdateFromOldReal) {
   ScopedServer test_server(test_commands_);
-  ExpectRegistrationEvent(&test_server, kUpdaterAppId);
+
+  // TODO(crbug.com/1308856): Current versions of the updater do not send an
+  // eventtype=2 event for their own registration, but the old version of the
+  // updater does. When the old version is rolled to a more current version,
+  // this test may start to fail and this expectation can be safely removed.
+  ExpectInstallEvent(&test_server, kUpdaterAppId);
+
   SetupRealUpdaterLowerVersion();
   ExpectVersionNotActive(kUpdaterVersion);
 
@@ -643,7 +637,6 @@
   RunWakeActive(0);
 
   // Qualify the new instance.
-  ExpectRegistrationEvent(&test_server, kQualificationAppId);
   ExpectUpdateSequence(&test_server, kQualificationAppId, "",
                        base::Version("0.1"), base::Version("0.2"));
   RunWake(0);
@@ -668,12 +661,10 @@
 
 TEST_F(IntegrationTest, SameVersionUpdate) {
   ScopedServer test_server(test_commands_);
-  ExpectRegistrationEvent(&test_server, kUpdaterAppId);
   Install();
   ExpectInstalled();
 
   const std::string app_id = "test-appid";
-  ExpectRegistrationEvent(&test_server, app_id);
   InstallApp(app_id);
 
   const std::string response = base::StringPrintf(
@@ -710,14 +701,12 @@
 
 TEST_F(IntegrationTest, InstallDataIndex) {
   ScopedServer test_server(test_commands_);
-  ExpectRegistrationEvent(&test_server, kUpdaterAppId);
   Install();
   ExpectInstalled();
 
   const std::string app_id = "test-appid";
   const std::string install_data_index = "test-install-data-index";
 
-  ExpectRegistrationEvent(&test_server, app_id);
   InstallApp(app_id);
 
   const std::string response = base::StringPrintf(
diff --git a/chrome/updater/update_service_impl.cc b/chrome/updater/update_service_impl.cc
index 4ba2ee9..35fb9e8 100644
--- a/chrome/updater/update_service_impl.cc
+++ b/chrome/updater/update_service_impl.cc
@@ -251,15 +251,7 @@
   crx_component.requires_network_encryption = false;
   crx_component.ap = request.ap;
   crx_component.brand = request.brand_code;
-  update_client_->SendRegistrationPing(
-      crx_component,
-      base::BindOnce(
-          [](base::OnceCallback<void(const RegistrationResponse&)> callback,
-             update_client::Error /*error*/) {
-            // Ping failures do not count as registration failures.
-            std::move(callback).Run(RegistrationResponse(kRegistrationSuccess));
-          },
-          std::move(callback)));
+  std::move(callback).Run(RegistrationResponse(kRegistrationSuccess));
 }
 
 void UpdateServiceImpl::GetAppStates(
@@ -459,6 +451,23 @@
     bool update_blocked) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  // TODO(crbug.com/1311743): The Install case is inferred by the presence of
+  // `PolicySameVersionUpdate::kAllowed` and only having one app.
+  if (policy_same_version_update == PolicySameVersionUpdate::kAllowed &&
+      app_install_data_index.size() == 1) {
+    main_task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &update_client::UpdateClient::Install, update_client_,
+            app_install_data_index.begin()->first,
+            base::BindOnce(&GetComponents, config_, persisted_data_,
+                           app_install_data_index, false, update_blocked,
+                           policy_same_version_update),
+            MakeUpdateClientCrxStateChangeCallback(config_, state_update),
+            MakeUpdateClientCallback(std::move(callback))));
+    return;
+  }
+
   main_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(
diff --git a/chromecast/chromecast.gni b/chromecast/chromecast.gni
index ac2861a..5899f59 100644
--- a/chromecast/chromecast.gni
+++ b/chromecast/chromecast.gni
@@ -168,7 +168,7 @@
   # Subtract out additional Android locales
   cast_locales -= extended_locales
 }
-if (!(is_ios || is_chromeos_ash || is_chromeos_lacros)) {
+if (!(is_ios || is_chromeos)) {
   # Subtract out the additional desktop locales
   cast_locales -= [
     "af",
diff --git a/chromecast/device/bluetooth/le/BUILD.gn b/chromecast/device/bluetooth/le/BUILD.gn
index a1f16be..a9ada32 100644
--- a/chromecast/device/bluetooth/le/BUILD.gn
+++ b/chromecast/device/bluetooth/le/BUILD.gn
@@ -6,30 +6,34 @@
 import("//testing/libfuzzer/fuzzer_test.gni")
 
 cast_source_set("le") {
-  sources = [
-    "ble_notification_logger.cc",
+  public = [
     "ble_notification_logger.h",
     "ble_types.h",
     "gatt_client_manager.h",
     "le_scan_manager.h",
-    "le_scan_result.cc",
     "le_scan_result.h",
     "remote_characteristic.h",
-    "remote_descriptor.cc",
     "remote_descriptor.h",
     "remote_device.h",
     "remote_service.h",
-    "scan_filter.cc",
     "scan_filter.h",
   ]
 
-  public_deps = [ "//chromecast/public" ]
+  sources = [
+    "ble_notification_logger.cc",
+    "le_scan_result.cc",
+    "remote_descriptor.cc",
+    "scan_filter.cc",
+  ]
+
+  public_deps = [
+    "//base",
+    "//chromecast/public",
+  ]
 
   deps = [
-    "//base",
     "//chromecast/base",
     "//chromecast/device/bluetooth:util",
-    "//chromecast/public",
     "//third_party/re2",
   ]
 }
diff --git a/chromeos/dbus/config/BUILD.gn b/chromeos/dbus/config/BUILD.gn
index 4875c4d..6aca8f0 100644
--- a/chromeos/dbus/config/BUILD.gn
+++ b/chromeos/dbus/config/BUILD.gn
@@ -5,7 +5,7 @@
 import("//build/config/chromeos/ui_mode.gni")
 import("use_real_dbus_clients.gni")
 
-assert(is_chromeos_ash || is_chromeos_lacros,
+assert(is_chromeos,
        "Non-Chrome-OS or Lacros builds must not depend on //chromeos")
 
 config("use_real_dbus_clients_config") {
diff --git a/chromeos/dbus/permission_broker/BUILD.gn b/chromeos/dbus/permission_broker/BUILD.gn
index 56756df..c3bf137 100644
--- a/chromeos/dbus/permission_broker/BUILD.gn
+++ b/chromeos/dbus/permission_broker/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//third_party/protobuf/proto_library.gni")
 
-assert(is_chromeos_ash || is_chromeos_lacros,
+assert(is_chromeos,
        "Non-Chrome-OS or Lacros builds must not depend on //chromeos")
 
 component("permission_broker") {
diff --git a/chromeos/process_proxy/BUILD.gn b/chromeos/process_proxy/BUILD.gn
index a777825..bff38db6 100644
--- a/chromeos/process_proxy/BUILD.gn
+++ b/chromeos/process_proxy/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//build/config/chromeos/ui_mode.gni")
 
-assert(is_chromeos_ash || is_chromeos_lacros,
+assert(is_chromeos,
        "Non-Chrome-OS or Lacros builds must not depend on //chromeos")
 
 component("process_proxy") {
diff --git a/chromeos/ui/base/BUILD.gn b/chromeos/ui/base/BUILD.gn
index 17646680..ce58a77 100644
--- a/chromeos/ui/base/BUILD.gn
+++ b/chromeos/ui/base/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//build/config/chromeos/ui_mode.gni")
 
-assert(is_chromeos_ash || is_chromeos_lacros,
+assert(is_chromeos,
        "Non-Chrome-OS or Lacros builds must not depend on //chromeos")
 
 # C++ headers and sources that can be used by both ash and lacros builds.
diff --git a/chromeos/ui/frame/BUILD.gn b/chromeos/ui/frame/BUILD.gn
index 161fe73..5c6a8084 100644
--- a/chromeos/ui/frame/BUILD.gn
+++ b/chromeos/ui/frame/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//build/config/chromeos/ui_mode.gni")
 
-assert(is_chromeos_ash || is_chromeos_lacros,
+assert(is_chromeos,
        "Non-Chrome-OS or Lacros builds must not depend on //chromeos")
 
 # C++ headers and sources that can be used by both ash and lacros builds.
diff --git a/chromeos/ui/frame/frame_header.cc b/chromeos/ui/frame/frame_header.cc
index 80f995c..e734fe3 100644
--- a/chromeos/ui/frame/frame_header.cc
+++ b/chromeos/ui/frame/frame_header.cc
@@ -375,7 +375,7 @@
   caption_button_container_->SetButtonImage(views::CAPTION_BUTTON_ICON_MINIMIZE,
                                             views::kWindowControlMinimizeIcon);
   caption_button_container_->SetButtonImage(views::CAPTION_BUTTON_ICON_MENU,
-                                            chromeos::kWindowControlMenuIcon);
+                                            chromeos::kFloatWindowIcon);
   caption_button_container_->SetButtonImage(views::CAPTION_BUTTON_ICON_CLOSE,
                                             views::kWindowControlCloseIcon);
   UpdateSnapIcons();
diff --git a/chromeos/ui/vector_icons/BUILD.gn b/chromeos/ui/vector_icons/BUILD.gn
index 65365e9e..393673d 100644
--- a/chromeos/ui/vector_icons/BUILD.gn
+++ b/chromeos/ui/vector_icons/BUILD.gn
@@ -40,6 +40,7 @@
     "filetype_tini.icon",
     "filetype_video.icon",
     "filetype_word.icon",
+    "float_window.icon",
     "keyboard_shortcuts.icon",
     "notification_assistant.icon",
     "notification_supervised_user.icon",
@@ -54,7 +55,6 @@
     "window_control_bottom_snapped.icon",
     "window_control_dezoom.icon",
     "window_control_left_snapped.icon",
-    "window_control_menu.icon",
     "window_control_right_snapped.icon",
     "window_control_top_snapped.icon",
     "window_control_zoom.icon",
diff --git a/chromeos/ui/vector_icons/window_control_menu.icon b/chromeos/ui/vector_icons/float_window.icon
similarity index 100%
rename from chromeos/ui/vector_icons/window_control_menu.icon
rename to chromeos/ui/vector_icons/float_window.icon
diff --git a/chromeos/ui/wm/BUILD.gn b/chromeos/ui/wm/BUILD.gn
index 5ce3a15..5dff115 100644
--- a/chromeos/ui/wm/BUILD.gn
+++ b/chromeos/ui/wm/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//build/config/chromeos/ui_mode.gni")
 
-assert(is_chromeos_ash || is_chromeos_lacros,
+assert(is_chromeos,
        "Non-Chrome-OS or Lacros builds must not depend on //chromeos")
 
 # C++ headers and sources that can be used by both ash and lacros builds.
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 10964557..34b8ee4 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -525,7 +525,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     deps += [
       "//components/account_manager_core:unit_tests",
       "//components/arc/common:unit_tests",
diff --git a/components/account_manager_core/BUILD.gn b/components/account_manager_core/BUILD.gn
index c342842..f7810c07 100644
--- a/components/account_manager_core/BUILD.gn
+++ b/components/account_manager_core/BUILD.gn
@@ -6,7 +6,7 @@
 import("//build/config/ui.gni")
 import("//third_party/protobuf/proto_library.gni")
 
-assert(is_chromeos_ash || is_chromeos_lacros)
+assert(is_chromeos)
 
 component("account_manager_core") {
   sources = [
diff --git a/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.cc b/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.cc
index c393815..4282aca 100644
--- a/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.cc
+++ b/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.cc
@@ -6,7 +6,6 @@
 
 #include <string.h>
 
-#include <memory>
 #include <string>
 
 #include "base/bind.h"
@@ -32,44 +31,30 @@
 // Minimum time between breadcrumb writes to disk.
 constexpr auto kMinDelayBetweenWrites = base::Milliseconds(250);
 
-// Writes |events| to |file_path| at |position|.
-void DoInsertEventsIntoMemoryMappedFile(const base::FilePath& file_path,
-                                        const size_t position,
-                                        const std::string& events) {
-  auto file = std::make_unique<base::MemoryMappedFile>();
-  const base::MemoryMappedFile::Region region = {0, kPersistedFilesizeInBytes};
-  const bool file_valid = file->Initialize(
-      base::File(file_path, base::File::FLAG_OPEN_ALWAYS |
-                                base::File::FLAG_READ | base::File::FLAG_WRITE),
-      region, base::MemoryMappedFile::READ_WRITE_EXTEND);
-
-  if (file_valid) {
-    char* data = reinterpret_cast<char*>(file->data());
-    strcpy(&data[position], events.data());
-  }
-}
-
-// Writes |events| to |file_path| overwriting any existing data.
+// Writes the given |events| to |file_path| at |position|. If |append| is false,
+// the existing file will be overwritten.
 void DoWriteEventsToFile(const base::FilePath& file_path,
-                         const std::string& events) {
+                         const size_t position,
+                         const std::string& events,
+                         const bool append) {
   const base::MemoryMappedFile::Region region = {0, kPersistedFilesizeInBytes};
   base::MemoryMappedFile file;
-  const bool file_valid = file.Initialize(
-      base::File(file_path, base::File::FLAG_CREATE_ALWAYS |
-                                base::File::FLAG_READ | base::File::FLAG_WRITE),
-      region, base::MemoryMappedFile::READ_WRITE_EXTEND);
+  int flags = base::File::FLAG_READ | base::File::FLAG_WRITE;
+  if (append) {
+    flags |= base::File::FLAG_OPEN_ALWAYS;
+  } else {
+    flags |= base::File::FLAG_CREATE_ALWAYS;
+  }
+  const bool file_valid =
+      file.Initialize(base::File(file_path, flags), region,
+                      base::MemoryMappedFile::READ_WRITE_EXTEND);
 
   if (file_valid) {
     char* data = reinterpret_cast<char*>(file.data());
-    strcpy(data, events.data());
+    strcpy(&data[position], events.data());
   }
 }
 
-void DoReplaceFile(const base::FilePath& from_path,
-                   const base::FilePath& to_path) {
-  base::ReplaceFile(from_path, to_path, nullptr);
-}
-
 // Returns breadcrumb events stored at |file_path|.
 std::vector<std::string> DoGetStoredEvents(const base::FilePath& file_path) {
   base::File events_file(file_path,
@@ -80,24 +65,22 @@
   }
 
   size_t file_size = events_file.GetLength();
-  if (file_size <= 0) {
+  if (file_size <= 0)
     return std::vector<std::string>();
-  }
 
   // Do not read more than |kPersistedFilesizeInBytes|, in case the file was
   // corrupted. If |kPersistedFilesizeInBytes| has been reduced since the last
   // breadcrumbs file was saved, this could result in a one time loss of the
   // oldest breadcrumbs which is ok because the decision has already been made
   // to reduce the size of the stored breadcrumbs.
-  if (file_size > kPersistedFilesizeInBytes) {
+  if (file_size > kPersistedFilesizeInBytes)
     file_size = kPersistedFilesizeInBytes;
-  }
 
   std::vector<uint8_t> data;
   data.resize(file_size);
-  if (!events_file.ReadAndCheck(/*offset=*/0, data)) {
+  if (!events_file.ReadAndCheck(/*offset=*/0, data))
     return std::vector<std::string>();
-  }
+
   const std::string persisted_events(data.begin(), data.end());
   const std::string all_events =
       persisted_events.substr(/*pos=*/0, strlen(persisted_events.c_str()));
@@ -112,29 +95,25 @@
 size_t DoGetStoredEventsLength(const base::FilePath& file_path) {
   base::File events_file(file_path,
                          base::File::FLAG_OPEN | base::File::FLAG_READ);
-  if (!events_file.IsValid()) {
+  if (!events_file.IsValid())
     return 0;
-  }
 
   size_t file_size = events_file.GetLength();
-  if (file_size <= 0) {
+  if (file_size <= 0)
     return 0;
-  }
 
   // Do not read more than |kPersistedFilesizeInBytes|, in case the file was
   // corrupted. If |kPersistedFilesizeInBytes| has been reduced since the last
   // breadcrumbs file was saved, this could result in a one time loss of the
   // oldest breadcrumbs which is ok because the decision has already been made
   // to reduce the size of the stored breadcrumbs.
-  if (file_size > kPersistedFilesizeInBytes) {
+  if (file_size > kPersistedFilesizeInBytes)
     file_size = kPersistedFilesizeInBytes;
-  }
 
   std::vector<uint8_t> data;
   data.resize(file_size);
-  if (!events_file.ReadAndCheck(/*offset=*/0, data)) {
+  if (!events_file.ReadAndCheck(/*offset=*/0, data))
     return 0;
-  }
 
   const std::string persisted_events(data.begin(), data.end());
   return strlen(persisted_events.c_str());
@@ -221,17 +200,14 @@
 void BreadcrumbPersistentStorageManager::CombineEventsAndRewriteAllBreadcrumbs(
     const std::vector<std::string> pending_breadcrumbs,
     std::vector<std::string> existing_events) {
-  // Add events which had not yet been written.
-  for (const std::string& event : pending_breadcrumbs) {
-    existing_events.push_back(event);
-  }
+  existing_events.insert(existing_events.end(), pending_breadcrumbs.begin(),
+                         pending_breadcrumbs.end());
 
   std::vector<std::string> breadcrumbs;
   for (const std::string& event : base::Reversed(existing_events)) {
-    // Reduce saved events to only fill the amount which would be included on
-    // a crash log. This allows future events to be appended individually up
-    // to |kPersistedFilesizeInBytes|, which is more efficient than writing
-    // out the
+    // Reduce saved events to only the amount that can be included in a crash
+    // report. This allows future events to be appended up to
+    // |kPersistedFilesizeInBytes|, reducing the number of resizes needed.
     const int event_with_seperator_size =
         event.size() + strlen(kEventSeparator);
     if (event_with_seperator_size + file_position_.value() >= kMaxDataLength)
@@ -245,13 +221,15 @@
   std::reverse(breadcrumbs.begin(), breadcrumbs.end());
   const std::string breadcrumbs_string = base::JoinString(breadcrumbs, "");
 
-  task_runner_->PostTask(FROM_HERE, base::BindOnce(&DoWriteEventsToFile,
-                                                   breadcrumbs_temp_file_path_,
-                                                   breadcrumbs_string));
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&DoWriteEventsToFile, breadcrumbs_temp_file_path_,
+                     /*position=*/0, breadcrumbs_string, /*append=*/false));
 
   task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&DoReplaceFile, breadcrumbs_temp_file_path_,
-                                breadcrumbs_file_path_));
+      FROM_HERE, base::BindOnce(IgnoreResult(&base::ReplaceFile),
+                                breadcrumbs_temp_file_path_,
+                                breadcrumbs_file_path_, /*error=*/nullptr));
 }
 
 void BreadcrumbPersistentStorageManager::RewriteAllExistingBreadcrumbs() {
@@ -276,18 +254,16 @@
 }
 
 void BreadcrumbPersistentStorageManager::WritePendingBreadcrumbs() {
-  if (pending_breadcrumbs_.empty()) {
+  if (pending_breadcrumbs_.empty())
     return;
-  }
 
-  // Make a copy of |pending_breadcrumbs_| to pass to the
-  // DoInsertEventsIntoMemoryMappedFile() callback, since |pending_breadcrumbs_|
-  // is about to be cleared.
+  // Make a copy of |pending_breadcrumbs_| to pass to the DoWriteEventsToFile()
+  // callback, since |pending_breadcrumbs_| is about to be cleared.
   const std::string pending_breadcrumbs = pending_breadcrumbs_;
   task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&DoInsertEventsIntoMemoryMappedFile,
-                                breadcrumbs_file_path_, file_position_.value(),
-                                pending_breadcrumbs));
+      FROM_HERE, base::BindOnce(&DoWriteEventsToFile, breadcrumbs_file_path_,
+                                file_position_.value(), pending_breadcrumbs,
+                                /*append=*/true));
 
   file_position_ = file_position_.value() + pending_breadcrumbs_.size();
   last_written_time_ = base::TimeTicks::Now();
@@ -297,12 +273,7 @@
 
 void BreadcrumbPersistentStorageManager::EventAdded(BreadcrumbManager* manager,
                                                     const std::string& event) {
-  WriteEvent(event);
-}
-
-void BreadcrumbPersistentStorageManager::WriteEvent(const std::string& event) {
   pending_breadcrumbs_ += event + kEventSeparator;
-
   WriteEvents();
 }
 
@@ -331,19 +302,20 @@
         FROM_HERE, kMinDelayBetweenWrites - time_delta_since_last_write,
         base::BindOnce(&BreadcrumbPersistentStorageManager::WriteEvents,
                        weak_ptr_factory_.GetWeakPtr()));
-  } else {
-    // If the event does not fit within |kPersistedFilesizeInBytes|, rewrite the
-    // file to trim old events.
-    if ((file_position_.value() + pending_breadcrumbs_.size())
-        // Use >= here instead of > to allow space for \0 to terminate file.
-        >= kPersistedFilesizeInBytes) {
-      RewriteAllExistingBreadcrumbs();
-      return;
-    }
-
-    // Otherwise, simply append the pending breadcrumbs.
-    WritePendingBreadcrumbs();
+    return;
   }
+
+  // If the event does not fit within |kPersistedFilesizeInBytes|, rewrite the
+  // file to trim old events.
+  if ((file_position_.value() + pending_breadcrumbs_.size())
+      // Use >= here instead of > to allow space for \0 to terminate file.
+      >= kPersistedFilesizeInBytes) {
+    RewriteAllExistingBreadcrumbs();
+    return;
+  }
+
+  // Otherwise, simply append the pending breadcrumbs.
+  WritePendingBreadcrumbs();
 }
 
 void BreadcrumbPersistentStorageManager::OldEventsRemoved(
diff --git a/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.h b/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.h
index 29e96a58..b2a470e 100644
--- a/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.h
+++ b/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.h
@@ -89,10 +89,6 @@
   // Writes breadcrumbs stored in |pending_breadcrumbs_| to |breadcrumbs_file_|.
   void WritePendingBreadcrumbs();
 
-  // Writes |event| to |breadcrumbs_file_|.
-  // NOTE: Writing may be delayed if the file has recently been written into.
-  void WriteEvent(const std::string& event);
-
   // BreadcrumbManagerObserver
   void EventAdded(BreadcrumbManager* manager,
                   const std::string& event) override;
diff --git a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialogTest.java b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialogTest.java
index d120ca7..0290f0f 100644
--- a/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialogTest.java
+++ b/components/browser_ui/photo_picker/android/java/src/org/chromium/components/browser_ui/photo_picker/PhotoPickerDialogTest.java
@@ -67,6 +67,7 @@
 
     // The timeout (in seconds) to wait for the decoder service to be ready.
     private static final long WAIT_TIMEOUT_SECONDS = 30L;
+    private static final long VIDEO_TIMEOUT_SECONDS = 10L;
 
     @Rule
     public RenderTestRule mRenderTestRule =
@@ -348,7 +349,8 @@
         int callCount = mOnVideoPlayingCallback.getCallCount();
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> { mDialog.getCategoryViewForTesting().startVideoPlaybackAsync(uri); });
-        mOnVideoPlayingCallback.waitForCallback(callCount, 1);
+        mOnVideoPlayingCallback.waitForCallback(
+                callCount, 1, VIDEO_TIMEOUT_SECONDS, TimeUnit.SECONDS);
     }
 
     private void dismissDialog() {
diff --git a/components/browser_ui/widget/android/java/res/values/styles.xml b/components/browser_ui/widget/android/java/res/values/styles.xml
index 8b80d3d5..373ae0a5 100644
--- a/components/browser_ui/widget/android/java/res/values/styles.xml
+++ b/components/browser_ui/widget/android/java/res/values/styles.xml
@@ -24,9 +24,6 @@
         <item name="android:buttonBarButtonStyle">@style/AlertDialogButtonStyle</item>
         <item name="buttonBarButtonStyle">@style/AlertDialogButtonStyle</item>
     </style>
-    <!-- TODO(https://crbug.com/1242702): Remove this once the style in downstream that depends on
-         this is removed. -->
-    <style name="Theme.Chromium.AlertDialog" parent="ThemeOverlay.BrowserUI.AlertDialog" tools:ignore="UnusedResources"/>
 
     <style name="ThemeOverlay.BrowserUI.AlertDialog.NoActionBar">
         <item name="windowNoTitle">true</item>
diff --git a/components/component_updater/component_installer_unittest.cc b/components/component_updater/component_installer_unittest.cc
index 51c206c..5d5d372 100644
--- a/components/component_updater/component_installer_unittest.cc
+++ b/components/component_updater/component_installer_unittest.cc
@@ -100,12 +100,6 @@
     std::move(callback).Run(update_client::Error::NONE);
   }
 
-  void SendRegistrationPing(const CrxComponent& crx_component,
-                            Callback callback) override {
-    DoSendRegistrationPing(crx_component);
-    std::move(callback).Run(update_client::Error::NONE);
-  }
-
   MOCK_METHOD1(AddObserver, void(Observer* observer));
   MOCK_METHOD1(RemoveObserver, void(Observer* observer));
   MOCK_METHOD2(DoInstall,
@@ -120,7 +114,6 @@
   MOCK_METHOD0(Stop, void());
   MOCK_METHOD2(DoSendUninstallPing,
                void(const CrxComponent& crx_component, int reason));
-  MOCK_METHOD1(DoSendRegistrationPing, void(const CrxComponent& crx_component));
 
  private:
   ~MockUpdateClient() override = default;
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc
index 9a51df3..75933e3 100644
--- a/components/cronet/url_request_context_config.cc
+++ b/components/cronet/url_request_context_config.cc
@@ -161,8 +161,6 @@
 
 const char kSSLKeyLogFile[] = "ssl_key_log_file";
 
-const char kGoAwayOnPathDegrading[] = "go_away_on_path_degrading";
-
 const char kAllowPortMigration[] = "allow_port_migration";
 
 const char kDisableTlsZeroRtt[] = "disable_tls_zero_rtt";
@@ -506,9 +504,6 @@
       quic_params->goaway_sessions_on_ip_change =
           quic_args.FindBoolKey(kQuicGoAwaySessionsOnIpChange)
               .value_or(quic_params->goaway_sessions_on_ip_change);
-      quic_params->go_away_on_path_degrading =
-          quic_args.FindBoolKey(kGoAwayOnPathDegrading)
-              .value_or(quic_params->go_away_on_path_degrading);
       quic_params->allow_server_migration =
           quic_args.FindBoolKey(kQuicAllowServerMigration)
               .value_or(quic_params->allow_server_migration);
diff --git a/components/cronet/url_request_context_config_unittest.cc b/components/cronet/url_request_context_config_unittest.cc
index e2641e7..78618de 100644
--- a/components/cronet/url_request_context_config_unittest.cc
+++ b/components/cronet/url_request_context_config_unittest.cc
@@ -219,7 +219,6 @@
   EXPECT_FALSE(quic_params->migrate_idle_sessions);
   EXPECT_FALSE(quic_params->retry_on_alternate_network_before_handshake);
   EXPECT_FALSE(quic_params->race_stale_dns_on_connection);
-  EXPECT_FALSE(quic_params->go_away_on_path_degrading);
   EXPECT_FALSE(quic_params->allow_port_migration);
   EXPECT_FALSE(quic_params->disable_tls_zero_rtt);
   EXPECT_TRUE(quic_params->retry_without_alt_svc_on_quic_errors);
@@ -1203,56 +1202,6 @@
   EXPECT_TRUE(quic_params->disable_tls_zero_rtt);
 }
 
-TEST(URLRequestContextConfigTest, SetQuicGoawayOnPathDegrading) {
-  base::test::TaskEnvironment task_environment_(
-      base::test::TaskEnvironment::MainThreadType::IO);
-
-  std::unique_ptr<URLRequestContextConfig> config =
-      URLRequestContextConfig::CreateURLRequestContextConfig(
-          // Enable QUIC.
-          true,
-          // QUIC User Agent ID.
-          "Default QUIC User Agent ID",
-          // Enable SPDY.
-          true,
-          // Enable Brotli.
-          false,
-          // Type of http cache.
-          URLRequestContextConfig::HttpCacheType::DISK,
-          // Max size of http cache in bytes.
-          1024000,
-          // Disable caching for HTTP responses. Other information may be stored
-          // in the cache.
-          false,
-          // Storage path for http cache and cookie storage.
-          "/data/data/org.chromium.net/app_cronet_test/test_storage",
-          // Accept-Language request header field.
-          "foreign-language",
-          // User-Agent request header field.
-          "fake agent",
-          // JSON encoded experimental options.
-          "{\"QUIC\":{\"go_away_on_path_degrading\":true}}",
-          // MockCertVerifier to use for testing purposes.
-          std::unique_ptr<net::CertVerifier>(),
-          // Enable network quality estimator.
-          false,
-          // Enable Public Key Pinning bypass for local trust anchors.
-          true,
-          // Optional network thread priority.
-          absl::optional<double>());
-
-  net::URLRequestContextBuilder builder;
-  config->ConfigureURLRequestContextBuilder(&builder);
-  // Set a ProxyConfigService to avoid DCHECK failure when building.
-  builder.set_proxy_config_service(
-      std::make_unique<net::ProxyConfigServiceFixed>(
-          net::ProxyConfigWithAnnotation::CreateDirect()));
-  std::unique_ptr<net::URLRequestContext> context(builder.Build());
-  const net::QuicParams* quic_params = context->quic_context()->params();
-
-  EXPECT_TRUE(quic_params->go_away_on_path_degrading);
-}
-
 TEST(URLRequestContextConfigTest, SetQuicHostWhitelist) {
   base::test::TaskEnvironment task_environment_(
       base::test::TaskEnvironment::MainThreadType::IO);
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index f3e3dd5..1a4b36d 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -152,6 +152,7 @@
       "//components/fullscreen_control",
       "//components/strings",
       "//ui/base",
+      "//ui/base:hit_test",
       "//ui/events/ozone/layout",
     ]
     sources += [
@@ -159,6 +160,8 @@
       "client_controlled_accelerators.h",
       "client_controlled_shell_surface.cc",
       "client_controlled_shell_surface.h",
+      "custom_window_state_delegate.cc",
+      "custom_window_state_delegate.h",
       "extended_drag_offer.cc",
       "extended_drag_offer.h",
       "extended_drag_source.cc",
@@ -183,6 +186,9 @@
       "shell_surface.h",
       "shell_surface_base.cc",
       "shell_surface_base.h",
+      "shell_surface_observer.h",
+      "shell_surface_presentation_time_recorder.cc",
+      "shell_surface_presentation_time_recorder.h",
       "text_input.cc",
       "text_input.h",
       "toast_surface.cc",
@@ -322,6 +328,7 @@
       "pointer_unittest.cc",
       "seat_unittest.cc",
       "shared_memory_unittest.cc",
+      "shell_surface_presentation_time_recorder_unittest.cc",
       "shell_surface_unittest.cc",
       "shell_surface_util_unittest.cc",
       "sub_surface_unittest.cc",
diff --git a/components/exo/custom_window_state_delegate.cc b/components/exo/custom_window_state_delegate.cc
new file mode 100644
index 0000000..e05e98f7
--- /dev/null
+++ b/components/exo/custom_window_state_delegate.cc
@@ -0,0 +1,49 @@
+// 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/exo/custom_window_state_delegate.h"
+
+#include "ash/shell.h"
+#include "ash/shell_delegate.h"
+#include "ash/wm/window_state.h"
+#include "components/exo/shell_surface_presentation_time_recorder.h"
+#include "ui/base/hit_test.h"
+
+namespace exo {
+
+CustomWindowStateDelegate::CustomWindowStateDelegate()
+    : CustomWindowStateDelegate(nullptr) {}
+
+CustomWindowStateDelegate::CustomWindowStateDelegate(
+    ShellSurface* shell_surface)
+    : shell_surface_(shell_surface) {}
+
+CustomWindowStateDelegate::~CustomWindowStateDelegate() = default;
+
+bool CustomWindowStateDelegate::ToggleFullscreen(
+    ash::WindowState* window_state) {
+  return false;
+}
+
+void CustomWindowStateDelegate::ToggleLockedFullscreen(
+    ash::WindowState* window_state) {
+  // Sets up the shell environment as appropriate for locked Lacros or Ash
+  // chrome sessions including disabling ARC.
+  ash::Shell::Get()->shell_delegate()->SetUpEnvironmentForLockedFullscreen(
+      window_state->IsPinned());
+}
+
+std::unique_ptr<ash::PresentationTimeRecorder>
+CustomWindowStateDelegate::OnDragStarted(int component) {
+  if (!shell_surface_ || !ui::IsResizingComponent(component))
+    return nullptr;
+
+  return std::make_unique<ShellSurfacePresentationTimeRecorder>(
+      shell_surface_,
+      ShellSurfacePresentationTimeRecorder::CreateHistogramReporter(
+          "Ash.InteractiveWindowResize.Lacros.TimeToPresent",
+          "Ash.InteractiveWindowResize.Lacros.TimeToPresent.MaxLatency"));
+}
+
+}  // namespace exo
diff --git a/components/exo/custom_window_state_delegate.h b/components/exo/custom_window_state_delegate.h
new file mode 100644
index 0000000..58d60aea
--- /dev/null
+++ b/components/exo/custom_window_state_delegate.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 COMPONENTS_EXO_CUSTOM_WINDOW_STATE_DELEGATE_H_
+#define COMPONENTS_EXO_CUSTOM_WINDOW_STATE_DELEGATE_H_
+
+#include "ash/wm/window_state_delegate.h"
+
+namespace exo {
+class ShellSurface;
+
+// CustomWindowStateDelegate for ShellSurface to override default fullscreen
+// behavior and optionally provide a resize presentation time recorder for
+// ShellSurface.
+class CustomWindowStateDelegate : public ash::WindowStateDelegate {
+ public:
+  CustomWindowStateDelegate();
+  explicit CustomWindowStateDelegate(ShellSurface* shell_surface);
+
+  CustomWindowStateDelegate(const CustomWindowStateDelegate&) = delete;
+  CustomWindowStateDelegate& operator=(const CustomWindowStateDelegate&) =
+      delete;
+
+  ~CustomWindowStateDelegate() override;
+
+  // ash::WindowStateDelegate:
+  bool ToggleFullscreen(ash::WindowState* window_state) override;
+  void ToggleLockedFullscreen(ash::WindowState* window_state) override;
+  std::unique_ptr<ash::PresentationTimeRecorder> OnDragStarted(
+      int component) override;
+
+ private:
+  ShellSurface* const shell_surface_;
+};
+
+}  //  namespace exo
+
+#endif  // COMPONENTS_EXO_CUSTOM_WINDOW_STATE_DELEGATE_H_
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index 30dba51a..951683e2 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -18,6 +18,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "chromeos/ui/base/window_state_type.h"
+#include "components/exo/custom_window_state_delegate.h"
 #include "components/exo/shell_surface_util.h"
 #include "components/exo/window_properties.h"
 #include "ui/aura/client/aura_constants.h"
@@ -125,6 +126,9 @@
   origin_change_callback_.Reset();
   if (widget_)
     ash::WindowState::Get(widget_->GetNativeWindow())->RemoveObserver(this);
+
+  for (auto& observer : observers_)
+    observer.OnShellSurfaceDestroyed();
 }
 
 void ShellSurface::AcknowledgeConfigure(uint32_t serial) {
@@ -149,6 +153,9 @@
       break;
   }
 
+  for (auto& observer : observers_)
+    observer.OnAcknowledgeConfigure(serial);
+
   // Shadow bounds update should be called in the next Commit() when applying
   // config instead of updating right when the client acknowledge the config.
 }
@@ -264,6 +271,14 @@
   AttemptToStartDrag(component);
 }
 
+void ShellSurface::AddObserver(ShellSurfaceObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ShellSurface::RemoveObserver(ShellSurfaceObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // SurfaceDelegate overrides:
 
@@ -527,6 +542,14 @@
   return true;
 }
 
+std::unique_ptr<views::NonClientFrameView>
+ShellSurface::CreateNonClientFrameView(views::Widget* widget) {
+  ash::WindowState* window_state =
+      ash::WindowState::Get(widget->GetNativeWindow());
+  window_state->SetDelegate(std::make_unique<CustomWindowStateDelegate>(this));
+  return CreateNonClientFrameViewInternal(widget);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // ShellSurface, private:
 
@@ -604,6 +627,9 @@
   LOG_IF(WARNING, pending_configs_.size() > 100)
       << "Number of pending configure acks for shell surface has reached: "
       << pending_configs_.size();
+
+  for (auto& observer : observers_)
+    observer.OnConfigure(serial);
 }
 
 void ShellSurface::AttemptToStartDrag(int component) {
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h
index 73d8eab..ca81f8f 100644
--- a/components/exo/shell_surface.h
+++ b/components/exo/shell_surface.h
@@ -8,7 +8,9 @@
 #include "ash/wm/toplevel_window_event_handler.h"
 #include "ash/wm/window_state_observer.h"
 #include "base/containers/circular_deque.h"
+#include "base/observer_list.h"
 #include "components/exo/shell_surface_base.h"
+#include "components/exo/shell_surface_observer.h"
 #include "ui/base/ui_base_types.h"
 
 namespace ash {
@@ -101,6 +103,9 @@
   // Return the initial show state for this surface.
   ui::WindowShowState initial_show_state() { return initial_show_state_; }
 
+  void AddObserver(ShellSurfaceObserver* observer);
+  void RemoveObserver(ShellSurfaceObserver* observer);
+
   // Overridden from SurfaceDelegate:
   void OnSetParent(Surface* parent, const gfx::Point& position) override;
 
@@ -129,6 +134,8 @@
   // Overridden from ShellSurfaceBase:
   void SetWidgetBounds(const gfx::Rect& bounds) override;
   bool OnPreWidgetCommit() override;
+  std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView(
+      views::Widget* widget) override;
 
  private:
   struct Config;
@@ -186,6 +193,8 @@
   int pending_resize_component_ = HTCAPTION;
   ui::WindowShowState initial_show_state_ = ui::SHOW_STATE_DEFAULT;
   bool ignore_window_bounds_changes_ = false;
+
+  base::ObserverList<ShellSurfaceObserver> observers_;
 };
 
 }  // namespace exo
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 389d289..8b6d262 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -17,7 +17,6 @@
 #include "ash/public/cpp/window_properties.h"
 #include "ash/screen_util.h"
 #include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ash/wm/desks/desks_controller.h"
 #include "ash/wm/desks/desks_util.h"
 #include "ash/wm/drag_window_resizer.h"
@@ -25,7 +24,6 @@
 #include "ash/wm/screen_pinning_controller.h"
 #include "ash/wm/window_resizer.h"
 #include "ash/wm/window_state.h"
-#include "ash/wm/window_state_delegate.h"
 #include "ash/wm/window_util.h"
 #include "base/check.h"
 #include "base/logging.h"
@@ -45,6 +43,7 @@
 #include "components/app_restore/app_restore_info.h"
 #include "components/app_restore/app_restore_utils.h"
 #include "components/app_restore/window_properties.h"
+#include "components/exo/custom_window_state_delegate.h"
 #include "components/exo/shell_surface_util.h"
 #include "components/exo/surface.h"
 #include "components/exo/window_properties.h"
@@ -279,33 +278,6 @@
   views::Widget* const widget_;
 };
 
-// A place holder to disable default implementation created by
-// ash::NonClientFrameViewAsh, which triggers immersive fullscreen etc, which
-// we don't need.
-class CustomWindowStateDelegate : public ash::WindowStateDelegate {
- public:
-  CustomWindowStateDelegate() {}
-
-  CustomWindowStateDelegate(const CustomWindowStateDelegate&) = delete;
-  CustomWindowStateDelegate& operator=(const CustomWindowStateDelegate&) =
-      delete;
-
-  ~CustomWindowStateDelegate() override {}
-
-  // Overridden from ash::WindowStateDelegate:
-  bool ToggleFullscreen(ash::WindowState* window_state) override {
-    return false;
-  }
-
-  // Overridden from ash::WindowStateDelegate.
-  void ToggleLockedFullscreen(ash::WindowState* window_state) override {
-    // Sets up the shell environment as appropriate for locked Lacros or Ash
-    // chrome sessions including disabling ARC.
-    ash::Shell::Get()->shell_delegate()->SetUpEnvironmentForLockedFullscreen(
-        window_state->IsPinned());
-  }
-};
-
 void CloseAllShellSurfaceTransientChildren(aura::Window* window) {
   // Deleting a window may delete other transient children. Remove other shell
   // surface bases first so they don't get deleted.
diff --git a/components/exo/shell_surface_observer.h b/components/exo/shell_surface_observer.h
new file mode 100644
index 0000000..ae1a5f2
--- /dev/null
+++ b/components/exo/shell_surface_observer.h
@@ -0,0 +1,28 @@
+// 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_EXO_SHELL_SURFACE_OBSERVER_H_
+#define COMPONENTS_EXO_SHELL_SURFACE_OBSERVER_H_
+
+#include <stdint.h>
+
+#include "base/observer_list_types.h"
+
+namespace exo {
+
+class ShellSurfaceObserver : public base::CheckedObserver {
+ public:
+  // Invoked to notify the configure event with `serial`.
+  virtual void OnConfigure(uint32_t serial) {}
+
+  // Invoked to notify an acknowledgement of the configure with `serial`.
+  virtual void OnAcknowledgeConfigure(uint32_t serial) {}
+
+  // Invoked when underlying ShellSurface goes away.
+  virtual void OnShellSurfaceDestroyed() {}
+};
+
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_SHELL_SURFACE_OBSERVER_H_
diff --git a/components/exo/shell_surface_presentation_time_recorder.cc b/components/exo/shell_surface_presentation_time_recorder.cc
new file mode 100644
index 0000000..9fd3459
--- /dev/null
+++ b/components/exo/shell_surface_presentation_time_recorder.cc
@@ -0,0 +1,185 @@
+// 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/exo/shell_surface_presentation_time_recorder.h"
+
+#include <cstdint>
+#include <memory>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
+#include "base/trace_event/typed_macros.h"
+#include "components/exo/shell_surface.h"
+#include "components/exo/shell_surface_util.h"
+#include "components/exo/surface.h"
+#include "third_party/perfetto/include/perfetto/tracing/track.h"
+#include "ui/gfx/presentation_feedback.h"
+
+namespace exo {
+namespace {
+
+constexpr char kTraceCategory[] = "benchmark,ui";
+
+base::HistogramBase* CreateTimesHistogram(const char* name) {
+  return base::Histogram::FactoryTimeGet(
+      name, base::Milliseconds(1), base::Milliseconds(200), 50,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+}
+
+// HistogramReporter reports latency and optional max latency as UMA histograms.
+class HistogramReporter
+    : public ShellSurfacePresentationTimeRecorder::Reporter {
+ public:
+  HistogramReporter(const char* latency_histogram_name,
+                    absl::optional<const char*> max_latency_histogram_name)
+      : latency_histogram_(CreateTimesHistogram(latency_histogram_name)),
+        max_latency_histogram_name_(max_latency_histogram_name) {}
+
+  HistogramReporter(const HistogramReporter&) = delete;
+  HistogramReporter& operator=(const HistogramReporter&) = delete;
+
+  ~HistogramReporter() override {
+    if (max_latency_histogram_name_.has_value()) {
+      CreateTimesHistogram(max_latency_histogram_name_.value())
+          ->AddTimeMillisecondsGranularity(max_latency_);
+    }
+  }
+
+  // PresentationTimeRecorder::Reporter
+  void ReportTime(base::TimeDelta delta) override {
+    latency_histogram_->AddTimeMillisecondsGranularity(delta);
+
+    if (max_latency_histogram_name_.has_value() && delta > max_latency_) {
+      max_latency_ = delta;
+    }
+  }
+
+ private:
+  base::HistogramBase* const latency_histogram_;
+  const absl::optional<const char*> max_latency_histogram_name_;
+  base::TimeDelta max_latency_;
+};
+
+}  // namespace
+
+// static
+std::unique_ptr<ShellSurfacePresentationTimeRecorder::Reporter>
+ShellSurfacePresentationTimeRecorder::CreateHistogramReporter(
+    const char* latency_histogram_name,
+    absl::optional<const char*> max_latency_histogram_name) {
+  return std::make_unique<HistogramReporter>(latency_histogram_name,
+                                             max_latency_histogram_name);
+}
+
+ShellSurfacePresentationTimeRecorder::ShellSurfacePresentationTimeRecorder(
+    ShellSurface* shell_surface,
+    std::unique_ptr<Reporter> reporter)
+    : shell_surface_(shell_surface), reporter_(std::move(reporter)) {
+  scoped_observation_.Observe(shell_surface_);
+}
+
+ShellSurfacePresentationTimeRecorder::~ShellSurfacePresentationTimeRecorder() =
+    default;
+
+void ShellSurfacePresentationTimeRecorder::PrepareToRecord() {
+  if (pending_request_.has_value())
+    return;
+
+  pending_request_ = absl::make_optional<Request>();
+  pending_request_->request_id = next_request_id_++;
+}
+
+bool ShellSurfacePresentationTimeRecorder::RequestNext() {
+  // Underlying ShellSurface must still be alive.
+  DCHECK(shell_surface_);
+  // `PrepareToRecord()` must have happened.
+  DCHECK(pending_request_.has_value());
+
+  // Early out if there is a pending request that does not get a Configure.
+  if (!pending_request_->serial.has_value())
+    return false;
+
+  TRACE_EVENT_BEGIN(kTraceCategory, "ShellSurfacePresentationTimeRecorder",
+                    perfetto::Track(pending_request_->request_id), "serial",
+                    pending_request_->serial.value());
+
+  pending_request_->request_time = base::TimeTicks::Now();
+  requests_.emplace_back(pending_request_.value());
+  pending_request_.reset();
+
+  LOG_IF(WARNING, requests_.size() > 100u)
+      << "Number of requests waiting for ack has reached: " << requests_.size();
+
+  return true;
+}
+
+void ShellSurfacePresentationTimeRecorder::OnConfigure(uint32_t serial) {
+  if (!pending_request_.has_value())
+    return;
+
+  pending_request_->serial = serial;
+}
+
+void ShellSurfacePresentationTimeRecorder::OnAcknowledgeConfigure(
+    uint32_t serial) {
+  // Must not ack a serial in `pending_request_`. RequestNext() should happen
+  // to commit the `pending_request_` before the ack.
+  DCHECK(!pending_request_.has_value() ||
+         !pending_request_->serial.has_value() ||
+         serial > pending_request_->serial);
+
+  Surface* root_surface = shell_surface_->root_surface();
+  while (!requests_.empty()) {
+    Request request = requests_.front();
+    requests_.pop_front();
+
+    root_surface->RequestPresentationCallback(base::BindRepeating(
+        &ShellSurfacePresentationTimeRecorder::OnFramePresented,
+        weak_ptr_factory_.GetWeakPtr(), request));
+
+    if (request.serial.value() == serial)
+      break;
+  }
+}
+
+void ShellSurfacePresentationTimeRecorder::OnShellSurfaceDestroyed() {
+  scoped_observation_.Reset();
+}
+
+void ShellSurfacePresentationTimeRecorder::OnFramePresented(
+    const Request& request,
+    const gfx::PresentationFeedback& feedback) {
+  TRACE_EVENT_END(kTraceCategory, perfetto::Track(request.request_id), "flags",
+                  feedback.flags, "serial", request.serial.value());
+
+  if (feedback.flags & gfx::PresentationFeedback::kFailure) {
+    LOG(WARNING) << "PresentationFailed (serial=" << *request.serial << "):"
+                 << ", flags=" << feedback.flags;
+    return;
+  }
+
+  if (feedback.timestamp.is_null()) {
+    // TODO(b/165951963): ideally feedback.timestamp should not be null.
+    // Consider replacing this by DCHECK or CHECK.
+    LOG(ERROR) << "Invalid feedback timestamp (serial=" << *request.serial
+               << "):"
+               << " timestamp is not set";
+    return;
+  }
+
+  const base::TimeDelta delta = feedback.timestamp - request.request_time;
+  if (delta.InMilliseconds() < 0) {
+    LOG(ERROR) << "Invalid timestamp for presentation feedback (serial="
+               << *request.serial
+               << "): requested_time=" << request.request_time
+               << " feedback.timestamp=" << feedback.timestamp;
+    return;
+  }
+
+  reporter_->ReportTime(delta);
+}
+
+}  // namespace exo
diff --git a/components/exo/shell_surface_presentation_time_recorder.h b/components/exo/shell_surface_presentation_time_recorder.h
new file mode 100644
index 0000000..83d85a7
--- /dev/null
+++ b/components/exo/shell_surface_presentation_time_recorder.h
@@ -0,0 +1,101 @@
+// 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_EXO_SHELL_SURFACE_PRESENTATION_TIME_RECORDER_H_
+#define COMPONENTS_EXO_SHELL_SURFACE_PRESENTATION_TIME_RECORDER_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "ash/public/cpp/presentation_time_recorder.h"
+#include "base/containers/circular_deque.h"
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observation.h"
+#include "base/time/time.h"
+#include "components/exo/shell_surface.h"
+#include "components/exo/shell_surface_observer.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace gfx {
+struct PresentationFeedback;
+}
+
+namespace exo {
+
+// ShellSurfacePresentationTimeRecorder records the time of
+//   configure-> ack -> present
+// of the underlying ShellSurface after a request is made. Requests
+// made for the same configure will be ignored.
+class ShellSurfacePresentationTimeRecorder
+    : public ash::PresentationTimeRecorder,
+      public ShellSurfaceObserver {
+ public:
+  class Reporter {
+   public:
+    virtual ~Reporter() = default;
+
+    // Invoked to report the time delta.
+    virtual void ReportTime(base::TimeDelta delta) = 0;
+  };
+
+  // Factory to create histogram reporter.
+  static std::unique_ptr<Reporter> CreateHistogramReporter(
+      const char* latency_histogram_name,
+      absl::optional<const char*> max_latency_histogram_name = absl::nullopt);
+
+  ShellSurfacePresentationTimeRecorder(ShellSurface* shell_surface,
+                                       std::unique_ptr<Reporter> reporter);
+  ShellSurfacePresentationTimeRecorder(
+      const ShellSurfacePresentationTimeRecorder&) = delete;
+  ShellSurfacePresentationTimeRecorder& operator=(
+      const ShellSurfacePresentationTimeRecorder&) = delete;
+
+  ~ShellSurfacePresentationTimeRecorder() override;
+
+  // ash::PresentationTimeRecorder:
+  void PrepareToRecord() override;
+  bool RequestNext() override;
+
+  // ShellSurfaceObserver:
+  void OnConfigure(uint32_t serial) override;
+  void OnAcknowledgeConfigure(uint32_t serial) override;
+  void OnShellSurfaceDestroyed() override;
+
+ protected:
+  struct Request {
+    uint64_t request_id = 0u;
+    // Time when RequestNext is called.
+    base::TimeTicks request_time;
+    // Serial of the first Configure after RequestNext.
+    absl::optional<uint32_t> serial = absl::nullopt;
+  };
+
+  // Invoked to notify a frame is presented to calculate time delta between
+  // `request_time` and the frame's presentation feedback.
+  // Virtual for testing.
+  virtual void OnFramePresented(const Request& request,
+                                const gfx::PresentationFeedback& feedback);
+
+ private:
+  ShellSurface* shell_surface_ = nullptr;
+  std::unique_ptr<Reporter> reporter_;
+
+  uint64_t next_request_id_ = 0u;
+
+  // Request waiting for configure. There would be only one such request.
+  absl::optional<Request> pending_request_;
+
+  // Requests that have received "configure" and wait for "ack".
+  base::circular_deque<Request> requests_;
+
+  base::ScopedObservation<ShellSurface, ShellSurfaceObserver>
+      scoped_observation_{this};
+  base::WeakPtrFactory<ShellSurfacePresentationTimeRecorder> weak_ptr_factory_{
+      this};
+};
+
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_SHELL_SURFACE_PRESENTATION_TIME_RECORDER_H_
diff --git a/components/exo/shell_surface_presentation_time_recorder_unittest.cc b/components/exo/shell_surface_presentation_time_recorder_unittest.cc
new file mode 100644
index 0000000..0edf1ad
--- /dev/null
+++ b/components/exo/shell_surface_presentation_time_recorder_unittest.cc
@@ -0,0 +1,196 @@
+// 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/exo/shell_surface_presentation_time_recorder.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/auto_reset.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_helper.h"
+#include "components/exo/test/shell_surface_builder.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/gfx/presentation_feedback.h"
+
+using testing::ElementsAre;
+
+namespace exo {
+namespace {
+
+class TestReporter : public ShellSurfacePresentationTimeRecorder::Reporter {
+ public:
+  TestReporter() = default;
+  ~TestReporter() override = default;
+
+  // ShellSurfacePresentationTimeRecorder::Reporter:
+  void ReportTime(base::TimeDelta delta) override { ++report_count_; }
+
+  int GetReportCountAndReset() {
+    int count = report_count_;
+    report_count_ = 0;
+    return count;
+  }
+
+ private:
+  int report_count_ = 0;
+};
+
+class TestRecorder : public ShellSurfacePresentationTimeRecorder {
+ public:
+  TestRecorder(ShellSurface* shell_surface, std::unique_ptr<Reporter> reporter)
+      : ShellSurfacePresentationTimeRecorder(shell_surface,
+                                             std::move(reporter)) {}
+
+  // ShellSurfacePresentationTimeRecorder:
+  void OnFramePresented(const Request& request,
+                        const gfx::PresentationFeedback& feedback) override {
+    presented_serials_.push_back(request.serial.value());
+    ShellSurfacePresentationTimeRecorder::OnFramePresented(request,
+                                                           fake_feedback_);
+    if (run_loop_)
+      run_loop_->Quit();
+  }
+
+  void WaitForFramePresented() {
+    base::RunLoop run_loop;
+
+    base::AutoReset<base::RunLoop*> scoped(&run_loop_, &run_loop);
+    run_loop.Run();
+  }
+
+  std::vector<uint32_t> TakePresentedSerials() {
+    return std::move(presented_serials_);
+  }
+
+  void set_fake_feedback(const gfx::PresentationFeedback& fake_feedback) {
+    fake_feedback_ = fake_feedback;
+  }
+
+ private:
+  gfx::PresentationFeedback fake_feedback_;
+  base::RunLoop* run_loop_ = nullptr;
+  std::vector<uint32_t> presented_serials_;
+};
+
+}  // namespace
+
+class ShellSurfacePresentationTimeRecorderTest : public test::ExoTestBase {
+ public:
+  ShellSurfacePresentationTimeRecorderTest() = default;
+  ~ShellSurfacePresentationTimeRecorderTest() override = default;
+
+  // test::ExoTestBase:
+  void SetUp() override {
+    test::ExoTestBase::SetUp();
+
+    shell_surface_ = test::ShellSurfaceBuilder({32, 32}).BuildShellSurface();
+
+    auto reporter = std::make_unique<TestReporter>();
+    reporter_ = reporter.get();
+    recorder_ = std::make_unique<TestRecorder>(shell_surface_.get(),
+                                               std::move(reporter));
+  }
+  void TearDown() override {
+    shell_surface_.reset();
+
+    test::ExoTestBase::TearDown();
+  }
+
+  void FakeFrameSubmitAndPresent() {
+    base::TimeDelta interval_not_used = base::Milliseconds(0);
+    // Create feedback with an extra 1s to ensure that presentation timestamp
+    // is later than the request time on slow bots. Otherwise, the presentation
+    // would not be reported and fail test expectations.
+    gfx::PresentationFeedback feedback(
+        base::TimeTicks().Now() + base::Milliseconds(1000), interval_not_used,
+        /*flags=*/0);
+    recorder_->set_fake_feedback(feedback);
+
+    root_surface()->Commit();
+    recorder_->WaitForFramePresented();
+  }
+
+  Surface* root_surface() { return shell_surface_->root_surface(); }
+
+ protected:
+  std::unique_ptr<ShellSurface> shell_surface_;
+  std::unique_ptr<TestRecorder> recorder_;
+  TestReporter* reporter_ = nullptr;
+};
+
+TEST_F(ShellSurfacePresentationTimeRecorderTest, Request) {
+  // Request without "config" fails.
+  recorder_->PrepareToRecord();
+  EXPECT_FALSE(recorder_->RequestNext());
+
+  // Fake a "Connfigure".
+  recorder_->OnConfigure(1u);
+
+  // Request should succeed.
+  EXPECT_TRUE(recorder_->RequestNext());
+}
+
+TEST_F(ShellSurfacePresentationTimeRecorderTest, AckSkippedOrOutOfOrder) {
+  // Issue 4 requests with configure serial 1-5.
+  for (size_t i = 1u; i <= 5u; ++i) {
+    recorder_->PrepareToRecord();
+    recorder_->OnConfigure(i);
+    ASSERT_TRUE(recorder_->RequestNext());
+  }
+
+  // Ack 2 and skip 1.
+  recorder_->OnAcknowledgeConfigure(2u);
+
+  // FramePrsented would be reported for 1 and 2, even though 1 is not acked.
+  FakeFrameSubmitAndPresent();
+  EXPECT_THAT(recorder_->TakePresentedSerials(), ElementsAre(1, 2));
+  EXPECT_EQ(2, reporter_->GetReportCountAndReset());
+
+  // Ack 4 and 3 out of order.
+  recorder_->OnAcknowledgeConfigure(4u);
+  recorder_->OnAcknowledgeConfigure(3u);
+  recorder_->OnAcknowledgeConfigure(5u);
+
+  // FramePresented would be reported for 3, 4, and 5, even though 3 and 4
+  // is acked out of order.
+  FakeFrameSubmitAndPresent();
+  EXPECT_THAT(recorder_->TakePresentedSerials(), ElementsAre(3, 4, 5));
+  EXPECT_EQ(3, reporter_->GetReportCountAndReset());
+}
+
+TEST_F(ShellSurfacePresentationTimeRecorderTest,
+       RecorderDestroyedBeforePresent) {
+  // Create a pending request on the recorder.
+  recorder_->PrepareToRecord();
+  recorder_->OnConfigure(1u);
+  EXPECT_TRUE(recorder_->RequestNext());
+  recorder_->OnAcknowledgeConfigure(1u);
+
+  // `recorder_` is gone before frame submission and presentation. `reporter_`
+  // is owned by `recorder_` so clear its reference too.
+  recorder_.reset();
+  reporter_ = nullptr;
+
+  // Fake frame submission. No FakeFrameSubmitAndPresent() because it depends
+  // on `recorder_`.
+  root_surface()->Commit();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(ShellSurfacePresentationTimeRecorderTest,
+       ShellSurfaceDestroyedBeforeRecorder) {
+  // Create a pending request on the recorder.
+  recorder_->PrepareToRecord();
+  recorder_->OnConfigure(1u);
+  EXPECT_TRUE(recorder_->RequestNext());
+  recorder_->OnAcknowledgeConfigure(1u);
+
+  // ShellSurface gets destroyed before recorder.
+  shell_surface_.reset();
+}
+
+}  // namespace exo
diff --git a/components/history_clusters/core/config.cc b/components/history_clusters/core/config.cc
index 1a6ff10..59b9e93 100644
--- a/components/history_clusters/core/config.cc
+++ b/components/history_clusters/core/config.cc
@@ -206,6 +206,10 @@
       features::kOnDeviceClustering, "should_label_clusters",
       should_label_clusters);
 
+  labels_from_entities = GetFieldTrialParamByFeatureAsBool(
+      features::kOnDeviceClustering, "labels_from_entities",
+      labels_from_entities);
+
   const base::FeatureParam<std::string> kHostsToSkipClusteringFor{
       &features::kOnDeviceClusteringBlocklists, "hosts_to_skip_clustering_for",
       ""};
diff --git a/components/history_clusters/core/config.h b/components/history_clusters/core/config.h
index 6ae38c8..3b03810fb 100644
--- a/components/history_clusters/core/config.h
+++ b/components/history_clusters/core/config.h
@@ -190,6 +190,9 @@
   // in the UI. If the label doesn't exist, the UI will emphasize the top visit.
   bool should_label_clusters = false;
 
+  // Whether to assign labels to clusters from the Entities of the cluster.
+  bool labels_from_entities = false;
+
   // The set of hosts for which all visits belonging to that host will not be in
   // any cluster.
   base::flat_set<std::string> hosts_to_skip_clustering_for;
diff --git a/components/history_clusters/core/label_cluster_finalizer.cc b/components/history_clusters/core/label_cluster_finalizer.cc
index 5b7c50f..3e0ca91e 100644
--- a/components/history_clusters/core/label_cluster_finalizer.cc
+++ b/components/history_clusters/core/label_cluster_finalizer.cc
@@ -7,6 +7,7 @@
 #include "base/containers/flat_set.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/history/core/browser/history_types.h"
+#include "components/history_clusters/core/config.h"
 #include "components/history_clusters/core/on_device_clustering_features.h"
 #include "components/history_clusters/core/on_device_clustering_util.h"
 #include "components/strings/grit/components_strings.h"
@@ -18,51 +19,40 @@
 LabelClusterFinalizer::~LabelClusterFinalizer() = default;
 
 void LabelClusterFinalizer::FinalizeCluster(history::Cluster& cluster) {
-  base::flat_map<std::string, float> entity_to_score;
   float max_label_score = -1;
   absl::optional<std::u16string> current_highest_scoring_label;
 
+  // First try finding search terms to use as the cluster label.
   for (const auto& visit : cluster.visits) {
-    if (!visit.annotated_visit.content_annotations.search_terms.empty()) {
-      // We have a search term, so use that instead. Clear out any old state.
-      if (!entity_to_score.empty()) {
-        entity_to_score.clear();
-        max_label_score = -1;
-        current_highest_scoring_label = absl::nullopt;
-      }
-
-      // Update with the highest scoring search term, if available.
-      if (visit.score > max_label_score) {
-        current_highest_scoring_label = l10n_util::GetStringFUTF16(
-            IDS_HISTORY_CLUSTERS_CLUSTER_LABEL_SEARCH_TERMS,
-            visit.annotated_visit.content_annotations.search_terms);
-        max_label_score = visit.score;
-      }
-      continue;
-    }
-
-    if (current_highest_scoring_label && entity_to_score.empty()) {
-      // If we are here, we are tracking high-scoring search terms for the
-      // cluster instead of falling back to entities.
-      continue;
-    }
-
-    for (const auto& entity :
-         visit.annotated_visit.content_annotations.model_annotations.entities) {
-      auto it = entity_to_score.find(entity.id);
-      float new_score = it != entity_to_score.end()
-                            ? it->second + (entity.weight * visit.score)
-                            : entity.weight * visit.score;
-      if (new_score > max_label_score) {
-        max_label_score = new_score;
-        current_highest_scoring_label = base::UTF8ToUTF16(entity.id);
-      }
-      entity_to_score[entity.id] = new_score;
+    if (!visit.annotated_visit.content_annotations.search_terms.empty() &&
+        visit.score > max_label_score) {
+      current_highest_scoring_label = l10n_util::GetStringFUTF16(
+          IDS_HISTORY_CLUSTERS_CLUSTER_LABEL_SEARCH_TERMS,
+          visit.annotated_visit.content_annotations.search_terms);
+      max_label_score = visit.score;
     }
   }
 
-  // If we get here, the label is either the search terms with the highest visit
-  // score or the entity with the highest score.
+  // If we haven't found a label yet, use the Entity name, if that flag is
+  // enabled.
+  if (GetConfig().labels_from_entities && !current_highest_scoring_label) {
+    base::flat_map<std::string, float> entity_to_score;
+    for (const auto& visit : cluster.visits) {
+      for (const auto& entity : visit.annotated_visit.content_annotations
+                                    .model_annotations.entities) {
+        auto it = entity_to_score.find(entity.id);
+        float new_score = it != entity_to_score.end()
+                              ? it->second + (entity.weight * visit.score)
+                              : entity.weight * visit.score;
+        if (new_score > max_label_score) {
+          max_label_score = new_score;
+          current_highest_scoring_label = base::UTF8ToUTF16(entity.id);
+        }
+        entity_to_score[entity.id] = new_score;
+      }
+    }
+  }
+
   if (current_highest_scoring_label) {
     cluster.label = *current_highest_scoring_label;
   }
diff --git a/components/history_clusters/core/label_cluster_finalizer_unittest.cc b/components/history_clusters/core/label_cluster_finalizer_unittest.cc
index b2b9403..553b33cf 100644
--- a/components/history_clusters/core/label_cluster_finalizer_unittest.cc
+++ b/components/history_clusters/core/label_cluster_finalizer_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/test/task_environment.h"
 #include "components/history_clusters/core/clustering_test_utils.h"
+#include "components/history_clusters/core/config.h"
 #include "components/history_clusters/core/on_device_clustering_features.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -33,7 +34,7 @@
 };
 
 TEST_F(LabelClusterFinalizerTest,
-       ClusterWithNoSearchTermsTakesHighestScoringEntity) {
+       ClusterWithNoSearchTermsTakesHighestScoringEntityIfFlagEnabled) {
   history::ClusterVisit visit = testing::CreateClusterVisit(
       testing::CreateDefaultAnnotatedVisit(1, GURL("https://foo.com/")));
   visit.score = 0.8;
@@ -53,13 +54,41 @@
   visit3.annotated_visit.content_annotations.model_annotations.entities = {
       {"chosenlabel", 25}, {"someotherentity", 10}};
 
-  history::Cluster cluster;
-  cluster.visits = {visit2, visit3};
-  FinalizeCluster(cluster);
-  EXPECT_EQ(cluster.label, u"chosenlabel");
+  {
+    // Without the flag being enabled, there should be no label.
+    Config config;
+    config.should_label_clusters = true;
+    config.labels_from_entities = false;
+    SetConfigForTesting(config);
+
+    history::Cluster cluster;
+    cluster.visits = {visit2, visit3};
+    FinalizeCluster(cluster);
+    EXPECT_EQ(cluster.label, absl::nullopt);
+  }
+
+  {
+    // With the flag being enabled, there should be an entity label.
+    Config config;
+    config.should_label_clusters = true;
+    config.labels_from_entities = true;
+    SetConfigForTesting(config);
+
+    history::Cluster cluster;
+    cluster.visits = {visit2, visit3};
+    FinalizeCluster(cluster);
+    EXPECT_EQ(cluster.label, u"chosenlabel");
+  }
 }
 
 TEST_F(LabelClusterFinalizerTest, TakesHighestScoringSearchTermIfAvailable) {
+  // Verify that search terms take precedence even if labels from entities are
+  // enabled.
+  Config config;
+  config.should_label_clusters = true;
+  config.labels_from_entities = true;
+  SetConfigForTesting(config);
+
   history::ClusterVisit visit =
       testing::CreateClusterVisit(testing::CreateDefaultAnnotatedVisit(
           2, GURL("https://nosearchtermsbuthighscorevisit.com/")));
diff --git a/components/language/core/browser/pref_names.h b/components/language/core/browser/pref_names.h
index 394bbc6..3290070 100644
--- a/components/language/core/browser/pref_names.h
+++ b/components/language/core/browser/pref_names.h
@@ -22,10 +22,10 @@
 extern const char kPreferredLanguagesSyncable[];
 #endif
 
-// The application locale.
-// DO NOT USE this locale directly: use language::ConvertToActualUILocale()
-// after reading it to get the system locale. This pref stores the locale that
-// the user selected, if applicable.
+// The application locale as selected by the user, such as "en-AU". This may not
+// necessarily be a string locale (a locale that we have strings for on this
+// platform). Use |l10n_util::CheckAndResolveLocale| to convert it to a string
+// locale if needed, such as "en-GB".
 extern const char kApplicationLocale[];
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/components/media_router/common/media_route.cc b/components/media_router/common/media_route.cc
index e1d1ef15..4d058ca9 100644
--- a/components/media_router/common/media_route.cc
+++ b/components/media_router/common/media_route.cc
@@ -83,7 +83,8 @@
 
 MediaRoute::MediaRoute(const MediaRoute& other) = default;
 
-MediaRoute::MediaRoute() = default;
+MediaRoute::MediaRoute() : media_source_("") {}
+
 MediaRoute::~MediaRoute() = default;
 
 bool MediaRoute::operator==(const MediaRoute& other) const {
diff --git a/components/media_router/common/media_route.h b/components/media_router/common/media_route.h
index 4a9a166..fbae95e 100644
--- a/components/media_router/common/media_route.h
+++ b/components/media_router/common/media_route.h
@@ -49,6 +49,9 @@
              const std::string& description,
              bool is_local);
   MediaRoute(const MediaRoute& other);
+
+  // TODO(crbug.com/1311341): Delete the default constructor and
+  // disallow passing in an empty string into the MediaSource ctor.
   MediaRoute();
 
   ~MediaRoute();
diff --git a/components/media_router/common/media_source.cc b/components/media_router/common/media_source.cc
index c10429d..65ccf99 100644
--- a/components/media_router/common/media_source.cc
+++ b/components/media_router/common/media_source.cc
@@ -66,8 +66,6 @@
   return presentation_id == kAutoJoinPresentationId;
 }
 
-MediaSource::MediaSource() = default;
-
 MediaSource::MediaSource(const MediaSource::Id& source_id) : id_(source_id) {
   GURL url(source_id);
   if (IsValidPresentationUrl(url))
diff --git a/components/media_router/common/media_source.h b/components/media_router/common/media_source.h
index d30d607..ec1ad73 100644
--- a/components/media_router/common/media_source.h
+++ b/components/media_router/common/media_source.h
@@ -54,10 +54,6 @@
  public:
   using Id = std::string;
 
-  // TODO(crbug.com/1291731): Eliminate this constructor and use
-  // optional<MediaSource> where needed.
-  MediaSource();
-
   // Create from an arbitrary string, which may or may not be a presentation
   // URL.
   explicit MediaSource(const MediaSource::Id& id);
@@ -81,10 +77,13 @@
 
   bool operator<(const MediaSource& other) const { return id_ < other.id(); }
 
-  // Hash operator for hash containers.
-  struct Hash {
-    uint32_t operator()(const MediaSource& source) const {
-      return base::FastHash(source.id());
+  // Compare operator for absl::optional<MediaSource>
+  struct Cmp {
+    bool operator()(const absl::optional<MediaSource>& source1,
+                    const absl::optional<MediaSource>& source2) const {
+      Id id1 = (source1.has_value()) ? (source1->id()) : "";
+      Id id2 = (source2.has_value()) ? (source2->id()) : "";
+      return id1 < id2;
     }
   };
 
diff --git a/components/metrics/metrics_pref_names.cc b/components/metrics/metrics_pref_names.cc
index fea0c74..63c904f 100644
--- a/components/metrics/metrics_pref_names.cc
+++ b/components/metrics/metrics_pref_names.cc
@@ -132,11 +132,6 @@
 const char kStabilityExtensionRendererFailedLaunchCount[] =
     "user_experience_metrics.stability.extension_renderer_failed_launch_count";
 
-// Number of times an extension renderer process successfully launched since the
-// last report.
-const char kStabilityExtensionRendererLaunchCount[] =
-    "user_experience_metrics.stability.extension_renderer_launch_count";
-
 // The total number of samples that will be lost if ASSOCIATE_INTERNAL_PROFILE
 // isn't enabled since the previous stability recorded, this is different than
 // the previous browser run, because one file was just uploaded before the
diff --git a/components/metrics/metrics_pref_names.h b/components/metrics/metrics_pref_names.h
index be9489e..274fd3b 100644
--- a/components/metrics/metrics_pref_names.h
+++ b/components/metrics/metrics_pref_names.h
@@ -48,7 +48,6 @@
 extern const char kStabilityExitedCleanly[];
 extern const char kStabilityExtensionRendererCrashCount[];
 extern const char kStabilityExtensionRendererFailedLaunchCount[];
-extern const char kStabilityExtensionRendererLaunchCount[];
 extern const char kStabilityFileMetricsUnsentSamplesCount[];
 extern const char kStabilityFileMetricsUnsentFilesCount[];
 extern const char kStabilityGmsCoreVersion[];
diff --git a/components/metrics/stability_metrics_helper.cc b/components/metrics/stability_metrics_helper.cc
index 7faf5ec..5f208a7 100644
--- a/components/metrics/stability_metrics_helper.cc
+++ b/components/metrics/stability_metrics_helper.cc
@@ -124,13 +124,6 @@
     local_state_->SetInteger(
         prefs::kStabilityExtensionRendererFailedLaunchCount, 0);
   }
-
-  count =
-      local_state_->GetInteger(prefs::kStabilityExtensionRendererLaunchCount);
-  if (count) {
-    stability_proto->set_extension_renderer_launch_count(count);
-    local_state_->SetInteger(prefs::kStabilityExtensionRendererLaunchCount, 0);
-  }
 }
 
 void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
@@ -138,7 +131,6 @@
   local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
   local_state_->SetInteger(prefs::kStabilityExtensionRendererFailedLaunchCount,
                            0);
-  local_state_->SetInteger(prefs::kStabilityExtensionRendererLaunchCount, 0);
   local_state_->SetInteger(prefs::kStabilityGpuCrashCount, 0);
   local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
   local_state_->SetInteger(prefs::kStabilityRendererCrashCount, 0);
@@ -152,8 +144,6 @@
                                 0);
   registry->RegisterIntegerPref(
       prefs::kStabilityExtensionRendererFailedLaunchCount, 0);
-  registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererLaunchCount,
-                                0);
   registry->RegisterIntegerPref(prefs::kStabilityGpuCrashCount, 0);
   registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
   registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0);
@@ -293,11 +283,9 @@
   auto metric = was_extension_process
                     ? StabilityEventType::kExtensionRendererLaunch
                     : StabilityEventType::kRendererLaunch;
-  auto* pref = was_extension_process
-                   ? prefs::kStabilityExtensionRendererLaunchCount
-                   : prefs::kStabilityRendererLaunchCount;
   RecordStabilityEvent(metric);
-  IncrementPrefValue(pref);
+  if (!was_extension_process)
+    IncrementPrefValue(prefs::kStabilityRendererLaunchCount);
 }
 
 void StabilityMetricsHelper::LogRendererLaunchFailed(
diff --git a/components/ml/mojom/BUILD.gn b/components/ml/mojom/BUILD.gn
new file mode 100644
index 0000000..7af27fd8
--- /dev/null
+++ b/components/ml/mojom/BUILD.gn
@@ -0,0 +1,13 @@
+# Copyright (c) 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+  sources = [
+    "ml_service.mojom",
+    "web_platform_model.mojom",
+  ]
+  deps = [ "//mojo/public/mojom/base" ]
+}
diff --git a/components/ml/mojom/OWNERS b/components/ml/mojom/OWNERS
new file mode 100644
index 0000000..4b08e76
--- /dev/null
+++ b/components/ml/mojom/OWNERS
@@ -0,0 +1,5 @@
+honglinyu@chromium.org
+qjw@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/components/ml/mojom/ml_service.mojom b/components/ml/mojom/ml_service.mojom
new file mode 100644
index 0000000..4b07858
--- /dev/null
+++ b/components/ml/mojom/ml_service.mojom
@@ -0,0 +1,23 @@
+// 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.
+
+module ml.model_loader.mojom;
+
+import "components/ml/mojom/web_platform_model.mojom";
+
+// Represents the Machine Learning service, corresponding to the `ML` interface
+// in the IDL definition.
+// This interface is used between the browser process and the renderer.
+interface MLService {
+  // Called by the renderer to ask the browser process to create a `ModelLoader`
+  // (see the `ModelLoader` interface). The browser process can handle this
+  // differently on different platforms.
+  //   - On Chrome OS, the browser process will forward this to the ml-service
+  //     daemon. And it will relay the returns from ml-service back to the
+  //     renderer.
+  //   - On non-supported platforms, the browser process will return
+  //     `CreateModelLoaderResult::kNotSupported` with `mojo::NullRemote`.
+  CreateModelLoader(CreateModelLoaderOptions options)
+      => (CreateModelLoaderResult result, pending_remote<ModelLoader>? remote);
+};
\ No newline at end of file
diff --git a/components/ml/mojom/web_platform_model.mojom b/components/ml/mojom/web_platform_model.mojom
new file mode 100644
index 0000000..eecc382
--- /dev/null
+++ b/components/ml/mojom/web_platform_model.mojom
@@ -0,0 +1,159 @@
+// 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.
+
+// This file needs to be synced between,
+// - "components/ml/mojom/web_platform_model.mojom" in the chromium repo
+// - "src/platform2/ml/mojom/web_platform_model.mojom" in the chromiumos repo
+// Modifications needed are,
+// - "big_buffer.mojom" needs to be included from mojo's base folder in chrome.
+//   whereas it should be included from "ml/mojom" in chromiumos repo.
+
+module ml.model_loader.mojom;
+
+import "mojo/public/mojom/base/big_buffer.mojom";
+
+// Model formats that will be loaded. Currently only supports TfLite
+// flatbuffer.
+// TODO(honglinyu): we may also need to add the versions of the formats, or/and
+// we can add feature query interfaces to tell the supported formats and
+// versions. And how to best version the API is still an open question, see
+// https://github.com/webmachinelearning/model-loader/issues/25.
+[Stable, Extensible]
+enum ModelFormat {
+  // This means the backend should decide the model format automatically.
+  [Default] kAuto = 0,
+  kTfLite = 1,
+};
+
+// Types of devices used to do model inference.
+// Currently only supports CPU.
+[Stable, Extensible]
+enum DevicePreference {
+  // Means the backend can arbitrarily select the device.
+  [Default] kAuto = 0,
+  // Prefers running model inference on CPU.
+  kCpu = 1,
+  // Prefers running the model inference on GPU. If some of the operators can
+  // not be supported on GPU, the backend can try to select a best fallback
+  // strategy: it may run the whole graph on CPU or still run part of the OPs on
+  // GPU. We do not directly return an error in this case to avoid directly
+  // exposing user's GPU information.
+  kGpu = 2,
+};
+
+[Stable, Extensible]
+struct CreateModelLoaderOptions {
+  // #Threads used in model inference.
+  // 0 means the backend can decide it automatically (e.g. equals the number of
+  // physical cores). And normally backends may have a upper cap on the number
+  // of threads a model can use. So setting a bigger number than that will have
+  // no difference.
+  uint32 num_threads@0 = 0;
+  // The format of model (e.g. "tflite").
+  ModelFormat model_format@1;
+  // The device to be used (e.g. "auto", "cpu", "gpu" etc.).
+  DevicePreference device_preference@2;
+};
+
+// Currently, the tensor type is only used to inform the user, and is not
+// meaningful to `compute()`. The `kUnknown` type just means the type is not
+// exposed in the mojo interface --- it does not mean the type is "unsupported".
+// We define this type just to avoid exposing unnecessary TfLite details from
+// the beginning. So even the type is `kUnknown`, user can still use the
+// `compute()` function by feeding in appropriate input binary buffers.
+[Stable, Extensible]
+enum DataType {
+  [Default] kUnknown = 0,
+  kInt64 = 1,
+  kUint64 = 2,
+  kFloat64 = 3,
+  kInt32 = 4,
+  kUint32 = 5,
+  kFloat32 = 6,
+  kInt16 = 7,
+  kUint16 = 8,
+  kFloat16 = 9,
+  kInt8 = 10,
+  kUint8 = 11,
+  kBool = 12,
+};
+
+// Represents the information of a tensor. The tensor infos of input and output
+// tensors are sent from ml-service to the client as a result of model loading.
+[Stable, Extensible]
+struct TensorInfo {
+  // The total size of the tensor buffer in bytes. This is the most important
+  // information. Ml-service will use it to check whether the input tensor is
+  // valid.
+  uint32 byte_size@0;
+  // The type of the tensor data.
+  DataType data_type@1;
+  // The dimensions of the tensor.
+  array<uint32> dimensions@2;
+};
+
+// Represents the model information. Currently it contains the tensor info of
+// input and output tensors.
+[Stable, Extensible]
+struct ModelInfo {
+  map<string, TensorInfo> input_tensor_info@0;
+  map<string, TensorInfo> output_tensor_info@1;
+};
+
+// Used by `Load()` of interface Model.
+[Stable, Extensible]
+enum LoadModelResult {
+  kOk,
+  kUnknownError,
+  // The model is invalid (e.g. the interpreter fails to parse the model).
+  kInvalidModel,
+  // The model can not be supported, e.g. some OPs are not supported.
+  kNotSupported,
+};
+
+[Stable, Extensible]
+enum CreateModelLoaderResult {
+  kOk,
+  kUnknownError,
+  // The input configuration is not supported.
+  kNotSupported,
+};
+
+// Used by `Compute()` of interface Model.
+[Stable, Extensible]
+enum ComputeResult {
+  kOk,
+  kUnknownError,
+  // There is no model that has been loaded yet.
+  kModelNotLoaded,
+  // The number of inputs is different from that required by the model.
+  kIncorrectNumberOfInputs,
+  // Some needed inputs are missing.
+  kMissingInput,
+  // The size of some input buffer is wrong.
+  kInvalidInputBufferSize,
+};
+
+// Corresponds to the `MLModelLoader` object in the WebIDL definition.
+[Stable]
+interface ModelLoader {
+  // We define this function in `Model` interface rather than in `MLService` to
+  // avoid unnecessary IPC hops of model content.
+  Load@0(mojo_base.mojom.BigBuffer model_content)
+      => (LoadModelResult result, pending_remote<Model>? remote,
+          ModelInfo? model_info);
+};
+
+// Represents a model instance. The user can use its `Compute` interface to do
+// model inferences.
+// Corresponds to the `MLModelLoaded` object in the WebIDL definition.
+[Stable]
+interface Model {
+  // The backend/frontend should already know the dimension needed for each
+  // input/output tensors. So we only need to know the buffer content of the
+  // input/output tensors.
+  Compute@0(map<string, array<uint8>> input_tensors)
+      => (ComputeResult result,
+          map<string, array<uint8>>? output_tensors);
+};
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc
index 50a3310..74ead5769 100644
--- a/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -330,13 +330,6 @@
       "true");
 }
 
-bool ShouldQuicGoawayOnPathDegrading(
-    const VariationParameters& quic_trial_params) {
-  return base::LowerCaseEqualsASCII(
-      GetVariationParam(quic_trial_params, "go_away_on_path_degrading"),
-      "true");
-}
-
 int GetQuicMaxTimeOnNonDefaultNetworkSeconds(
     const VariationParameters& quic_trial_params) {
   int value;
@@ -620,8 +613,6 @@
         ShouldQuicAllowPortMigration(quic_trial_params);
     quic_params->retry_on_alternate_network_before_handshake =
         ShouldQuicRetryOnAlternateNetworkBeforeHandshake(quic_trial_params);
-    quic_params->go_away_on_path_degrading =
-        ShouldQuicGoawayOnPathDegrading(quic_trial_params);
     int initial_rtt_for_handshake_milliseconds =
         GetQuicInitialRttForHandshakeMilliseconds(quic_trial_params);
     if (initial_rtt_for_handshake_milliseconds > 0) {
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
index d510377..54d49250 100644
--- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc
+++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -92,7 +92,6 @@
   EXPECT_FALSE(quic_params_.migrate_sessions_early_v2);
   EXPECT_FALSE(quic_params_.retry_on_alternate_network_before_handshake);
   EXPECT_FALSE(quic_params_.migrate_idle_sessions);
-  EXPECT_FALSE(quic_params_.go_away_on_path_degrading);
   EXPECT_TRUE(quic_params_.initial_rtt_for_handshake.is_zero());
   EXPECT_FALSE(quic_params_.allow_server_migration);
   EXPECT_TRUE(params_.quic_host_allowlist.empty());
@@ -446,18 +445,6 @@
 }
 
 TEST_F(NetworkSessionConfiguratorTest,
-       QuicGoawayOnPathDegradingFromFieldTrialParams) {
-  std::map<std::string, std::string> field_trial_params;
-  field_trial_params["go_away_on_path_degrading"] = "true";
-  variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
-  base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
-
-  ParseFieldTrials();
-
-  EXPECT_TRUE(quic_params_.go_away_on_path_degrading);
-}
-
-TEST_F(NetworkSessionConfiguratorTest,
        QuicIdleSessionMigrationPeriodFromFieldTrialParams) {
   std::map<std::string, std::string> field_trial_params;
   field_trial_params["migrate_idle_sessions"] = "true";
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 9484d28..9a100a3 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -26102,7 +26102,8 @@
         {
           'name': 'privet',
           'value': 'privet',
-          'caption': '''Zeroconf-based (mDNS + DNS-SD) protocol destinations''',
+          'caption': '''Zeroconf-based (mDNS + DNS-SD) protocol destinations (Deprecated)''',
+          'supported_on': ['chrome_os:80-101', 'chrome.*:80-101']
         },
         {
           'name': 'extension',
@@ -26130,7 +26131,7 @@
         'dynamic_refresh': True,
         'per_profile': True,
       },
-      'example_value': ['cloud', 'privet'],
+      'example_value': ['local', 'pdf'],
       'id': 647,
       'caption': '''Disable printer types on the deny list''',
       'tags': [],
@@ -30318,30 +30319,34 @@
       'tags': [],
       'id': 969,
       'caption': '''Override First-Party Sets.''',
-      'desc': '''This policy is as a way to override the list of sets that Chrome uses for First-Party Sets features.
+      'desc': '''This policy provides a way to override the list of sets the browser uses for First-Party Sets features.
 
-      When this policy is provided with an empty dictionary, the Chrome uses the public list of First-Party Sets.
-
-      When this policy receives a set in the 'replacements' list, any sets in the public list that
-      intersect with it will be removed from Chrome's list and the provided set will be added to Chrome's list.
-
-      When this policy receives a set in the 'additions' list, any sets in the Chrome's list that
-      intersect with it will be updated in order to add the provided set to the list while still maintaining
-      that Chrome's list of First-Party Sets is disjoint.
-
-      The list of First-Party Sets that Chrome uses must remain disjoint, so applying this policy requires
-      that both policy lists of First-Party Sets are disjoint within themselves, and between each other.
-
-      Additionally, all sets in both lists must adhere to the invariants of a First-Party Set.
+      Each set in the browser's list of First-Party Sets must meet the requirements of a First-Party Set.
       A First-Party Set consists of an owner and one or more member sites. All sites in a First-Party Set must
       be a registrable domain served over HTTPS, regardless of whether it is an owner or member site.
       Each site in a First-Party Set must also be unique, meaning a site cannot be both owner and member, nor
       listed more than once as a member of a First-Party Set.
       See https://github.com/privacycg/first-party-sets for more information on First-Party Sets.
 
+      When this policy is given an empty dictionary, the browser uses the public list of First-Party Sets.
+
+      For all sites in a First-Party Set from the <ph name="REPLACEMENTS">replacements</ph> list, if a site is also present
+      on a First-Party Set in the browser's list, then that site will be removed from the browser's First-Party Set.
+      After this, the policy's First-Party Set will be added to the browser's list of First-Party Sets.
+
+      For all sites in a First-Party Set from the <ph name="ADDITIONS">additions</ph> list, if a site is also present
+      on a First-Party Set in the browser's list, then the browser's First-Party Set will be updated so that the
+      new First-Party Set can be added to the browser's list. After the browser's list has been updated,
+      the policy's First-Party Set will be added to the browser's list of First-Party Sets.
+
+      The browser's list of First-Party Sets requires that for all sites in its list, no site is in
+      more than one set. This is also required for both the <ph name="REPLACEMENTS">replacements</ph> list
+      and the <ph name="ADDITIONS">additions</ph> list. Similarly, a site cannot be in both the
+      <ph name="REPLACEMENTS">replacements</ph> list and the <ph name="ADDITIONS">additions</ph> list.
+
       Wildcards (*) are not supported as a policy value, nor within any First-Party Set in these lists.
 
-      All sets provided by this policy must be valid First-Party Sets,  if they aren't then an
+      All sets provided by to policy must be valid First-Party Sets, if they aren't then an
       appropriate error will be outputted.''',
     },
     {
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 541b6de..53aa1e4 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
@@ -163,21 +163,11 @@
 
 #if BUILDFLAG(SAFE_BROWSING_AVAILABLE)
 bool PasswordProtectionRequestContent::IsClientSideDetectionEnabled() {
-#if BUILDFLAG(FULL_SAFE_BROWSING)
   return true;
-#else
-  return base::FeatureList::IsEnabled(
-      safe_browsing::kClientSideDetectionForAndroid);
-#endif  // BUILDFLAG(FULL_SAFE_BROWSING)
 }
 
 bool PasswordProtectionRequestContent::IsVisualFeaturesEnabled() {
-#if BUILDFLAG(FULL_SAFE_BROWSING)
   return true;
-#else
-  return base::FeatureList::IsEnabled(
-      kVisualFeaturesInPasswordProtectionAndroid);
-#endif  // BUILDFLAG(FULL_SAFE_BROWSING)
 }
 
 void PasswordProtectionRequestContent::GetDomFeatures() {
diff --git a/components/safe_browsing/core/common/features.cc b/components/safe_browsing/core/common/features.cc
index 41fb705..106108f 100644
--- a/components/safe_browsing/core/common/features.cc
+++ b/components/safe_browsing/core/common/features.cc
@@ -31,12 +31,6 @@
     "SafeBrowsingBetterTelemetryAcrossReports",
     base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kClientSideDetectionDocumentScanning{
-    "ClientSideDetectionDocumentScanning", base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kClientSideDetectionForAndroid{
-    "ClientSideDetectionModelOnAndroid", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enable only for Android
 #if BUILDFLAG(IS_ANDROID)
 const base::Feature kClientSideDetectionModelIsFlatBuffer{
@@ -46,9 +40,6 @@
     "ClientSideDetectionModelIsFlatBuffer", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-extern const base::Feature kClientSideDetectionModelVersion{
-    "ClientSideDetectionModel", base::FEATURE_ENABLED_BY_DEFAULT};
-
 extern const base::Feature kClientSideDetectionModelTag{
     "ClientSideDetectionTag", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -116,9 +107,6 @@
     "SafeBrowsingOmitNonUserGesturesFromReferrerChain",
     base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kPromptEsbForDeepScanning{
-    "SafeBrowsingPromptEsbForDeepScanning", base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kSafeBrowsingCsbrrWithToken{
     "SafeBrowsingCsbrrWithToken", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -152,13 +140,10 @@
 const base::Feature kTriggerThrottlerDailyQuotaFeature{
     "SafeBrowsingTriggerThrottlerDailyQuota",
     base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kUseNewDownloadWarnings{"UseNewDownloadWarnings",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kVisualFeaturesInPasswordProtectionAndroid{
-    "VisualFeaturesInPasswordProtectionAndroid",
-    base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kVisualFeaturesSizes{"VisualFeaturesSizes",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -174,9 +159,7 @@
     {&kAccuracyTipsFeature, true},
     {&kAdSamplerTriggerFeature, false},
     {&kBetterTelemetryAcrossReports, true},
-    {&kClientSideDetectionForAndroid, true},
     {&kClientSideDetectionModelIsFlatBuffer, true},
-    {&kClientSideDetectionModelVersion, true},
     {&kClientSideDetectionReferrerChain, true},
     {&kConnectorsScanningReportOnlyUI, true},
     {&kDelayedWarnings, true},
diff --git a/components/safe_browsing/core/common/features.h b/components/safe_browsing/core/common/features.h
index 27a1c771..9b6fef5 100644
--- a/components/safe_browsing/core/common/features.h
+++ b/components/safe_browsing/core/common/features.h
@@ -29,19 +29,9 @@
 // Browsing.
 extern const base::Feature kBetterTelemetryAcrossReports;
 
-// Controls whether Office documents will be scanned using //third_party maldoca
-extern const base::Feature kClientSideDetectionDocumentScanning;
-
-// Enables client side detection on Android.
-extern const base::Feature kClientSideDetectionForAndroid;
-
 // The client side detection model is a flatbuffer.
 extern const base::Feature kClientSideDetectionModelIsFlatBuffer;
 
-// Determines the experimental version of client side detection model, for
-// Desktop.
-extern const base::Feature kClientSideDetectionModelVersion;
-
 // Determines the tag to pass to Omaha to get a client side detection model.
 extern const base::Feature kClientSideDetectionModelTag;
 
@@ -102,10 +92,6 @@
 // Enable omitting non-user gesture from referrer chain.
 extern const base::Feature kOmitNonUserGesturesFromReferrerChain;
 
-// Controls whether Chrome prompts Enhanced Safe Browsing users for deep
-// scanning.
-extern const base::Feature kPromptEsbForDeepScanning;
-
 // Controls whether Client Safe Browsing Reports are sent with a GAIA-tied token
 // for Enhanced Safe Browsing users
 extern const base::Feature kSafeBrowsingCsbrrWithToken;
@@ -165,10 +151,6 @@
 // Controls whether Chrome uses new download warning UX.
 extern const base::Feature kUseNewDownloadWarnings;
 
-// Controls whether we include visual features in password protection pings on
-// Android.
-extern const base::Feature kVisualFeaturesInPasswordProtectionAndroid;
-
 // Controls the behavior of visual features in CSD pings. This feature is
 // checked for the final size of the visual features and the minimum size of
 // the screen.
diff --git a/components/signin/features.gni b/components/signin/features.gni
index e253b1e4..40a8e598 100644
--- a/components/signin/features.gni
+++ b/components/signin/features.gni
@@ -8,4 +8,4 @@
 enable_dice_support = is_linux || is_mac || is_win || is_fuchsia
 
 # Mirror is enabled and other account consistency mechanisms are not available.
-enable_mirror = is_android || is_chromeos_ash || is_chromeos_lacros || is_ios
+enable_mirror = is_android || is_chromeos || is_ios
diff --git a/components/signin/internal/identity_manager/BUILD.gn b/components/signin/internal/identity_manager/BUILD.gn
index 18a0526..4dc6f1e 100644
--- a/components/signin/internal/identity_manager/BUILD.gn
+++ b/components/signin/internal/identity_manager/BUILD.gn
@@ -102,7 +102,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [
       "profile_oauth2_token_service_delegate_chromeos.cc",
       "profile_oauth2_token_service_delegate_chromeos.h",
diff --git a/components/update_client/BUILD.gn b/components/update_client/BUILD.gn
index b334c4c..6b4f654 100644
--- a/components/update_client/BUILD.gn
+++ b/components/update_client/BUILD.gn
@@ -122,8 +122,6 @@
     "request_sender.cc",
     "request_sender.h",
     "task.h",
-    "task_send_registration_ping.cc",
-    "task_send_registration_ping.h",
     "task_send_uninstall_ping.cc",
     "task_send_uninstall_ping.h",
     "task_traits.h",
diff --git a/components/update_client/component.cc b/components/update_client/component.cc
index 3b0202c..8e20783 100644
--- a/components/update_client/component.cc
+++ b/components/update_client/component.cc
@@ -442,7 +442,7 @@
 
 base::Value Component::MakeEventUpdateComplete() const {
   base::Value event(base::Value::Type::DICTIONARY);
-  event.SetKey("eventtype", base::Value(3));
+  event.SetKey("eventtype", base::Value(update_context_.is_install ? 2 : 3));
   event.SetKey(
       "eventresult",
       base::Value(static_cast<int>(state() == ComponentState::kUpdated)));
diff --git a/components/update_client/ping_manager_unittest.cc b/components/update_client/ping_manager_unittest.cc
index 14ee2510..e9117549 100644
--- a/components/update_client/ping_manager_unittest.cc
+++ b/components/update_client/ping_manager_unittest.cc
@@ -115,7 +115,7 @@
 
 scoped_refptr<UpdateContext> PingManagerTest::MakeMockUpdateContext() const {
   return base::MakeRefCounted<UpdateContext>(
-      config_, false, std::vector<std::string>(),
+      config_, false, false, std::vector<std::string>(),
       UpdateClient::CrxStateChangeCallback(),
       UpdateEngine::NotifyObserversCallback(), UpdateEngine::Callback(),
       nullptr);
diff --git a/components/update_client/task_send_registration_ping.cc b/components/update_client/task_send_registration_ping.cc
deleted file mode 100644
index 0cb012f..0000000
--- a/components/update_client/task_send_registration_ping.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/update_client/task_send_registration_ping.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/version.h"
-#include "components/update_client/update_client.h"
-#include "components/update_client/update_engine.h"
-
-namespace update_client {
-
-TaskSendRegistrationPing::TaskSendRegistrationPing(
-    scoped_refptr<UpdateEngine> update_engine,
-    const CrxComponent& crx_component,
-    Callback callback)
-    : update_engine_(update_engine),
-      crx_component_(crx_component),
-      callback_(std::move(callback)) {}
-
-TaskSendRegistrationPing::~TaskSendRegistrationPing() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-void TaskSendRegistrationPing::Run() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (crx_component_.app_id.empty()) {
-    TaskComplete(Error::INVALID_ARGUMENT);
-    return;
-  }
-
-  update_engine_->SendRegistrationPing(
-      crx_component_,
-      base::BindOnce(&TaskSendRegistrationPing::TaskComplete, this));
-}
-
-void TaskSendRegistrationPing::Cancel() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  TaskComplete(Error::UPDATE_CANCELED);
-}
-
-std::vector<std::string> TaskSendRegistrationPing::GetIds() const {
-  return std::vector<std::string>{crx_component_.app_id};
-}
-
-void TaskSendRegistrationPing::TaskComplete(Error error) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&TaskSendRegistrationPing::RunCallback, this, error));
-}
-
-void TaskSendRegistrationPing::RunCallback(Error error) {
-  std::move(callback_).Run(this, error);
-}
-
-}  // namespace update_client
diff --git a/components/update_client/task_send_registration_ping.h b/components/update_client/task_send_registration_ping.h
deleted file mode 100644
index d87fd37..0000000
--- a/components/update_client/task_send_registration_ping.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_UPDATE_CLIENT_TASK_SEND_REGISTRATION_PING_H_
-#define COMPONENTS_UPDATE_CLIENT_TASK_SEND_REGISTRATION_PING_H_
-
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/sequence_checker.h"
-#include "components/update_client/task.h"
-#include "components/update_client/update_client.h"
-
-namespace update_client {
-
-class UpdateEngine;
-enum class Error;
-
-// Defines a specialized task for sending the registration ping.
-class TaskSendRegistrationPing : public Task {
- public:
-  using Callback =
-      base::OnceCallback<void(scoped_refptr<Task> task, Error error)>;
-
-  TaskSendRegistrationPing(const TaskSendRegistrationPing&) = delete;
-  TaskSendRegistrationPing& operator=(const TaskSendRegistrationPing&) = delete;
-
-  // |update_engine| is injected here to handle the task.
-  // |id| represents the CRX to send the ping for.
-  // |callback| is posted when the task is done.
-  TaskSendRegistrationPing(scoped_refptr<UpdateEngine> update_engine,
-                           const CrxComponent& crx_component,
-                           Callback callback);
-
-  void Run() override;
-
-  void Cancel() override;
-
-  std::vector<std::string> GetIds() const override;
-
- private:
-  ~TaskSendRegistrationPing() override;
-
-  // Called when the task has completed either because the task has run or
-  // it has been canceled.
-  void TaskComplete(Error error);
-
-  // Runs the task registration ping callback
-  void RunCallback(Error error);
-
-  SEQUENCE_CHECKER(sequence_checker_);
-  scoped_refptr<UpdateEngine> update_engine_;
-  const CrxComponent crx_component_;
-  Callback callback_;
-};
-
-}  // namespace update_client
-
-#endif  // COMPONENTS_UPDATE_CLIENT_TASK_SEND_REGISTRATION_PING_H_
diff --git a/components/update_client/task_update.cc b/components/update_client/task_update.cc
index 4d78c55..b755b58 100644
--- a/components/update_client/task_update.cc
+++ b/components/update_client/task_update.cc
@@ -16,12 +16,14 @@
 TaskUpdate::TaskUpdate(
     scoped_refptr<UpdateEngine> update_engine,
     bool is_foreground,
+    bool is_install,
     const std::vector<std::string>& ids,
     UpdateClient::CrxDataCallback crx_data_callback,
     UpdateClient::CrxStateChangeCallback crx_state_change_callback,
     Callback callback)
     : update_engine_(update_engine),
       is_foreground_(is_foreground),
+      is_install_(is_install),
       ids_(ids),
       crx_data_callback_(std::move(crx_data_callback)),
       crx_state_change_callback_(crx_state_change_callback),
@@ -39,7 +41,8 @@
     return;
   }
 
-  update_engine_->Update(is_foreground_, ids_, std::move(crx_data_callback_),
+  update_engine_->Update(is_foreground_, is_install_, ids_,
+                         std::move(crx_data_callback_),
                          std::move(crx_state_change_callback_),
                          base::BindOnce(&TaskUpdate::TaskComplete, this));
 }
diff --git a/components/update_client/task_update.h b/components/update_client/task_update.h
index ee6522d1..a937b1f 100644
--- a/components/update_client/task_update.h
+++ b/components/update_client/task_update.h
@@ -28,12 +28,14 @@
 
   // |update_engine| is injected here to handle the task.
   // |is_foreground| is true when the update task is initiated by the user.
+  // |is_install| is true when the task is initiated in an install flow.
   // |ids| represents the CRXs to be updated by this task.
   // |crx_data_callback| is called to get update data for the these CRXs.
   // |callback| is called to return the execution flow back to creator of
   //    this task when the task is done.
   TaskUpdate(scoped_refptr<UpdateEngine> update_engine,
              bool is_foreground,
+             bool is_install,
              const std::vector<std::string>& ids,
              UpdateClient::CrxDataCallback crx_data_callback,
              UpdateClient::CrxStateChangeCallback crx_state_change_callback,
@@ -59,6 +61,7 @@
   base::ThreadChecker thread_checker_;
   scoped_refptr<UpdateEngine> update_engine_;
   const bool is_foreground_;
+  const bool is_install_;
   const std::vector<std::string> ids_;
   UpdateClient::CrxDataCallback crx_data_callback_;
   UpdateClient::CrxStateChangeCallback crx_state_change_callback_;
diff --git a/components/update_client/update_checker_unittest.cc b/components/update_client/update_checker_unittest.cc
index 7f5842d..de549312 100644
--- a/components/update_client/update_checker_unittest.cc
+++ b/components/update_client/update_checker_unittest.cc
@@ -180,7 +180,7 @@
 
 scoped_refptr<UpdateContext> UpdateCheckerTest::MakeMockUpdateContext() const {
   return base::MakeRefCounted<UpdateContext>(
-      config_, false, std::vector<std::string>(),
+      config_, false, false, std::vector<std::string>(),
       UpdateClient::CrxStateChangeCallback(),
       UpdateEngine::NotifyObserversCallback(), UpdateEngine::Callback(),
       nullptr);
diff --git a/components/update_client/update_client.cc b/components/update_client/update_client.cc
index fe5ee1d86..33a9ea3 100644
--- a/components/update_client/update_client.cc
+++ b/components/update_client/update_client.cc
@@ -24,7 +24,6 @@
 #include "components/update_client/persisted_data.h"
 #include "components/update_client/ping_manager.h"
 #include "components/update_client/protocol_parser.h"
-#include "components/update_client/task_send_registration_ping.h"
 #include "components/update_client/task_send_uninstall_ping.h"
 #include "components/update_client/task_update.h"
 #include "components/update_client/update_checker.h"
@@ -96,9 +95,10 @@
   // Install tasks are run concurrently and never queued up. They are always
   // considered foreground tasks.
   constexpr bool kIsForeground = true;
+  constexpr bool kIsInstall = true;
   RunTask(base::MakeRefCounted<TaskUpdate>(
-      update_engine_.get(), kIsForeground, ids, std::move(crx_data_callback),
-      crx_state_change_callback,
+      update_engine_.get(), kIsForeground, kIsInstall, ids,
+      std::move(crx_data_callback), crx_state_change_callback,
       base::BindOnce(&UpdateClientImpl::OnTaskComplete, this,
                      std::move(callback))));
 }
@@ -110,9 +110,10 @@
                               Callback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
+  constexpr bool kIsInstall = false;
   auto task = base::MakeRefCounted<TaskUpdate>(
-      update_engine_.get(), is_foreground, ids, std::move(crx_data_callback),
-      crx_state_change_callback,
+      update_engine_.get(), is_foreground, kIsInstall, ids,
+      std::move(crx_data_callback), crx_state_change_callback,
       base::BindOnce(&UpdateClientImpl::OnTaskComplete, this,
                      std::move(callback)));
 
@@ -236,16 +237,6 @@
                      std::move(callback))));
 }
 
-void UpdateClientImpl::SendRegistrationPing(const CrxComponent& crx_component,
-                                            Callback callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  RunTask(base::MakeRefCounted<TaskSendRegistrationPing>(
-      update_engine_.get(), crx_component,
-      base::BindOnce(&UpdateClientImpl::OnTaskComplete, this,
-                     std::move(callback))));
-}
-
 scoped_refptr<UpdateClient> UpdateClientFactory(
     scoped_refptr<Configurator> config) {
   return base::MakeRefCounted<UpdateClientImpl>(
diff --git a/components/update_client/update_client.h b/components/update_client/update_client.h
index 4e98a52e..2cf39f9 100644
--- a/components/update_client/update_client.h
+++ b/components/update_client/update_client.h
@@ -484,13 +484,6 @@
                                  int reason,
                                  Callback callback) = 0;
 
-  // Sends a registration ping for `crx_component`. The current implementation
-  // of this function only sends a best-effort ping. It has no other side
-  // effects regarding installs or updates done through an instance of this
-  // class.
-  virtual void SendRegistrationPing(const CrxComponent& crx_component,
-                                    Callback callback) = 0;
-
   // Returns status details about a CRX update. The function returns true in
   // case of success and false in case of errors, such as |id| was
   // invalid or not known.
diff --git a/components/update_client/update_client_internal.h b/components/update_client/update_client_internal.h
index f767365..a6b928f5 100644
--- a/components/update_client/update_client_internal.h
+++ b/components/update_client/update_client_internal.h
@@ -54,8 +54,6 @@
   void SendUninstallPing(const CrxComponent& crx_component,
                          int reason,
                          Callback callback) override;
-  void SendRegistrationPing(const CrxComponent& crx_component,
-                            Callback callback) override;
 
  private:
   ~UpdateClientImpl() override;
diff --git a/components/update_client/update_client_unittest.cc b/components/update_client/update_client_unittest.cc
index f1ede7d..ba8405c 100644
--- a/components/update_client/update_client_unittest.cc
+++ b/components/update_client/update_client_unittest.cc
@@ -3235,70 +3235,6 @@
   RunThreads();
 }
 
-TEST_F(UpdateClientTest, SendRegistrationPing) {
-  class CompletionCallbackMock {
-   public:
-    static void Callback(base::OnceClosure quit_closure, Error error) {
-      std::move(quit_closure).Run();
-    }
-  };
-
-  class MockUpdateChecker : public UpdateChecker {
-   public:
-    static std::unique_ptr<UpdateChecker> Create(
-        scoped_refptr<Configurator> config,
-        PersistedData* metadata) {
-      return std::make_unique<MockUpdateChecker>();
-    }
-
-    void CheckForUpdates(
-        const std::string& session_id,
-        const std::vector<std::string>& ids_to_check,
-        const IdToComponentPtrMap& components,
-        const base::flat_map<std::string, std::string>& additional_attributes,
-        UpdateCheckCallback update_check_callback) override {
-      NOTREACHED();
-    }
-  };
-
-  class MockCrxDownloader : public CrxDownloader {
-   public:
-    MockCrxDownloader() : CrxDownloader(nullptr) {}
-
-   private:
-    ~MockCrxDownloader() override = default;
-
-    void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); }
-  };
-
-  class MockPingManager : public MockPingManagerImpl {
-   public:
-    explicit MockPingManager(scoped_refptr<Configurator> config)
-        : MockPingManagerImpl(config) {}
-
-   protected:
-    ~MockPingManager() override {
-      const auto ping_data = MockPingManagerImpl::ping_data();
-      EXPECT_EQ(1u, ping_data.size());
-      EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
-      EXPECT_EQ(base::Version("1.2.3.4"), ping_data[0].next_version);
-    }
-  };
-
-  scoped_refptr<UpdateClient> update_client =
-      base::MakeRefCounted<UpdateClientImpl>(
-          config(), base::MakeRefCounted<MockPingManager>(config()),
-          &MockUpdateChecker::Create);
-
-  CrxComponent crx;
-  crx.app_id = "jebgalgnebhfojomionfpkfelancnnkf";
-  crx.version = base::Version("1.2.3.4");
-  update_client->SendRegistrationPing(
-      crx, base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
-
-  RunThreads();
-}
-
 TEST_F(UpdateClientTest, RetryAfter) {
   class DataCallbackMock {
    public:
@@ -4223,10 +4159,10 @@
       EXPECT_EQ(1, event1.FindKey("eventresult")->GetInt());
       EXPECT_EQ(1877345072, event1.FindKey("errorcode")->GetInt());
 
-      // "<event eventtype=\"3\" eventresult=\"1\" previousversion=\"0.0\" "
+      // "<event eventtype=\"2\" eventresult=\"1\" previousversion=\"0.0\" "
       // "nextversion=\"1.0\"/>",
       const auto& event2 = events()[2];
-      EXPECT_EQ(3, event2.FindKey("eventtype")->GetInt());
+      EXPECT_EQ(2, event2.FindKey("eventtype")->GetInt());
       EXPECT_EQ(1, event1.FindKey("eventresult")->GetInt());
       EXPECT_EQ("0.0", event0.FindKey("previousversion")->GetString());
       EXPECT_EQ("1.0", event0.FindKey("nextversion")->GetString());
diff --git a/components/update_client/update_engine.cc b/components/update_client/update_engine.cc
index ae9d941..8ea994e 100644
--- a/components/update_client/update_engine.cc
+++ b/components/update_client/update_engine.cc
@@ -34,6 +34,7 @@
 UpdateContext::UpdateContext(
     scoped_refptr<Configurator> config,
     bool is_foreground,
+    bool is_install,
     const std::vector<std::string>& ids,
     UpdateClient::CrxStateChangeCallback crx_state_change_callback,
     const UpdateEngine::NotifyObserversCallback& notify_observers_callback,
@@ -41,6 +42,7 @@
     PersistedData* persisted_data)
     : config(config),
       is_foreground(is_foreground),
+      is_install(is_install),
       ids(ids),
       crx_state_change_callback(crx_state_change_callback),
       notify_observers_callback(notify_observers_callback),
@@ -74,6 +76,7 @@
 
 void UpdateEngine::Update(
     bool is_foreground,
+    bool is_install,
     const std::vector<std::string>& ids,
     UpdateClient::CrxDataCallback crx_data_callback,
     UpdateClient::CrxStateChangeCallback crx_state_change_callback,
@@ -104,7 +107,7 @@
   }
 
   const auto update_context = base::MakeRefCounted<UpdateContext>(
-      config_, is_foreground, ids, crx_state_change_callback,
+      config_, is_foreground, is_install, ids, crx_state_change_callback,
       notify_observers_callback_, std::move(callback), metadata_.get());
   DCHECK(!update_context->session_id.empty());
 
@@ -386,7 +389,7 @@
   const std::string& id = crx_component.app_id;
 
   const auto update_context = base::MakeRefCounted<UpdateContext>(
-      config_, false, std::vector<std::string>{id},
+      config_, false, false, std::vector<std::string>{id},
       UpdateClient::CrxStateChangeCallback(),
       UpdateEngine::NotifyObserversCallback(), std::move(callback),
       metadata_.get());
@@ -410,35 +413,4 @@
       base::BindOnce(&UpdateEngine::HandleComponent, this, update_context));
 }
 
-void UpdateEngine::SendRegistrationPing(const CrxComponent& crx_component,
-                                        Callback callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  const std::string& id = crx_component.app_id;
-
-  const auto update_context = base::MakeRefCounted<UpdateContext>(
-      config_, false, std::vector<std::string>{id},
-      UpdateClient::CrxStateChangeCallback(),
-      UpdateEngine::NotifyObserversCallback(), std::move(callback),
-      metadata_.get());
-  DCHECK(!update_context->session_id.empty());
-
-  const auto result = update_contexts_.insert(
-      std::make_pair(update_context->session_id, update_context));
-  DCHECK(result.second);
-
-  DCHECK(update_context);
-  DCHECK_EQ(1u, update_context->ids.size());
-  DCHECK_EQ(1u, update_context->components.count(id));
-  const auto& component = update_context->components.at(id);
-
-  component->Registration(crx_component);
-
-  update_context->component_queue.push(id);
-
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&UpdateEngine::HandleComponent, this, update_context));
-}
-
 }  // namespace update_client
diff --git a/components/update_client/update_engine.h b/components/update_client/update_engine.h
index 265ada0..4d4ca4d6 100644
--- a/components/update_client/update_engine.h
+++ b/components/update_client/update_engine.h
@@ -58,6 +58,7 @@
   bool GetUpdateState(const std::string& id, CrxUpdateItem* update_state);
 
   void Update(bool is_foreground,
+              bool is_install,
               const std::vector<std::string>& ids,
               UpdateClient::CrxDataCallback crx_data_callback,
               UpdateClient::CrxStateChangeCallback crx_state_change_callback,
@@ -67,9 +68,6 @@
                          int reason,
                          Callback update_callback);
 
-  void SendRegistrationPing(const CrxComponent& crx_component,
-                            Callback update_callback);
-
  private:
   friend class base::RefCountedThreadSafe<UpdateEngine>;
   ~UpdateEngine();
@@ -118,6 +116,7 @@
   UpdateContext(
       scoped_refptr<Configurator> config,
       bool is_foreground,
+      bool is_install,
       const std::vector<std::string>& ids,
       UpdateClient::CrxStateChangeCallback crx_state_change_callback,
       const UpdateEngine::NotifyObserversCallback& notify_observers_callback,
@@ -131,6 +130,9 @@
   // True if the component is updated as a result of user interaction.
   bool is_foreground = false;
 
+  // True if the component is updating in an installation flow.
+  bool is_install = false;
+
   // Contains the ids of all CRXs in this context in the order specified
   // by the caller of |UpdateClient::Update| or |UpdateClient:Install|.
   const std::vector<std::string> ids;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index c2ffe0a9..7de8d6a 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2091,6 +2091,8 @@
     "webauth/client_data_json.h",
     "webauth/webauth_request_security_checker.cc",
     "webauth/webauth_request_security_checker.h",
+    "webid/fake_identity_request_dialog_controller.cc",
+    "webid/fake_identity_request_dialog_controller.h",
     "webid/fedcm_metrics.cc",
     "webid/fedcm_metrics.h",
     "webid/federated_auth_request_impl.cc",
diff --git a/content/browser/attribution_reporting/privacy_sandbox_ads_apis_browsertest.cc b/content/browser/attribution_reporting/privacy_sandbox_ads_apis_browsertest.cc
index 82745dd0..6bab231 100644
--- a/content/browser/attribution_reporting/privacy_sandbox_ads_apis_browsertest.cc
+++ b/content/browser/attribution_reporting/privacy_sandbox_ads_apis_browsertest.cc
@@ -68,7 +68,7 @@
   PrivacySandboxAdsAPIsAllEnabledBrowserTest() {
     feature_list_.InitWithFeatures(
         {blink::features::kPrivacySandboxAdsAPIs,
-         blink::features::kBrowsingTopics, blink::features::kFledge},
+         blink::features::kBrowsingTopics, blink::features::kInterestGroupStorage},
         /*disabled_features=*/{});
   }
 
@@ -154,7 +154,7 @@
  public:
   PrivacySandboxAdsAPIsFledgeDisabledBrowserTest() {
     feature_list_.InitWithFeatures({blink::features::kPrivacySandboxAdsAPIs},
-                                   {blink::features::kFledge});
+                                   {blink::features::kInterestGroupStorage});
   }
 
  private:
diff --git a/content/browser/interest_group/ad_auction_result_metrics.cc b/content/browser/interest_group/ad_auction_result_metrics.cc
index 36f6997..c180e9d 100644
--- a/content/browser/interest_group/ad_auction_result_metrics.cc
+++ b/content/browser/interest_group/ad_auction_result_metrics.cc
@@ -47,7 +47,6 @@
 }
 
 bool AdAuctionResultMetrics::ShouldRunAuction() {
-  DCHECK(base::FeatureList::IsEnabled(blink::features::kFledge));
   num_requested_auctions_++;
   if (!base::FeatureList::IsEnabled(features::kFledgeLimitNumAuctions))
     return true;
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc
index b8613fb..4a1c5261 100644
--- a/content/browser/interest_group/interest_group_browsertest.cc
+++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -245,8 +245,7 @@
         {blink::features::kInterestGroupStorage,
          blink::features::kAdInterestGroupAPI, blink::features::kParakeet,
          blink::features::kFledge, blink::features::kAllowURNsInIframes,
-         blink::features::kBiddingAndScoringDebugReportingAPI,
-         features::kPrivacySandboxAdsAPIsOverride},
+         blink::features::kBiddingAndScoringDebugReportingAPI},
         /*disabled_features=*/
         {blink::features::kFencedFrames});
   }
diff --git a/content/browser/network_sandbox.cc b/content/browser/network_sandbox.cc
index a436b0c9..3fa68bd6 100644
--- a/content/browser/network_sandbox.cc
+++ b/content/browser/network_sandbox.cc
@@ -164,7 +164,7 @@
     network::mojom::NetworkContextParams* params) {
   // Never delete old data unless the checkpoint file exists.
   DCHECK(base::PathExists(
-      params->file_paths->data_directory.Append(kCheckpointFileName)));
+      params->file_paths->data_directory.path().Append(kCheckpointFileName)));
 
   SandboxGrantResult last_error = SandboxGrantResult::kSuccess;
   SandboxGrantResult result = MaybeDeleteOldData(
@@ -202,19 +202,22 @@
 }
 
 // Grants the sandbox access to the specified `path`, which must be a directory
-// that exists. Currently this is only implemented on Windows, where the LPAC
-// capability name should be supplied in the `sandbox_params` to specify the
-// name of the LPAC capability to be applied to the path. Returns true if the
-// sandbox was successfully granted access to the path.
+// that exists.  On Windows, the LPAC capability name should be supplied in the
+// `sandbox_params` to specify the name of the LPAC capability to be applied to
+// the path.  On platforms which support directory transfer, the directory is
+// opened as a handle which is then sent to the NetworkService.
+// Returns true if the sandbox was successfully granted access to the path.
 bool MaybeGrantAccessToDataPath(const SandboxParameters& sandbox_params,
-                                const base::FilePath& path) {
+                                network::TransferableDirectory* directory) {
   // There is no need to set file permissions if the network service is running
   // in-process.
   if (IsInProcessNetworkService())
     return true;
   // Only do this on directories.
-  if (!base::DirectoryExists(path))
+  if (!base::DirectoryExists(directory->path())) {
     return false;
+  }
+
 #if BUILDFLAG(IS_WIN)
   // On platforms that don't support the LPAC sandbox, do nothing.
   if (!sandbox::features::IsAppContainerSandboxSupported())
@@ -230,9 +233,15 @@
   // Grant recursive access to directory. This also means new files in the
   // directory will inherit the ACE.
   return base::win::GrantAccessToPath(
-      path, *ac_sids, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE,
+      directory->path(), *ac_sids,
+      GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE,
       CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, /*recursive=*/true);
 #else
+  if (directory->IsOpenForTransferRequired()) {
+    directory->OpenForTransfer();
+    return true;
+  }
+
   return true;
 #endif  // BUILDFLAG(IS_WIN)
 }
@@ -279,7 +288,7 @@
   if (params->http_cache_directory && params->http_cache_enabled) {
     SandboxGrantResult cache_result = SandboxGrantResult::kSuccess;
     // The path must exist for the cache ACL to be set. Create if needed.
-    if (!base::CreateDirectory(params->http_cache_directory.value()))
+    if (!base::CreateDirectory(params->http_cache_directory->path()))
       cache_result = SandboxGrantResult::kFailedToCreateCacheDirectory;
     if (cache_result == SandboxGrantResult::kSuccess) {
       // Note, this code always grants access to the cache directory even when
@@ -289,9 +298,9 @@
       // inherited ACE rather than having to set them manually later.
       SCOPED_UMA_HISTOGRAM_TIMER("NetworkService.TimeToGrantCacheAccess");
       if (!MaybeGrantAccessToDataPath(sandbox_params,
-                                      params->http_cache_directory.value())) {
+                                      &*params->http_cache_directory)) {
         PLOG(ERROR) << "Failed to grant sandbox access to cache directory "
-                    << *params->http_cache_directory;
+                    << params->http_cache_directory->path();
         cache_result = SandboxGrantResult::kFailedToGrantSandboxAccessToCache;
       }
     }
@@ -306,7 +315,7 @@
   if (!params->file_paths)
     return SandboxGrantResult::kDidNotAttemptToGrantSandboxAccess;
 
-  DCHECK(!params->file_paths->data_directory.empty());
+  DCHECK(!params->file_paths->data_directory.path().empty());
 
   if (!params->file_paths->unsandboxed_data_path.has_value()) {
 #if BUILDFLAG(IS_WIN) && DCHECK_IS_ON()
@@ -324,7 +333,7 @@
   // If these paths are ever the same then this is a mistake, as the file
   // permissions will be applied to the top level path which could contain other
   // data that should not be accessible by the network sandbox.
-  DCHECK_NE(params->file_paths->data_directory,
+  DCHECK_NE(params->file_paths->data_directory.path(),
             *params->file_paths->unsandboxed_data_path);
 
   // Four cases need to be handled here.
@@ -343,7 +352,7 @@
   // to `data_directory`. This is the same as above and `trigger_migration`
   // changes nothing, as it's already happened.
   base::FilePath checkpoint_filename =
-      params->file_paths->data_directory.Append(kCheckpointFileName);
+      params->file_paths->data_directory.path().Append(kCheckpointFileName);
   bool migration_already_happened = base::PathExists(checkpoint_filename);
 
   // Case 1. above where nothing is done.
@@ -360,9 +369,9 @@
   // Create the `data_directory` if necessary so access can be granted to it.
   // Note that if a migration has already happened then this does nothing, as
   // the directory already exists.
-  if (!base::CreateDirectory(params->file_paths->data_directory)) {
+  if (!base::CreateDirectory(params->file_paths->data_directory.path())) {
     PLOG(ERROR) << "Failed to create network context data directory "
-                << params->file_paths->data_directory;
+                << params->file_paths->data_directory.path();
     // This is a fatal error, if the `data_directory` does not exist then
     // migration cannot be attempted. In this case the network context will
     // operate using `unsandboxed_data_path` and the migration attempt will be
@@ -383,10 +392,10 @@
     // as they do not rely on filesystem permissions, but runtime sandbox broker
     // permissions.
     if (!MaybeGrantAccessToDataPath(sandbox_params,
-                                    params->file_paths->data_directory)) {
+                                    &params->file_paths->data_directory)) {
       PLOG(ERROR)
           << "Failed to grant sandbox access to network context data directory "
-          << params->file_paths->data_directory;
+          << params->file_paths->data_directory.path();
       // If migration has already happened there isn't much that can be done
       // about this, the data has already moved, but the sandbox might not have
       // access.
@@ -435,14 +444,14 @@
     // existing files if it was partially successful in an earlier attempt.
     SCOPED_UMA_HISTOGRAM_TIMER("NetworkService.TimeToMigrateData");
     result = MaybeCopyData(*params->file_paths->unsandboxed_data_path,
-                           params->file_paths->data_directory,
+                           params->file_paths->data_directory.path(),
                            params->file_paths->cookie_database_name,
                            /*is_sql=*/true);
     if (result != SandboxGrantResult::kSuccess)
       return result;
 
     result = MaybeCopyData(*params->file_paths->unsandboxed_data_path,
-                           params->file_paths->data_directory,
+                           params->file_paths->data_directory.path(),
                            params->file_paths->http_server_properties_file_name,
                            /*is_sql=*/false);
     if (result != SandboxGrantResult::kSuccess)
@@ -450,7 +459,7 @@
 
     result = MaybeCopyData(
         *params->file_paths->unsandboxed_data_path,
-        params->file_paths->data_directory,
+        params->file_paths->data_directory.path(),
         params->file_paths->transport_security_persister_file_name,
         /*is_sql=*/false);
     if (result != SandboxGrantResult::kSuccess)
@@ -458,14 +467,14 @@
 
     result =
         MaybeCopyData(*params->file_paths->unsandboxed_data_path,
-                      params->file_paths->data_directory,
+                      params->file_paths->data_directory.path(),
                       params->file_paths->reporting_and_nel_store_database_name,
                       /*is_sql=*/true);
     if (result != SandboxGrantResult::kSuccess)
       return result;
 
     result = MaybeCopyData(*params->file_paths->unsandboxed_data_path,
-                           params->file_paths->data_directory,
+                           params->file_paths->data_directory.path(),
                            params->file_paths->trust_token_database_name,
                            /*is_sql=*/true);
     if (result != SandboxGrantResult::kSuccess)
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index db278a8..99932b95 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -73,68 +73,6 @@
 
 namespace {
 
-constexpr char kCookieName[] = "Name";
-constexpr char kCookieValue[] = "Value";
-const base::FilePath::CharType kCheckpointFileName[] =
-    FILE_PATH_LITERAL("NetworkDataMigrated");
-
-net::CookieList GetCookies(
-    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
-  base::RunLoop run_loop;
-  net::CookieList cookies_out;
-  cookie_manager->GetAllCookies(
-      base::BindLambdaForTesting([&](const net::CookieList& cookies) {
-        cookies_out = cookies;
-        run_loop.Quit();
-      }));
-  run_loop.Run();
-  return cookies_out;
-}
-
-void SetCookie(
-    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
-  base::Time t = base::Time::Now();
-  auto cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
-      kCookieName, kCookieValue, "example.test", "/", t, t + base::Days(1),
-      base::Time(), true /* secure */, false /* http-only*/,
-      net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
-      false /* same_party */);
-  base::RunLoop run_loop;
-  cookie_manager->SetCanonicalCookie(
-      *cookie, net::cookie_util::SimulatedCookieSource(*cookie, "https"),
-      net::CookieOptions(),
-      base::BindLambdaForTesting(
-          [&](net::CookieAccessResult result) { run_loop.Quit(); }));
-  run_loop.Run();
-}
-
-void FlushCookies(
-    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
-  base::RunLoop run_loop;
-  cookie_manager->FlushCookieStore(
-      base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
-  run_loop.Run();
-}
-
-mojo::PendingRemote<network::mojom::NetworkContext>
-CreateNetworkContextForPaths(network::mojom::NetworkContextFilePathsPtr paths,
-                             const base::FilePath& cache_path) {
-  network::mojom::NetworkContextParamsPtr context_params =
-      network::mojom::NetworkContextParams::New();
-  context_params->file_paths = std::move(paths);
-  context_params->cert_verifier_params = GetCertVerifierParams(
-      cert_verifier::mojom::CertVerifierCreationParams::New());
-  // Not passing in a key for simplicity, so disable encryption.
-  context_params->enable_encrypted_cookies = false;
-  context_params->http_cache_enabled = true;
-  context_params->http_cache_directory = cache_path;
-  mojo::PendingRemote<network::mojom::NetworkContext> network_context;
-  content::CreateNetworkContextInNetworkService(
-      network_context.InitWithNewPipeAndPassReceiver(),
-      std::move(context_params));
-  return network_context;
-}
-
 class WebUITestWebUIControllerFactory : public WebUIControllerFactory {
  public:
   std::unique_ptr<WebUIController> CreateWebUIControllerForURL(
@@ -610,7 +548,6 @@
 
 // Android doesn't support PRE_ tests.
 // TODO(wfh): Enable this test when https://crbug.com/1257820 is fixed.
-// TODO(crbug.com/1266222): Fix disk cache error on Fuchsia
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
 class NetworkServiceBrowserCacheResetTest : public NetworkServiceBrowserTest {
  public:
@@ -765,7 +702,72 @@
                                            /*load_only_from_cache=*/true, url),
               net::test::IsError(net::ERR_CACHE_MISS));
 }
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
+#endif  // BUILDFLAG(IS_ANDROID)
+
+// Cache data migration is not used for Fuchsia.
+#if !BUILDFLAG(IS_FUCHSIA)
+
+const base::FilePath::CharType kCheckpointFileName[] =
+    FILE_PATH_LITERAL("NetworkDataMigrated");
+constexpr char kCookieName[] = "Name";
+constexpr char kCookieValue[] = "Value";
+
+net::CookieList GetCookies(
+    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
+  base::RunLoop run_loop;
+  net::CookieList cookies_out;
+  cookie_manager->GetAllCookies(
+      base::BindLambdaForTesting([&](const net::CookieList& cookies) {
+        cookies_out = cookies;
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+  return cookies_out;
+}
+
+void SetCookie(
+    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
+  base::Time t = base::Time::Now();
+  auto cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
+      kCookieName, kCookieValue, "example.test", "/", t, t + base::Days(1),
+      base::Time(), true /* secure */, false /* http-only*/,
+      net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT,
+      false /* same_party */);
+  base::RunLoop run_loop;
+  cookie_manager->SetCanonicalCookie(
+      *cookie, net::cookie_util::SimulatedCookieSource(*cookie, "https"),
+      net::CookieOptions(),
+      base::BindLambdaForTesting(
+          [&](net::CookieAccessResult result) { run_loop.Quit(); }));
+  run_loop.Run();
+}
+
+void FlushCookies(
+    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
+  base::RunLoop run_loop;
+  cookie_manager->FlushCookieStore(
+      base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
+  run_loop.Run();
+}
+
+mojo::PendingRemote<network::mojom::NetworkContext>
+CreateNetworkContextForPaths(network::mojom::NetworkContextFilePathsPtr paths,
+                             const base::FilePath& cache_path) {
+  network::mojom::NetworkContextParamsPtr context_params =
+      network::mojom::NetworkContextParams::New();
+  context_params->file_paths = std::move(paths);
+  context_params->cert_verifier_params = GetCertVerifierParams(
+      cert_verifier::mojom::CertVerifierCreationParams::New());
+  // Not passing in a key for simplicity, so disable encryption.
+  context_params->enable_encrypted_cookies = false;
+  context_params->http_cache_enabled = true;
+  context_params->http_cache_directory = cache_path;
+  mojo::PendingRemote<network::mojom::NetworkContext> network_context;
+  content::CreateNetworkContextInNetworkService(
+      network_context.InitWithNewPipeAndPassReceiver(),
+      std::move(context_params));
+  return network_context;
+}
 
 enum class FailureType {
   kNoFailures = 0,
@@ -1471,6 +1473,8 @@
     ::testing::Combine(::testing::Values(false),
                        ::testing::ValuesIn(kFailureTypes)));
 
+#endif  // !BUILDFLAG(IS_FUCHSIA)
+
 class NetworkServiceInProcessBrowserTest : public ContentBrowserTest {
  public:
   NetworkServiceInProcessBrowserTest() {
diff --git a/content/browser/network_service_instance_impl.cc b/content/browser/network_service_instance_impl.cc
index 256da2fe..b577151f 100644
--- a/content/browser/network_service_instance_impl.cc
+++ b/content/browser/network_service_instance_impl.cc
@@ -259,8 +259,9 @@
       grant_access_result != SandboxGrantResult::kMigrationAlreadySucceeded) {
     PLOG(ERROR) << "Encountered error while migrating network context data or "
                    "granting sandbox access for "
-                << (params->file_paths ? params->file_paths->data_directory
-                                       : base::FilePath())
+                << (params->file_paths
+                        ? params->file_paths->data_directory.path()
+                        : base::FilePath())
                 << ". Result: " << static_cast<int>(grant_access_result);
   }
 
@@ -276,16 +277,16 @@
     params->file_paths->data_directory =
         *params->file_paths->unsandboxed_data_path;
   }
-  if (params->http_cache_enabled && params->http_cache_directory) {
-    // Delete any old data except for the "Cache_Data" directory.
-    base::ThreadPool::PostTask(
-        FROM_HERE,
-        {base::TaskPriority::BEST_EFFORT, base::MayBlock(),
-         base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-        base::BindOnce(MaybeDeleteOldCache, *params->http_cache_directory));
-    params->http_cache_directory =
-        params->http_cache_directory->Append(kCacheDataDirectoryName);
+
+  if (network::TransferableDirectory::IsOpenForTransferRequired()) {
+    if (params->file_paths) {
+      params->file_paths->data_directory.OpenForTransfer();
+    }
+    if (params->http_cache_directory) {
+      params->http_cache_directory->OpenForTransfer();
+    }
   }
+
   GetNetworkService()->CreateNetworkContext(std::move(context),
                                             std::move(params));
 }
@@ -790,11 +791,29 @@
   g_cert_verifier_service_factory_for_testing = service_factory;
 }
 
+void MaybeCleanCacheDirectory(network::mojom::NetworkContextParams* params) {
+  if (params->http_cache_enabled && params->http_cache_directory) {
+    // Delete any old data except for the "Cache_Data" directory.
+    base::ThreadPool::PostTask(
+        FROM_HERE,
+        {base::TaskPriority::BEST_EFFORT, base::MayBlock(),
+         base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+        base::BindOnce(MaybeDeleteOldCache,
+                       params->http_cache_directory->path()));
+
+    params->http_cache_directory =
+        params->http_cache_directory->path().Append(kCacheDataDirectoryName);
+  }
+}
+
 void CreateNetworkContextInNetworkService(
     mojo::PendingReceiver<network::mojom::NetworkContext> context,
     network::mojom::NetworkContextParamsPtr params) {
   TRACE_EVENT0("loading", "CreateNetworkContextInNetworkService");
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  MaybeCleanCacheDirectory(params.get());
+
 #if BUILDFLAG(IS_ANDROID)
   // Create network context immediately without thread hops.
   CreateNetworkContextInternal(
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 49a1d672..ac76f03 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1779,6 +1779,23 @@
   }
 }
 
+ui::TextInputClient::EditingContext
+RenderWidgetHostViewAura::GetTextEditingContext() {
+  ui::TextInputClient::EditingContext editing_context;
+  // We use the focused frame's URL here and not the main frame because
+  // TSF(Windows Text Service Framework) works on the active editable element
+  // context and it uses this information to assist the UIA(Microsoft UI
+  // Automation) service to determine the character that is being typed by the
+  // user via IME composition, the URL of the site that the user is typing on
+  // and other text related services that are used by the UIA clients to power
+  // accessibility features on Windows. We want to expose the focused frame's
+  // URL to TSF that notifies the UIA service which uses this info and the
+  // focused element's data to provide better screen reading capabilities.
+  RenderFrameHostImpl* frame = GetFocusedFrame();
+  if (frame)
+    editing_context.page_url = frame->GetLastCommittedURL();
+  return editing_context;
+}
 #endif
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 8ae8485..0bb88cf 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -279,6 +279,12 @@
       const gfx::Range& range,
       const std::u16string& active_composition_text,
       bool is_composition_committed) override;
+
+  // Returns the editing context of the active web content.
+  // This is currently used by TSF to  to fetch the URL of the active web
+  // content.
+  // https://docs.microsoft.com/en-us/windows/win32/tsf/predefined-properties
+  ui::TextInputClient::EditingContext GetTextEditingContext() override;
 #endif
 
   // Overridden from display::DisplayObserver:
diff --git a/content/browser/webid/fake_identity_request_dialog_controller.cc b/content/browser/webid/fake_identity_request_dialog_controller.cc
new file mode 100644
index 0000000..0fa61a3
--- /dev/null
+++ b/content/browser/webid/fake_identity_request_dialog_controller.cc
@@ -0,0 +1,32 @@
+// 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 "content/browser/webid/fake_identity_request_dialog_controller.h"
+
+namespace content {
+
+FakeIdentityRequestDialogController::FakeIdentityRequestDialogController(
+    absl::optional<std::string> selected_account)
+    : selected_account_(selected_account) {}
+
+FakeIdentityRequestDialogController::~FakeIdentityRequestDialogController() =
+    default;
+
+void FakeIdentityRequestDialogController::ShowAccountsDialog(
+    content::WebContents* rp_web_contents,
+    const GURL& idp_signin_url,
+    base::span<const IdentityRequestAccount> accounts,
+    const IdentityProviderMetadata& idp_metadata,
+    const ClientIdData& client_id_data,
+    IdentityRequestAccount::SignInMode sign_in_mode,
+    AccountSelectionCallback on_selected) {
+  DCHECK_GT(accounts.size(), 0ul);
+  // Use the provided account, if any. Otherwise use the first one.
+  if (selected_account_)
+    std::move(on_selected).Run(*selected_account_, /* is_sign_in= */ true);
+  else
+    std::move(on_selected).Run(accounts[0].id, /* is_sign_in= */ true);
+}
+
+}  // namespace content
diff --git a/content/browser/webid/fake_identity_request_dialog_controller.h b/content/browser/webid/fake_identity_request_dialog_controller.h
new file mode 100644
index 0000000..3dc205b8
--- /dev/null
+++ b/content/browser/webid/fake_identity_request_dialog_controller.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 CONTENT_BROWSER_WEBID_FAKE_IDENTITY_REQUEST_DIALOG_CONTROLLER_H_
+#define CONTENT_BROWSER_WEBID_FAKE_IDENTITY_REQUEST_DIALOG_CONTROLLER_H_
+
+#include <string>
+
+#include "content/public/browser/identity_request_dialog_controller.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace content {
+
+// This fakes the request dialogs to always provide user consent.
+// Used by tests and if the --use-fake-ui-for-fedcm command-line
+// flag is provided.
+class CONTENT_EXPORT FakeIdentityRequestDialogController
+    : public IdentityRequestDialogController {
+ public:
+  explicit FakeIdentityRequestDialogController(
+      absl::optional<std::string> selected_account = absl::nullopt);
+  ~FakeIdentityRequestDialogController() override;
+
+  void ShowAccountsDialog(content::WebContents* rp_web_contents,
+                          const GURL& idp_signin_url,
+                          base::span<const IdentityRequestAccount> accounts,
+                          const IdentityProviderMetadata& idp_metadata,
+                          const ClientIdData& client_id_data,
+                          IdentityRequestAccount::SignInMode sign_in_mode,
+                          AccountSelectionCallback on_selected) override;
+
+ private:
+  absl::optional<std::string> selected_account_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_WEBID_FAKE_IDENTITY_REQUEST_DIALOG_CONTROLLER_H_
diff --git a/content/browser/webid/federated_auth_request_impl.cc b/content/browser/webid/federated_auth_request_impl.cc
index 5a3fa17..1ccc2f2 100644
--- a/content/browser/webid/federated_auth_request_impl.cc
+++ b/content/browser/webid/federated_auth_request_impl.cc
@@ -5,12 +5,14 @@
 #include "content/browser/webid/federated_auth_request_impl.h"
 
 #include "base/callback.h"
+#include "base/command_line.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_piece.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/browser/webid/fake_identity_request_dialog_controller.h"
 #include "content/browser/webid/fedcm_metrics.h"
 #include "content/browser/webid/flags.h"
 #include "content/browser/webid/webid_utils.h"
@@ -23,6 +25,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_client.h"
+#include "content/public/common/content_switches.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
 #include "third_party/blink/public/mojom/devtools/inspector_issue.mojom.h"
 #include "ui/accessibility/ax_mode.h"
@@ -1108,6 +1111,17 @@
   if (mock_dialog_controller_)
     return std::move(mock_dialog_controller_);
 
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kUseFakeUIForFedCM)) {
+    std::string selected_account =
+        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+            switches::kUseFakeUIForFedCM);
+    return std::make_unique<FakeIdentityRequestDialogController>(
+        selected_account.empty()
+            ? absl::nullopt
+            : absl::optional<std::string>(selected_account));
+  }
+
   return GetContentClient()->browser()->CreateIdentityRequestDialogController();
 }
 
diff --git a/content/browser/webid/test/fake_identity_request_dialog_controller.cc b/content/browser/webid/test/fake_identity_request_dialog_controller.cc
deleted file mode 100644
index c66f78bc..0000000
--- a/content/browser/webid/test/fake_identity_request_dialog_controller.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/webid/test/fake_identity_request_dialog_controller.h"
-
-#include "base/bind.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-FakeIdentityRequestDialogController::FakeIdentityRequestDialogController(
-    absl::optional<std::string> dialog_selected_account)
-    : dialog_selected_account_(dialog_selected_account) {}
-
-FakeIdentityRequestDialogController::~FakeIdentityRequestDialogController() =
-    default;
-
-void FakeIdentityRequestDialogController::ShowAccountsDialog(
-    WebContents* rp_web_contents,
-    const GURL& idp_signin_url,
-    base::span<const IdentityRequestAccount> accounts,
-    const IdentityProviderMetadata& idp_metadata,
-    const ClientIdData& client_id_data,
-    IdentityRequestAccount::SignInMode sign_in_mode,
-    AccountSelectionCallback on_selected) {
-  if (dialog_selected_account_) {
-    std::move(on_selected)
-        .Run(*dialog_selected_account_, true /* is_sign_in */);
-  }
-}
-
-}  // namespace content
diff --git a/content/browser/webid/test/fake_identity_request_dialog_controller.h b/content/browser/webid/test/fake_identity_request_dialog_controller.h
deleted file mode 100644
index 342b9b4..0000000
--- a/content/browser/webid/test/fake_identity_request_dialog_controller.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_WEBID_TEST_FAKE_IDENTITY_REQUEST_DIALOG_CONTROLLER_H_
-#define CONTENT_BROWSER_WEBID_TEST_FAKE_IDENTITY_REQUEST_DIALOG_CONTROLLER_H_
-
-#include <string>
-
-#include "content/public/browser/identity_request_dialog_controller.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "url/gurl.h"
-
-namespace content {
-
-class WebContents;
-
-// This fakes the request dialogs to always provide user consent.
-// Tests that need to vary the responses or set test expectations should use
-// MockIdentityRequestDialogController.
-// This also fakes an IdP sign-in page until tests can be set up to
-// verify the FederatedAuthResponse mechanics.
-class FakeIdentityRequestDialogController
-    : public IdentityRequestDialogController {
- public:
-  explicit FakeIdentityRequestDialogController(
-      absl::optional<std::string> dialog_selected_account);
-  ~FakeIdentityRequestDialogController() override;
-
-  FakeIdentityRequestDialogController(
-      const FakeIdentityRequestDialogController&) = delete;
-  FakeIdentityRequestDialogController& operator=(
-      const FakeIdentityRequestDialogController&) = delete;
-
-  void ShowAccountsDialog(WebContents* rp_web_contents,
-                          const GURL& idp_signin_url,
-                          base::span<const IdentityRequestAccount> accounts,
-                          const IdentityProviderMetadata& idp_metadata,
-                          const ClientIdData& client_id_data,
-                          IdentityRequestAccount::SignInMode sign_in_mode,
-                          AccountSelectionCallback on_selected) override;
-
- private:
-  absl::optional<std::string> dialog_selected_account_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_WEBID_TEST_FAKE_IDENTITY_REQUEST_DIALOG_CONTROLLER_H_
diff --git a/content/browser/webid/webid_browsertest.cc b/content/browser/webid/webid_browsertest.cc
index bd45be0..e2cba7a2 100644
--- a/content/browser/webid/webid_browsertest.cc
+++ b/content/browser/webid/webid_browsertest.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/network_session_configurator/common/network_switches.h"
-#include "content/browser/webid/test/fake_identity_request_dialog_controller.h"
+#include "content/browser/webid/fake_identity_request_dialog_controller.h"
 #include "content/browser/webid/test/webid_test_content_browser_client.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/identity_request_dialog_controller.h"
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index c1a9b5be..b6990705 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -349,6 +349,8 @@
           {"EditingNG", blink::features::kEditingNG},
           {"ElementSuperRareData", blink::features::kElementSuperRareData},
           {"FileHandling", blink::features::kFileHandlingAPI},
+          {"Fledge", blink::features::kFledge,
+           kSetOnlyIfOverridden},
           {"Fledge", features::kPrivacySandboxAdsAPIsOverride,
            kSetOnlyIfOverridden},
           {"FontAccess", blink::features::kFontAccess},
diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
index d7d82785..3ce26ac 100644
--- a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java
@@ -132,9 +132,9 @@
     BrowserStartupControllerImpl() {
         mAsyncStartupCallbacks = new ArrayList<>();
         mMinimalBrowserStartedCallbacks = new ArrayList<>();
-        if (BuildInfo.isDebugAndroid()) {
-            // Only set up the tracing broadcast receiver on debug builds of the OS. Normal tracing
-            // should use the DevTools API.
+        if (BuildInfo.isDebugAndroid() && !ContextUtils.isSdkSandboxProcess()) {
+            // Only set up the tracing broadcast receiver on debug builds of the OS and
+            // non-SdkSandbox process. Normal tracing should use the DevTools API.
             PostTask.postTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
                 @Override
                 public void run() {
diff --git a/content/public/android/java/src/org/chromium/content/browser/sms/Wrappers.java b/content/public/android/java/src/org/chromium/content/browser/sms/Wrappers.java
index 50f7a65..048ff5f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/sms/Wrappers.java
+++ b/content/public/android/java/src/org/chromium/content/browser/sms/Wrappers.java
@@ -110,7 +110,7 @@
         public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
                 String permission, Handler handler, int flags) {
             onRegisterReceiver(receiver, filter);
-            return super.registerReceiver(receiver, filter, permission, handler);
+            return super.registerReceiver(receiver, filter, permission, handler, flags);
         }
 
         @Override
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index dc96641..bf2342c9 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -799,6 +799,11 @@
 const char kUseFakeCodecForPeerConnection[] =
     "use-fake-codec-for-peer-connection";
 
+// Bypass the FedCM account selection dialog. If a value is provided for
+// this switch, that account ID is selected, otherwise the first account
+// is chosen.
+const char kUseFakeUIForFedCM[] = "use-fake-ui-for-fedcm";
+
 // Bypass the media stream infobar by selecting the default device for media
 // streams (e.g. WebRTC). Works with --use-fake-device-for-media-stream.
 const char kUseFakeUIForMediaStream[]     = "use-fake-ui-for-media-stream";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 07877047..ce85db8 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -221,6 +221,7 @@
 CONTENT_EXPORT extern const char kTouchEventFeatureDetectionDisabled[];
 CONTENT_EXPORT extern const char kTrustableWebBundleFileUrl[];
 CONTENT_EXPORT extern const char kUseFakeCodecForPeerConnection[];
+CONTENT_EXPORT extern const char kUseFakeUIForFedCM[];
 CONTENT_EXPORT extern const char kUseFakeUIForMediaStream[];
 CONTENT_EXPORT extern const char kVideoImageTextureTarget[];
 CONTENT_EXPORT extern const char kUseMobileUserAgent[];
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index cf042eeb..9e6fde15 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -133,8 +133,6 @@
     "browser/shell_download_manager_delegate.h",
     "browser/shell_federated_permission_context.cc",
     "browser/shell_federated_permission_context.h",
-    "browser/shell_identity_dialog_controller.cc",
-    "browser/shell_identity_dialog_controller.h",
     "browser/shell_javascript_dialog.h",
     "browser/shell_javascript_dialog_manager.cc",
     "browser/shell_javascript_dialog_manager.h",
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 353d55e5..1720e904 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -51,7 +51,6 @@
 #include "content/shell/browser/shell_browser_context.h"
 #include "content/shell/browser/shell_browser_main_parts.h"
 #include "content/shell/browser/shell_devtools_manager_delegate.h"
-#include "content/shell/browser/shell_identity_dialog_controller.h"
 #include "content/shell/browser/shell_paths.h"
 #include "content/shell/browser/shell_quota_permission_context.h"
 #include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
@@ -621,11 +620,6 @@
   return http_status_code >= 400 && http_status_code < 600;
 }
 
-std::unique_ptr<IdentityRequestDialogController>
-ShellContentBrowserClient::CreateIdentityRequestDialogController() {
-  return std::make_unique<ShellIdentityDialogController>();
-}
-
 void ShellContentBrowserClient::CreateFeatureListAndFieldTrials() {
   local_state_ = CreateLocalState();
   SetUpFieldTrials();
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h
index 7d02e93b..9aa5169 100644
--- a/content/shell/browser/shell_content_browser_client.h
+++ b/content/shell/browser/shell_content_browser_client.h
@@ -128,8 +128,6 @@
   void GetHyphenationDictionary(
       base::OnceCallback<void(const base::FilePath&)>) override;
   bool HasErrorPage(int http_status_code) override;
-  std::unique_ptr<IdentityRequestDialogController>
-  CreateIdentityRequestDialogController() override;
   void OnNetworkServiceCreated(
       network::mojom::NetworkService* network_service) override;
 
diff --git a/content/shell/browser/shell_identity_dialog_controller.cc b/content/shell/browser/shell_identity_dialog_controller.cc
deleted file mode 100644
index 2727183..0000000
--- a/content/shell/browser/shell_identity_dialog_controller.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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 "content/shell/browser/shell_identity_dialog_controller.h"
-
-namespace content {
-
-void ShellIdentityDialogController::ShowAccountsDialog(
-    content::WebContents* rp_web_contents,
-    const GURL& idp_signin_url,
-    base::span<const IdentityRequestAccount> accounts,
-    const IdentityProviderMetadata& idp_metadata,
-    const ClientIdData& client_id_data,
-    IdentityRequestAccount::SignInMode sign_in_mode,
-    AccountSelectionCallback on_selected) {
-  // Similar in spirit to allowlisted permissions in ShellPermissionManager,
-  // we automatically select the first account here so that tests can pass.
-  DCHECK_GT(accounts.size(), 0ul);
-  std::move(on_selected).Run(accounts[0].id, /* is_sign_in= */ false);
-}
-
-}  // namespace content
diff --git a/content/shell/browser/shell_identity_dialog_controller.h b/content/shell/browser/shell_identity_dialog_controller.h
deleted file mode 100644
index b7eec9c..0000000
--- a/content/shell/browser/shell_identity_dialog_controller.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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 CONTENT_SHELL_BROWSER_SHELL_IDENTITY_DIALOG_CONTROLLER_H_
-#define CONTENT_SHELL_BROWSER_SHELL_IDENTITY_DIALOG_CONTROLLER_H_
-
-#include "content/public/browser/identity_request_dialog_controller.h"
-
-namespace content {
-
-class ShellIdentityDialogController : public IdentityRequestDialogController {
- public:
-  void ShowAccountsDialog(content::WebContents* rp_web_contents,
-                          const GURL& idp_signin_url,
-                          base::span<const IdentityRequestAccount> accounts,
-                          const IdentityProviderMetadata& idp_metadata,
-                          const ClientIdData& client_id_data,
-                          IdentityRequestAccount::SignInMode sign_in_mode,
-                          AccountSelectionCallback on_selected) override;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_BROWSER_SHELL_IDENTITY_DIALOG_CONTROLLER_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index bfaafcd..5325219 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1357,8 +1357,6 @@
     "../browser/web_package/web_bundle_file_browsertest.cc",
     "../browser/web_package/web_bundle_network_browsertest.cc",
     "../browser/web_package/web_bundle_trustable_file_browsertest.cc",
-    "../browser/webid/test/fake_identity_request_dialog_controller.cc",
-    "../browser/webid/test/fake_identity_request_dialog_controller.h",
     "../browser/webid/test/webid_test_content_browser_client.cc",
     "../browser/webid/test/webid_test_content_browser_client.h",
     "../browser/webid/webid_browsertest.cc",
@@ -2333,8 +2331,6 @@
     "../browser/web_package/web_bundle_utils_unittest.cc",
     "../browser/webid/federated_auth_request_impl_unittest.cc",
     "../browser/webid/idp_network_request_manager_unittest.cc",
-    "../browser/webid/test/fake_identity_request_dialog_controller.cc",
-    "../browser/webid/test/fake_identity_request_dialog_controller.h",
     "../browser/webid/test/mock_active_session_permission_delegate.cc",
     "../browser/webid/test/mock_active_session_permission_delegate.h",
     "../browser/webid/test/mock_api_permission_delegate.cc",
diff --git a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
index 4650b335..87eaee0 100644
--- a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
@@ -128,6 +128,9 @@
 # Flaky Vulkan Loader Timeout
 crbug.com/1275738 [ linux angle-swiftshader ] GpuProcess_disable_gpu [ RetryOnFailure ]
 
+# Flakey on Lacros FYI bot
+crbug.com/1311719 [ linux display-server-wayland ] GpuProcess_disabling_workarounds_works [ RetryOnFailure ]
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/content/web_test/browser/web_test_browser_main_runner.cc b/content/web_test/browser/web_test_browser_main_runner.cc
index 107cd00..823bfa0 100644
--- a/content/web_test/browser/web_test_browser_main_runner.cc
+++ b/content/web_test/browser/web_test_browser_main_runner.cc
@@ -211,6 +211,9 @@
   command_line.AppendSwitch(switches::kUseFakeUIForMediaStream);
   command_line.AppendSwitch(switches::kUseFakeDeviceForMediaStream);
 
+  // Always run with fake FedCM UI.
+  command_line.AppendSwitch(switches::kUseFakeUIForFedCM);
+
   // Enable the deprecated WebAuthn Mojo Testing API.
   command_line.AppendSwitch(switches::kEnableWebAuthDeprecatedMojoTestingApi);
 
diff --git a/device/BUILD.gn b/device/BUILD.gn
index 40439fa6..b729ba1 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -237,7 +237,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [
       "bluetooth/bluetooth_low_energy_scan_filter_unittest.cc",
       "bluetooth/chromeos/bluetooth_connection_logger_unittest.cc",
@@ -275,7 +275,7 @@
       "//dbus:test_support",
     ]
 
-    if (is_chromeos_ash || is_chromeos_lacros) {
+    if (is_chromeos) {
       sources += [
         "bluetooth/dbus/bluetooth_advertisement_monitor_application_service_provider_unittest.cc",
         "bluetooth/dbus/bluetooth_advertisement_monitor_service_provider_unittest.cc",
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index 6439731..f1c5a48 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -8,7 +8,7 @@
 if (is_android) {
   import("//build/config/android/rules.gni")  # For generate_jni().
 }
-if (is_chromeos_ash || is_chromeos_lacros) {
+if (is_chromeos) {
   import("//chromeos/dbus/config/use_real_dbus_clients.gni")
 } else if (use_bluez) {
   use_real_dbus_clients = false
@@ -200,7 +200,7 @@
     deps += [ ":jni_headers" ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     deps += [ "//chromeos/constants" ]
   }
 
@@ -450,7 +450,7 @@
         "floss/floss_manager_client.cc",
         "floss/floss_manager_client.h",
       ]
-      if (is_chromeos_ash || is_chromeos_lacros) {
+      if (is_chromeos) {
         configs += [ "//chromeos/dbus/config:use_real_dbus_clients_config" ]
         sources += [
           "chromeos/bluetooth_connection_logger.cc",
@@ -581,7 +581,7 @@
     "test/mock_bluetooth_socket.h",
   ]
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [
       "test/mock_bluetooth_low_energy_scan_session.cc",
       "test/mock_bluetooth_low_energy_scan_session.h",
diff --git a/device/fido/cable/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc
index 8c9e18af..8ad291b 100644
--- a/device/fido/cable/fido_cable_discovery.cc
+++ b/device/fido/cable/fido_cable_discovery.cc
@@ -30,6 +30,10 @@
 #include "device/fido/features.h"
 #include "device/fido/fido_parsing_utils.h"
 
+#if BUILDFLAG(IS_MAC)
+#include "device/fido/mac/util.h"
+#endif
+
 namespace device {
 
 namespace {
@@ -268,6 +272,17 @@
     OnSetPowered();
   }
 
+#if BUILDFLAG(IS_MAC)
+  if (fido::mac::ProcessIsSigned()) {
+    FIDO_LOG(DEBUG) << "Bluetooth authorized: "
+                    << (adapter_->GetOsPermissionStatus() !=
+                        BluetoothAdapter::PermissionStatus::kDenied);
+  } else {
+    FIDO_LOG(DEBUG)
+        << "Build not signed. Assuming Bluetooth permission is granted.";
+  }
+#endif
+
   // FidoCableDiscovery blocks its transport availability callback on the
   // DiscoveryStarted() calls of all instantiated discoveries. Hence, this call
   // must not be put behind the BLE adapter getting powered on (which is
diff --git a/device/fido/mac/util.h b/device/fido/mac/util.h
index 2853e7f..38a899e1 100644
--- a/device/fido/mac/util.h
+++ b/device/fido/mac/util.h
@@ -58,6 +58,9 @@
 std::unique_ptr<PublicKey> SecKeyRefToECPublicKey(SecKeyRef public_key_ref)
     API_AVAILABLE(macosx(10.12.2));
 
+// ProcessIsSigned returns true if the current process has been code signed.
+bool ProcessIsSigned();
+
 }  // namespace mac
 }  // namespace fido
 }  // namespace device
diff --git a/device/fido/mac/util.mm b/device/fido/mac/util.mm
index 9c847aa..e7df480e 100644
--- a/device/fido/mac/util.mm
+++ b/device/fido/mac/util.mm
@@ -152,6 +152,17 @@
   return key;
 }
 
+bool ProcessIsSigned() {
+  base::ScopedCFTypeRef<SecTaskRef> task(SecTaskCreateFromSelf(nullptr));
+  if (!task) {
+    return false;
+  }
+
+  base::ScopedCFTypeRef<CFStringRef> sign_id(
+      SecTaskCopySigningIdentifier(task.get(), /* error= */ nullptr));
+  return static_cast<bool>(sign_id);
+}
+
 }  // namespace mac
 }  // namespace fido
 }  // namespace device
diff --git a/device/gamepad/BUILD.gn b/device/gamepad/BUILD.gn
index 3d0c239a..7d29de20 100644
--- a/device/gamepad/BUILD.gn
+++ b/device/gamepad/BUILD.gn
@@ -156,7 +156,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     deps += [ "//chromeos/dbus/permission_broker" ]
   }
 }
diff --git a/docs/updater/functional_spec.md b/docs/updater/functional_spec.md
index 0cb45a8..1d68c085 100644
--- a/docs/updater/functional_spec.md
+++ b/docs/updater/functional_spec.md
@@ -166,3 +166,11 @@
 The updater will not delete this file.
 * This installerdata is not persisted anywhere else, and it is not sent as a
 part of pings to the update server.
+
+## Telemetry
+When the updater installs an application (an installer is run) it will send an
+event with `"eventtype": 2` indicating the outcome of installation. The updater
+does not send such a ping for its own installation.
+
+When the updater updates an application (including itself) it will send an
+event with `"eventtype": 3` indicating the outcome of update operation.
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index fff8a6d..efe4f2db 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -367,6 +367,8 @@
     "external_install_info.cc",
     "external_install_info.h",
     "external_provider_interface.h",
+    "favicon_util.cc",
+    "favicon_util.h",
     "file_highlighter.cc",
     "file_highlighter.h",
     "file_reader.cc",
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc
index 388b72b0..6ab1842 100644
--- a/extensions/browser/extension_protocols.cc
+++ b/extensions/browser/extension_protocols.cc
@@ -59,6 +59,7 @@
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/extension_util.h"
 #include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/favicon_util.h"
 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
 #include "extensions/browser/info_map.h"
@@ -66,6 +67,7 @@
 #include "extensions/browser/process_map_factory.h"
 #include "extensions/browser/url_request_util.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_features.h"
 #include "extensions/common/extension_resource.h"
 #include "extensions/common/file_util.h"
 #include "extensions/common/identifiability_metrics.h"
@@ -399,10 +401,19 @@
       (extension.creation_flags() & Extension::FOLLOW_SYMLINKS_ANYWHERE) != 0;
 }
 
-bool IsBackgroundPageURL(const GURL& url) {
+bool IsPathEqualTo(const GURL& url, const char* test) {
   base::StringPiece path_piece = url.path_piece();
-  return path_piece.size() > 1 &&
-         path_piece.substr(1) == kGeneratedBackgroundPageFilename;
+  return path_piece.size() > 1 && path_piece.substr(1) == test;
+}
+
+bool IsFaviconURL(const GURL& url) {
+  return IsPathEqualTo(url, kFaviconSourcePath) &&
+         base::FeatureList::IsEnabled(
+             extensions_features::kNewExtensionFaviconHandling);
+}
+
+bool IsBackgroundPageURL(const GURL& url) {
+  return IsPathEqualTo(url, kGeneratedBackgroundPageFilename);
 }
 
 scoped_refptr<net::HttpResponseHeaders> BuildHttpHeaders(
@@ -742,8 +753,10 @@
       }
     }
 
-    if (IsBackgroundPageURL(request.url)) {
-      // Handle background page requests immediately with a simple generated
+    const bool is_background_page_url = IsBackgroundPageURL(request.url);
+    const bool is_favicon_url = IsFaviconURL(request.url);
+    if (is_background_page_url || is_favicon_url) {
+      // Handle specific page requests immediately with a simple generated
       // chunk of HTML.
 
       // Leave cache headers out of generated background page jobs.
@@ -753,8 +766,13 @@
           cross_origin_opener_policy, false /* send_cors_headers */,
           include_allow_service_worker_header);
       std::string contents;
-      GenerateBackgroundPageContents(extension.get(), &head->mime_type,
-                                     &head->charset, &contents);
+      if (is_background_page_url) {
+        GenerateBackgroundPageContents(extension.get(), &head->mime_type,
+                                       &head->charset, &contents);
+      } else if (is_favicon_url) {
+        favicon_util::GetFaviconForExtensionRequest(
+            extension.get(), &head->mime_type, &head->charset, &contents);
+      }
 
       mojo::Remote<network::mojom::URLLoaderClient> client_remote(
           std::move(client));
diff --git a/extensions/browser/favicon_util.cc b/extensions/browser/favicon_util.cc
new file mode 100644
index 0000000..dc088cf
--- /dev/null
+++ b/extensions/browser/favicon_util.cc
@@ -0,0 +1,20 @@
+// 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 "extensions/browser/favicon_util.h"
+
+namespace extensions::favicon_util {
+
+void GetFaviconForExtensionRequest(const Extension* extension,
+                                   std::string* mime_type,
+                                   std::string* charset,
+                                   std::string* data) {
+  // TODO(solomonkinard): Check extension permission.
+  *mime_type = "text/plain";
+  *charset = "utf-8";
+  *data = "Favicon";
+  // TODO(solomonkinard): Return actual favicon.
+}
+
+}  // namespace extensions::favicon_util
diff --git a/extensions/browser/favicon_util.h b/extensions/browser/favicon_util.h
new file mode 100644
index 0000000..8a137ff
--- /dev/null
+++ b/extensions/browser/favicon_util.h
@@ -0,0 +1,24 @@
+// 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 EXTENSIONS_BROWSER_FAVICON_UTIL_H_
+#define EXTENSIONS_BROWSER_FAVICON_UTIL_H_
+
+#include <string>
+
+namespace extensions {
+
+class Extension;
+
+namespace favicon_util {
+
+void GetFaviconForExtensionRequest(const Extension* extension,
+                                   std::string* mime_type,
+                                   std::string* charset,
+                                   std::string* data);
+
+}  // namespace favicon_util
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_FAVICON_UTIL_H_
diff --git a/extensions/browser/updater/update_service_unittest.cc b/extensions/browser/updater/update_service_unittest.cc
index 86c9a503..91619e4 100644
--- a/extensions/browser/updater/update_service_unittest.cc
+++ b/extensions/browser/updater/update_service_unittest.cc
@@ -120,8 +120,6 @@
     uninstall_pings_.emplace_back(crx_component.app_id, crx_component.version,
                                   reason);
   }
-  void SendRegistrationPing(const update_client::CrxComponent& crx_component,
-                            update_client::Callback Callback) override {}
 
   void FireEvent(Observer::Events event, const std::string& extension_id) {
     for (Observer* observer : observers_)
diff --git a/extensions/common/constants.cc b/extensions/common/constants.cc
index 7a36a04..59d9e0a 100644
--- a/extensions/common/constants.cc
+++ b/extensions/common/constants.cc
@@ -43,6 +43,8 @@
 const char kGeneratedBackgroundPageFilename[] =
     "_generated_background_page.html";
 
+const char kFaviconSourcePath[] = "_favicon/";
+
 const char kModulesDir[] = "_modules";
 
 const base::FilePath::CharType kExtensionFileExtension[] =
diff --git a/extensions/common/constants.h b/extensions/common/constants.h
index 2103c23..2232082 100644
--- a/extensions/common/constants.h
+++ b/extensions/common/constants.h
@@ -68,6 +68,9 @@
 // background.scripts.
 EXTENSIONS_EXPORT extern const char kGeneratedBackgroundPageFilename[];
 
+// The URL piece between the extension ID and favicon URL.
+EXTENSIONS_EXPORT extern const char kFaviconSourcePath[];
+
 // Path to imported modules.
 EXTENSIONS_EXPORT extern const char kModulesDir[];
 
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc
index 92ea1e59..2a15fa1 100644
--- a/extensions/common/extension_features.cc
+++ b/extensions/common/extension_features.cc
@@ -86,4 +86,8 @@
     "EMF_NO_EXTENSION_ID_FOR_EXTENSION_SOURCE",
     base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Controls whether extensions can use the new favicon fetching in Manifest V3.
+const base::Feature kNewExtensionFaviconHandling{
+    "ExtensionsNewFaviconHandling", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace extensions_features
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h
index 89dbc22..d20cd1f6e 100644
--- a/extensions/common/extension_features.h
+++ b/extensions/common/extension_features.h
@@ -33,6 +33,8 @@
 extern const base::Feature kCheckingUnexpectedExtensionIdInContentScriptIpcs;
 extern const base::Feature kCheckingNoExtensionIdInExtensionIpcs;
 
+extern const base::Feature kNewExtensionFaviconHandling;
+
 }  // namespace extensions_features
 
 #endif  // EXTENSIONS_COMMON_EXTENSION_FEATURES_H_
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn
index 583dfdc8..5de4863 100644
--- a/extensions/shell/BUILD.gn
+++ b/extensions/shell/BUILD.gn
@@ -218,7 +218,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     deps += [ "//chromeos/dbus/constants" ]
   }
 
@@ -262,9 +262,7 @@
     # TODO(https://crbug.com/1299021): Implement building these NaCl targets
     # as ARM32 when Chrome is built for ARM64 (for Linux/Chrome OS).
     if (target_cpu != "arm64") {
-      deps += [
-        "//components/nacl/loader",
-      ]
+      deps += [ "//components/nacl/loader" ]
       if (is_linux || is_chromeos) {
         deps += [ "//components/nacl/loader:nacl_helper" ]
       }
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index da1227e..10533fe 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -1011,19 +1011,6 @@
   configs += [ ":headless_defines_config" ]
 }
 
-if (is_fuchsia) {
-  cr_fuchsia_package("headless_shell_pkg") {
-    binary = ":headless_shell"
-    package_name = "headless_shell"
-    manifest = "//build/config/fuchsia/test/minimum_capabilities.test-cmx"
-  }
-
-  fuchsia_package_installer("headless_shell_fuchsia") {
-    package = ":headless_shell_pkg"
-    package_name = "headless_shell"
-  }
-}
-
 executable("headless_shell") {
   sources = [ "app/headless_shell_main.cc" ]
   defines = []
diff --git a/headless/OWNERS b/headless/OWNERS
index 6c07907d..86ed88d2 100644
--- a/headless/OWNERS
+++ b/headless/OWNERS
@@ -11,3 +11,6 @@
 # Emeritus:
 altimin@chromium.org
 dvallet@chromium.org
+
+per-file *.cmx=set noparent
+per-file *.cmx=file://fuchsia/SECURITY_OWNERS
\ No newline at end of file
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 2cb2571d..66e34a6 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -5691,11 +5691,11 @@
       name: "Deterministic Android (dbg)"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
-      dimensions: "cores:8"
+      dimensions: "cores:16"
       dimensions: "cpu:x86-64"
       dimensions: "os:Ubuntu-18.04"
       dimensions: "pool:luci.chromium.ci"
-      dimensions: "ssd:0"
+      dimensions: "ssd:1"
       exe {
         cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
         cipd_version: "refs/heads/main"
diff --git a/infra/config/subprojects/chromium/ci/chromium.android.star b/infra/config/subprojects/chromium/ci/chromium.android.star
index 4eb7b35..e597683 100644
--- a/infra/config/subprojects/chromium/ci/chromium.android.star
+++ b/infra/config/subprojects/chromium/ci/chromium.android.star
@@ -192,6 +192,7 @@
         category = "builder|det",
         short_name = "dbg",
     ),
+    cores = 16,
     executable = "recipe:swarming/deterministic_build",
     execution_timeout = 6 * time.hour,
     notifies = ["Deterministic Android"],
@@ -199,6 +200,7 @@
     goma_backend = None,
     reclient_jobs = rbe_jobs.DEFAULT,
     reclient_instance = rbe_instance.DEFAULT,
+    ssd = True,
 )
 
 ci.builder(
diff --git a/ios/chrome/browser/safe_browsing/BUILD.gn b/ios/chrome/browser/safe_browsing/BUILD.gn
index 76fd37f..db3023f 100644
--- a/ios/chrome/browser/safe_browsing/BUILD.gn
+++ b/ios/chrome/browser/safe_browsing/BUILD.gn
@@ -30,8 +30,6 @@
     "safe_browsing_service_impl.mm",
     "safe_browsing_tab_helper.h",
     "safe_browsing_tab_helper.mm",
-    "safe_browsing_unsafe_resource_container.h",
-    "safe_browsing_unsafe_resource_container.mm",
     "url_checker_delegate_impl.h",
     "url_checker_delegate_impl.mm",
     "user_population_helper.h",
@@ -183,7 +181,6 @@
     "safe_browsing_query_manager_unittest.mm",
     "safe_browsing_service_unittest.mm",
     "safe_browsing_tab_helper_unittest.mm",
-    "safe_browsing_unsafe_resource_container_unittest.mm",
     "url_checker_delegate_impl_unittest.mm",
     "verdict_cache_manager_factory_unittest.mm",
   ]
@@ -229,6 +226,7 @@
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/web:test_support",
     "//ios/chrome/test:test_support",
+    "//ios/components/security_interstitials/safe_browsing",
     "//ios/web/public",
     "//ios/web/public/test",
     "//net:test_support",
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_service_unittest.mm b/ios/chrome/browser/safe_browsing/safe_browsing_service_unittest.mm
index 9ec1269..904b076 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_service_unittest.mm
+++ b/ios/chrome/browser/safe_browsing/safe_browsing_service_unittest.mm
@@ -32,9 +32,9 @@
 #import "ios/chrome/browser/prerender/prerender_service_factory.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_metrics_collector_factory.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_query_manager.h"
-#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/chrome/browser/safe_browsing/verdict_cache_manager_factory.h"
 #import "ios/chrome/test/testing_application_context.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/web/public/test/fakes/fake_web_state.h"
 #include "ios/web/public/test/web_task_environment.h"
 #include "ios/web/public/thread/web_task_traits.h"
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm
index 0ff9bae..ff05a2b 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm
+++ b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.mm
@@ -21,7 +21,7 @@
 #import "ios/chrome/browser/prerender/prerender_service_factory.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_error.h"
 #include "ios/chrome/browser/safe_browsing/safe_browsing_service.h"
-#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/web/public/navigation/navigation_context.h"
 #import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/navigation/navigation_manager.h"
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm
index 30e16fa..f110000 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm
+++ b/ios/chrome/browser/safe_browsing/safe_browsing_tab_helper_unittest.mm
@@ -15,7 +15,7 @@
 #import "ios/chrome/browser/safe_browsing/fake_safe_browsing_service.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_error.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_query_manager.h"
-#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/test/fakes/fake_navigation_context.h"
 #import "ios/web/public/test/fakes/fake_navigation_manager.h"
diff --git a/ios/chrome/browser/safe_browsing/url_checker_delegate_impl_unittest.mm b/ios/chrome/browser/safe_browsing/url_checker_delegate_impl_unittest.mm
index 3760041..efb3f05 100644
--- a/ios/chrome/browser/safe_browsing/url_checker_delegate_impl_unittest.mm
+++ b/ios/chrome/browser/safe_browsing/url_checker_delegate_impl_unittest.mm
@@ -15,7 +15,7 @@
 #import "ios/chrome/browser/prerender/fake_prerender_service.h"
 #import "ios/chrome/browser/prerender/prerender_service_factory.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_query_manager.h"
-#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/web/public/navigation/navigation_item.h"
 #import "ios/web/public/test/fakes/fake_navigation_manager.h"
 #import "ios/web/public/test/fakes/fake_web_state.h"
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn
index 10dab59..2a92ae11 100644
--- a/ios/chrome/browser/tabs/BUILD.gn
+++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -109,6 +109,7 @@
     "//ios/chrome/browser/webui",
     "//ios/components/security_interstitials",
     "//ios/components/security_interstitials/lookalikes",
+    "//ios/components/security_interstitials/safe_browsing",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/text_zoom:text_zoom_api",
     "//ios/web/common:features",
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm
index 83ab66a5..642c0ea9 100644
--- a/ios/chrome/browser/tabs/tab_helper_util.mm
+++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -62,7 +62,6 @@
 #import "ios/chrome/browser/reading_list/reading_list_web_state_observer.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_query_manager.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_tab_helper.h"
-#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/chrome/browser/search_engines/search_engine_tab_helper.h"
 #import "ios/chrome/browser/sessions/ios_chrome_session_tab_helper.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
@@ -90,6 +89,7 @@
 #import "ios/components/security_interstitials/lookalikes/lookalike_url_container.h"
 #import "ios/components/security_interstitials/lookalikes/lookalike_url_tab_allow_list.h"
 #import "ios/components/security_interstitials/lookalikes/lookalike_url_tab_helper.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/public/provider/chrome/browser/text_zoom/text_zoom_api.h"
 #include "ios/web/common/features.h"
 #import "ios/web/public/web_state.h"
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
index eb11168..58b5fc2 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller_unittest.mm
@@ -72,6 +72,7 @@
 
 enum PasswordsSections {
   SavePasswordsSwitch = 0,
+  PasswordsInOtherApps,
   PasswordCheck,
   SavedPasswords,
   Blocked,
@@ -125,14 +126,15 @@
   int GetSectionIndex(PasswordsSections section) {
     switch (section) {
       case SavePasswordsSwitch:
+      case PasswordsInOtherApps:
       case PasswordCheck:
         return section;
       case SavedPasswords:
-        return 2;
+        return 3;
       case Blocked:
-        return 3;
+        return 4;
       case ExportPasswordsButton:
-        return 3;
+        return 4;
     }
   }
 
@@ -291,14 +293,14 @@
 // Tests default case has no saved sites and no blocked sites.
 TEST_F(PasswordsTableViewControllerTest, TestInitialization) {
   CheckController();
-  EXPECT_EQ(2 + SectionsOffset(), NumberOfSections());
+  EXPECT_EQ(3 + SectionsOffset(), NumberOfSections());
 }
 
 // Tests adding one item in saved password section.
 TEST_F(PasswordsTableViewControllerTest, AddSavedPasswords) {
   AddSavedForm1();
 
-  EXPECT_EQ(3 + SectionsOffset(), NumberOfSections());
+  EXPECT_EQ(4 + SectionsOffset(), NumberOfSections());
   EXPECT_EQ(1, NumberOfItemsInSection(GetSectionIndex(SavedPasswords)));
 }
 
@@ -306,7 +308,7 @@
 TEST_F(PasswordsTableViewControllerTest, AddBlockedPasswords) {
   AddBlockedForm1();
 
-  EXPECT_EQ(3 + SectionsOffset(), NumberOfSections());
+  EXPECT_EQ(4 + SectionsOffset(), NumberOfSections());
   EXPECT_EQ(1, NumberOfItemsInSection(GetSectionIndex(Blocked)));
 }
 
@@ -318,7 +320,7 @@
   AddBlockedForm2();
 
   // There should be two sections added.
-  EXPECT_EQ(4 + SectionsOffset(), NumberOfSections());
+  EXPECT_EQ(5 + SectionsOffset(), NumberOfSections());
 
   // There should be 1 row in saved password section.
   EXPECT_EQ(1, NumberOfItemsInSection(GetSectionIndex(SavedPasswords)));
@@ -392,7 +394,7 @@
   AddSavedForm1();
   AddSavedForm1();
 
-  EXPECT_EQ(3 + SectionsOffset(), NumberOfSections());
+  EXPECT_EQ(4 + SectionsOffset(), NumberOfSections());
   EXPECT_EQ(1, NumberOfItemsInSection(GetSectionIndex(SavedPasswords)));
 }
 
@@ -402,7 +404,7 @@
   AddBlockedForm1();
   AddBlockedForm1();
 
-  EXPECT_EQ(3 + SectionsOffset(), NumberOfSections());
+  EXPECT_EQ(4 + SectionsOffset(), NumberOfSections());
   EXPECT_EQ(1, NumberOfItemsInSection(GetSectionIndex(SavedPasswords)));
 }
 
@@ -411,11 +413,11 @@
   AddSavedForm1();
   AddBlockedForm1();
   AddBlockedForm2();
-  ASSERT_EQ(5, NumberOfSections());
+  ASSERT_EQ(6, NumberOfSections());
 
   // Delete item in save passwords section.
   deleteItemAndWait(GetSectionIndex(SavedPasswords), 0);
-  EXPECT_EQ(4, NumberOfSections());
+  EXPECT_EQ(5, NumberOfSections());
 
   // Section 2 should now be the blocked passwords section, and should still
   // have both its items.
@@ -427,7 +429,7 @@
 
   // There should be no password sections remaining and no search bar.
   deleteItemAndWait(GetSectionIndex(SavedPasswords), 0);
-  EXPECT_EQ(3, NumberOfSections());
+  EXPECT_EQ(4, NumberOfSections());
 }
 
 // Tests deleting items from saved passwords and blocked passwords sections
@@ -438,11 +440,11 @@
   AddBlockedForm1();
   AddBlockedForm1();
   AddBlockedForm2();
-  ASSERT_EQ(5, NumberOfSections());
+  ASSERT_EQ(6, NumberOfSections());
 
   // Delete item in save passwords section.
   deleteItemAndWait(GetSectionIndex(SavedPasswords), 0);
-  EXPECT_EQ(4, NumberOfSections());
+  EXPECT_EQ(5, NumberOfSections());
 
   // Section 2 should now be the blocked passwords section, and should still
   // have both its items.
@@ -454,7 +456,7 @@
 
   // There should be no password sections remaining and no search bar.
   deleteItemAndWait(GetSectionIndex(Blocked) - 1, 0);
-  EXPECT_EQ(3, NumberOfSections());
+  EXPECT_EQ(4, NumberOfSections());
 }
 
 TEST_F(PasswordsTableViewControllerTest,
@@ -572,7 +574,7 @@
   AddBlockedForm1();
   AddBlockedForm2();
 
-  EXPECT_EQ(4 + SectionsOffset(), NumberOfSections());
+  EXPECT_EQ(5 + SectionsOffset(), NumberOfSections());
 
   PasswordsTableViewController* passwords_controller =
       static_cast<PasswordsTableViewController*>(controller());
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc
index 697f8863..c7ca83f 100644
--- a/ios/chrome/browser/ui/ui_feature_flags.cc
+++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -56,7 +56,7 @@
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kCredentialProviderExtensionPromo{
-    "CredentialProviderExtensionPromo", base::FEATURE_DISABLED_BY_DEFAULT};
+    "CredentialProviderExtensionPromo", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kRemoveExcessNTPs{"RemoveExcessNTPs",
                                       base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index ef9a6f7..3eaa7f1f 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -260,6 +260,7 @@
     "//ios/chrome/browser/web/web_performance_metrics",
     "//ios/components/security_interstitials",
     "//ios/components/security_interstitials/lookalikes",
+    "//ios/components/security_interstitials/safe_browsing",
     "//ios/components/webui:url_constants",
     "//ios/net",
     "//ios/public/provider/chrome/browser/url_rewriters:url_rewriters_api",
@@ -335,6 +336,7 @@
     "//ios/chrome/test/fakes",
     "//ios/components/security_interstitials",
     "//ios/components/security_interstitials/lookalikes",
+    "//ios/components/security_interstitials/safe_browsing",
     "//ios/net",
     "//ios/web/common:features",
     "//ios/web/common:web_view_creation_util",
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm
index c141aba..4ac44f5 100644
--- a/ios/chrome/browser/web/chrome_web_client.mm
+++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -42,7 +42,6 @@
 #import "ios/chrome/browser/safe_browsing/password_protection_java_script_feature.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_error.h"
-#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/chrome/browser/search_engines/search_engine_java_script_feature.h"
 #import "ios/chrome/browser/search_engines/search_engine_tab_helper_factory.h"
 #include "ios/chrome/browser/ssl/ios_ssl_error_handler.h"
@@ -65,6 +64,7 @@
 #import "ios/components/security_interstitials/lookalikes/lookalike_url_container.h"
 #import "ios/components/security_interstitials/lookalikes/lookalike_url_controller_client.h"
 #import "ios/components/security_interstitials/lookalikes/lookalike_url_error.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #include "ios/components/webui/web_ui_url_constants.h"
 #import "ios/net/protocol_handler_util.h"
 #include "ios/public/provider/chrome/browser/url_rewriters/url_rewriters_api.h"
diff --git a/ios/chrome/browser/web/chrome_web_client_unittest.mm b/ios/chrome/browser/web/chrome_web_client_unittest.mm
index 568fda6e..e414ee6 100644
--- a/ios/chrome/browser/web/chrome_web_client_unittest.mm
+++ b/ios/chrome/browser/web/chrome_web_client_unittest.mm
@@ -25,7 +25,6 @@
 #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
 #import "ios/chrome/browser/safe_browsing/safe_browsing_error.h"
-#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/chrome/browser/ssl/captive_portal_tab_helper.h"
 #import "ios/chrome/browser/ssl/captive_portal_tab_helper_delegate.h"
 #include "ios/chrome/browser/web/error_page_controller_bridge.h"
@@ -34,6 +33,7 @@
 #import "ios/components/security_interstitials/ios_blocking_page_tab_helper.h"
 #import "ios/components/security_interstitials/lookalikes/lookalike_url_container.h"
 #import "ios/components/security_interstitials/lookalikes/lookalike_url_error.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 #import "ios/net/protocol_handler_util.h"
 #include "ios/web/common/features.h"
 #import "ios/web/common/web_view_creation_util.h"
diff --git a/ios/components/security_interstitials/DEPS b/ios/components/security_interstitials/DEPS
index 0dea5c6..39d3c7b 100644
--- a/ios/components/security_interstitials/DEPS
+++ b/ios/components/security_interstitials/DEPS
@@ -5,5 +5,6 @@
   "+ios/components/ui_util",
   "+ios/web/common",
   "+ios/web/public",
+  "+services/network/public/mojom",
   "+ui/base",
 ]
diff --git a/ios/components/security_interstitials/safe_browsing/BUILD.gn b/ios/components/security_interstitials/safe_browsing/BUILD.gn
index ddd81b1..2af48b3 100644
--- a/ios/components/security_interstitials/safe_browsing/BUILD.gn
+++ b/ios/components/security_interstitials/safe_browsing/BUILD.gn
@@ -8,6 +8,8 @@
   sources = [
     "pending_unsafe_resource_storage.h",
     "pending_unsafe_resource_storage.mm",
+    "safe_browsing_unsafe_resource_container.h",
+    "safe_browsing_unsafe_resource_container.mm",
   ]
 
   deps = [
@@ -16,6 +18,7 @@
     "//components/safe_browsing/ios/browser/password_protection",
     "//components/security_interstitials/core:unsafe_resource",
     "//ios/components/security_interstitials/safe_browsing:util",
+    "//ios/web/public",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
@@ -41,12 +44,16 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [ "pending_unsafe_resource_storage_unittest.mm" ]
+  sources = [
+    "pending_unsafe_resource_storage_unittest.mm",
+    "safe_browsing_unsafe_resource_container_unittest.mm",
+  ]
 
   deps = [
     ":safe_browsing",
     "//base",
     "//base/test:test_support",
+    "//components/safe_browsing/ios/browser:allow_list",
     "//ios/web/public",
     "//ios/web/public/test",
     "//testing/gmock",
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h b/ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h
similarity index 88%
rename from ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h
rename to ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h
index 1b68c0e..8e3c755 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h
+++ b/ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.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 IOS_CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_UNSAFE_RESOURCE_CONTAINER_H_
-#define IOS_CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_UNSAFE_RESOURCE_CONTAINER_H_
+#ifndef IOS_COMPONENTS_SECURITY_INTERSTITIALS_SAFE_BROWSING_SAFE_BROWSING_UNSAFE_RESOURCE_CONTAINER_H_
+#define IOS_COMPONENTS_SECURITY_INTERSTITIALS_SAFE_BROWSING_SAFE_BROWSING_UNSAFE_RESOURCE_CONTAINER_H_
 
 #include "components/security_interstitials/core/unsafe_resource.h"
 #import "ios/components/security_interstitials/safe_browsing/pending_unsafe_resource_storage.h"
@@ -57,4 +57,4 @@
   PendingUnsafeResourceStorage main_frame_unsafe_resource_;
 };
 
-#endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_UNSAFE_RESOURCE_CONTAINER_H_
+#endif  // IOS_COMPONENTS_SECURITY_INTERSTITIALS_SAFE_BROWSING_SAFE_BROWSING_UNSAFE_RESOURCE_CONTAINER_H_
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.mm b/ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.mm
similarity index 97%
rename from ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.mm
rename to ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.mm
index ce32704..a9749db 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.mm
+++ b/ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 
 #include <list>
 
diff --git a/ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container_unittest.mm b/ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container_unittest.mm
similarity index 97%
rename from ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container_unittest.mm
rename to ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container_unittest.mm
index 896b3a3..e708f90 100644
--- a/ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container_unittest.mm
+++ b/ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
+#import "ios/components/security_interstitials/safe_browsing/safe_browsing_unsafe_resource_container.h"
 
 #include "base/bind.h"
 #import "components/safe_browsing/ios/browser/safe_browsing_url_allow_list.h"
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 9c39b3172..2fd61be 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-687b4ddef433142831b67dd9891a33f70014ac4d
\ No newline at end of file
+58a80dc11cd01dbb9510161c4a34c114029b9b09
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index a6bab254..2cfbc45 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-78104e9c828d5415db44355ba8d1bc9b2bbedee8
\ No newline at end of file
+3c57ee3358a542eae8c22cbee0d4a512a2554cb0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index dc750204..a87b3cc4 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-b78c9aac3cbfecaf31ec089c819152ea6dfdd679
\ No newline at end of file
+436af7c9cc15fb08d12483643530b139c426d83f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index a443db0..8b67be4 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-b1821814e53f9e2c28ce6c334e1971183078af0b
\ No newline at end of file
+883e4f3903b305f89c269cab22cd7a4198960ff9
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
index ee0c8797..72a3238 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-cae92f512387c52d2a00b64391da4e8e691da05d
\ No newline at end of file
+65096249749c1476c816a619fac61a8eb7ced539
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
index 3307259..f46b912 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-42a879d3adc8ffaeb35cb81e1ae7b4553f50705e
\ No newline at end of file
+5d80b7de1bfc3973a24e2d4332c7351e70d3b3d2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index c86c14a..b40fbef 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-654060000942b2fed9f31ebe0c450517a1503f5b
\ No newline at end of file
+f90224d126bcbef5cda996cfaa635c804acfada5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 6c252c4..eb9e11d 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-aede1e45e95eead68ae62c89488dcdbbff7fe8f5
\ No newline at end of file
+12c5f52299aeea38df16d9c536d6f056381ec017
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 13dd0ba..f138bf0 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-394831cc4a43758cdb1e66bd94492dc01ad5b67e
\ No newline at end of file
+c563d472fbed23c3428aa4b173f4c1c3377aada4
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 6d51e136..9136cf26 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-b0ac2e7fb36a0339e17562c57a526f4e7d51da41
\ No newline at end of file
+38d660e55a45de6bc575f0aba03461cfc07867cc
\ No newline at end of file
diff --git a/ios/web_view/tools/build.py b/ios/web_view/tools/build.py
index b7b3713..65ad123 100755
--- a/ios/web_view/tools/build.py
+++ b/ios/web_view/tools/build.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright 2017 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -54,6 +54,7 @@
   else:
     gn_args.extend([
         'target_cpu="x64"',
+        'additional_target_cpus = [ "arm64" ]',
         'target_environment="simulator"',
     ])
 
@@ -71,7 +72,7 @@
 
   build_dir = os.path.join("out", target_dir_name(build_config, target_device))
   gn_command = 'gn gen %s --args=\'%s\'' % (build_dir, ' '.join(gn_args))
-  print gn_command
+  print(gn_command)
   gn_result = os.system(gn_command)
   if gn_result != 0:
     return gn_result
@@ -81,7 +82,7 @@
     ninja_options += ' %s' % extra_ninja_options
   ninja_command = ('ninja %s ios/web_view:ios_web_view_package' %
                    ninja_options)
-  print ninja_command
+  print(ninja_command)
   return os.system(ninja_command)
 
 def copy_build_products(build_config, target_device, out_dir, output_name):
@@ -100,14 +101,14 @@
   framework_name = '%s.framework' % output_name
   framework_source = os.path.join(build_dir, framework_name)
   framework_dest = os.path.join(out_dir, target_dir, framework_name)
-  print 'Copying %s to %s' % (framework_source, framework_dest)
+  print('Copying %s to %s' % (framework_source, framework_dest))
   shutil.copytree(framework_source, framework_dest)
 
   # Copy symbols.
   symbols_name = '%s.dSYM' % output_name
   symbols_source = os.path.join(build_dir, symbols_name)
   symbols_dest = os.path.join(out_dir, target_dir, symbols_name)
-  print 'Copying %s to %s' % (symbols_source, symbols_dest)
+  print('Copying %s to %s' % (symbols_source, symbols_dest))
   shutil.copytree(symbols_source, symbols_dest)
 
 def package_framework(build_config,
@@ -130,7 +131,7 @@
   Returns:
     The return code of the build if it fails or 0 if the build was successful.
   """
-  print '\nBuilding for %s (%s)' % (target_device, build_config)
+  print('\nBuilding for %s (%s)' % (target_device, build_config))
 
   build_result = build(build_config,
                        target_device,
@@ -138,7 +139,7 @@
                        extra_ninja_options)
   if build_result != 0:
     error = 'Building %s/%s failed with code: ' % (build_config, target_device)
-    print >>sys.stderr, error, build_result
+    print(error, build_result, file=sys.stderr)
     return build_result
   copy_build_products(build_config, target_device, out_dir, output_name)
   return 0
@@ -162,7 +163,7 @@
   Returns:
     0 if all builds are successful or 1 if any build fails.
   """
-  print 'Building ChromeWebView.framework...'
+  print('Building ChromeWebView.framework...')
 
   # Package all builds in the output directory
   os.makedirs(out_dir)
@@ -184,7 +185,7 @@
   shutil.copy2(os.path.join(package_dir, 'LICENSE'), out_dir)
   shutil.copy2(os.path.join(package_dir, 'VERSION'), out_dir)
 
-  print '\nSuccess! ChromeWebView.framework is packaged into %s' % out_dir
+  print('\nSuccess! ChromeWebView.framework is packaged into %s' % out_dir)
 
   return 0
 
@@ -210,7 +211,7 @@
                       help='Specify which devices to target.')
 
   options, extra_options = parser.parse_known_args()
-  print 'Options:', options
+  print('Options:', options)
 
   if len(extra_options):
     print >>sys.stderr, 'Unknown options: ', extra_options
@@ -219,7 +220,7 @@
   out_dir = options.out_dir
   # Make sure that the output directory does not exist
   if os.path.exists(out_dir):
-    print >>sys.stderr, 'The output directory already exists: ' + out_dir
+    print('The output directory already exists: ' + out_dir, file=sys.stderr)
     return 1
 
   output_name = 'ChromeWebView'
diff --git a/media/gpu/chromeos/BUILD.gn b/media/gpu/chromeos/BUILD.gn
index 86f4735f..6ddcef75 100644
--- a/media/gpu/chromeos/BUILD.gn
+++ b/media/gpu/chromeos/BUILD.gn
@@ -97,6 +97,7 @@
     "//media/gpu:command_buffer_helper",
     "//media/gpu:common",
     "//media/gpu:video_frame_mapper_common",
+    "//media/mojo/common:common",
     "//third_party/libyuv",
     "//ui/gfx:buffer_types",
     "//ui/gfx:memory_buffer",
diff --git a/media/gpu/chromeos/oop_video_decoder.cc b/media/gpu/chromeos/oop_video_decoder.cc
index ed93854..8a9c117 100644
--- a/media/gpu/chromeos/oop_video_decoder.cc
+++ b/media/gpu/chromeos/oop_video_decoder.cc
@@ -5,6 +5,7 @@
 #include "media/gpu/chromeos/oop_video_decoder.h"
 
 #include "media/gpu/macros.h"
+#include "media/mojo/common/mojo_decoder_buffer_converter.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
@@ -102,13 +103,27 @@
   remote_decoder_.set_disconnect_handler(
       base::BindOnce(&OOPVideoDecoder::Stop, base::Unretained(this)));
 
+  // TODO(b/195769334): |remote_consumer_handle| corresponds to the data pipe
+  // that allows us to send data to the out-of-process video decoder. This data
+  // pipe is separate from the one set up by renderers to send data to the GPU
+  // process. Therefore, we're introducing the need for copying the encoded data
+  // from one pipe to the other. Ideally, we would just forward the pipe
+  // endpoint directly to the out-of-process video decoder and avoid the extra
+  // copy. This would require us to plumb the mojo::ScopedDataPipeConsumerHandle
+  // from the MojoVideoDecoderService all the way here.
+  mojo::ScopedDataPipeConsumerHandle remote_consumer_handle;
+  mojo_decoder_buffer_writer_ = MojoDecoderBufferWriter::Create(
+      GetDefaultDecoderBufferConverterCapacity(DemuxerStream::VIDEO),
+      &remote_consumer_handle);
+  CHECK(mojo_decoder_buffer_writer_);
+
   CHECK(!has_error_);
   // TODO(b/171813538): plumb the remaining parameters.
   remote_decoder_->Construct(
       client_receiver_.BindNewEndpointAndPassRemote(),
       mojo::PendingRemote<stable::mojom::MediaLog>(),
       mojo::PendingReceiver<stable::mojom::VideoFrameHandleReleaser>(),
-      mojo::ScopedDataPipeConsumerHandle(), gfx::ColorSpace());
+      std::move(remote_consumer_handle), gfx::ColorSpace());
 }
 
 OOPVideoDecoder::~OOPVideoDecoder() {
@@ -210,6 +225,15 @@
 
   const bool is_flushing = buffer->end_of_stream();
 
+  CHECK(buffer);
+
+  mojom::DecoderBufferPtr mojo_buffer =
+      mojo_decoder_buffer_writer_->WriteDecoderBuffer(std::move(buffer));
+  if (!mojo_buffer) {
+    Stop();
+    return;
+  }
+
   // TODO(b/171813538): create buffer from input parameter |buffer|.
   remote_decoder_->Decode(
       stable::mojom::DecoderBufferPtr(),
@@ -295,6 +319,7 @@
 
   client_receiver_.reset();
   remote_decoder_.reset();
+  mojo_decoder_buffer_writer_.reset();
 
   if (init_cb_)
     std::move(init_cb_).Run(DecoderStatus::Codes::kFailed);
diff --git a/media/gpu/chromeos/oop_video_decoder.h b/media/gpu/chromeos/oop_video_decoder.h
index 7cec18e..dd4bb40 100644
--- a/media/gpu/chromeos/oop_video_decoder.h
+++ b/media/gpu/chromeos/oop_video_decoder.h
@@ -15,6 +15,8 @@
 
 namespace media {
 
+class MojoDecoderBufferWriter;
+
 // Proxy video decoder that connects with an out-of-process
 // video decoder via Mojo. This class should be operated and
 // destroyed on |decoder_task_runner_|.
@@ -97,6 +99,9 @@
       GUARDED_BY_CONTEXT(sequence_checker_);
   bool has_error_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
 
+  std::unique_ptr<MojoDecoderBufferWriter> mojo_decoder_buffer_writer_
+      GUARDED_BY_CONTEXT(sequence_checker_);
+
   SEQUENCE_CHECKER(sequence_checker_);
 
   base::WeakPtrFactory<OOPVideoDecoder> weak_this_factory_
diff --git a/net/BUILD.gn b/net/BUILD.gn
index ff1dac8..c29f1538 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1173,7 +1173,7 @@
     ]
   }
 
-  if ((is_chromeos_ash || is_chromeos_lacros) && use_nss_certs) {
+  if (is_chromeos && use_nss_certs) {
     sources += [
       "cert/nss_cert_database_chromeos.cc",
       "cert/nss_cert_database_chromeos.h",
diff --git a/net/base/features.cc b/net/base/features.cc
index b15b792..f268b40 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -257,6 +257,9 @@
 const base::Feature kPartitionedCookiesBypassOriginTrial{
     "PartitionedCookiesBypassOriginTrial", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kNoncedPartitionedCookies{
+    "NoncedPartitionedCookies", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kExtraCookieValidityChecks{
     "ExtraCookieValidityChecks", base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/net/base/features.h b/net/base/features.h
index 3b5bfdd..632b360 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -384,6 +384,12 @@
 // TODO(crbug.com/1296161): Remove this feature when the CHIPS OT ends.
 NET_EXPORT extern const base::Feature kPartitionedCookiesBypassOriginTrial;
 
+// When enabled, then we allow partitioned cookies even if kPartitionedCookies
+// is disabled only if the cookie partition key contains a nonce. So far, this
+// is used to create temporary cookie jar partitions for fenced and anonymous
+// frames.
+NET_EXPORT extern const base::Feature kNoncedPartitionedCookies;
+
 // When enabled, additional cookie-related APIs will perform cookie field size
 // and character set validation to enforce stricter conformance with RFC6265bis.
 // TODO(crbug.com/1243852) Eventually enable this permanently and remove the
diff --git a/net/cookies/cookie_partition_key.cc b/net/cookies/cookie_partition_key.cc
index 71026105..ec9872e7 100644
--- a/net/cookies/cookie_partition_key.cc
+++ b/net/cookies/cookie_partition_key.cc
@@ -95,8 +95,16 @@
 absl::optional<CookiePartitionKey> CookiePartitionKey::FromNetworkIsolationKey(
     const NetworkIsolationKey& network_isolation_key,
     const SchemefulSite* first_party_set_owner_site) {
-  if (!base::FeatureList::IsEnabled(features::kPartitionedCookies))
+  absl::optional<base::UnguessableToken> nonce =
+      network_isolation_key.GetNonce();
+  // If PartitionedCookies is enabled, all partitioned cookies are allowed.
+  // If NoncedPartitionedCookies is enabled, only partitioned cookies whose
+  // partition key has a nonce are allowed.
+  if (!base::FeatureList::IsEnabled(features::kPartitionedCookies) &&
+      (!base::FeatureList::IsEnabled(features::kNoncedPartitionedCookies) ||
+       !nonce)) {
     return absl::nullopt;
+  }
 
   // TODO(crbug.com/1225444): Check if the top frame site is in a First-Party
   // Set or if it is an extension URL.
@@ -107,8 +115,6 @@
   if (!partition_key_site)
     return absl::nullopt;
 
-  absl::optional<base::UnguessableToken> nonce =
-      network_isolation_key.GetNonce();
   return absl::make_optional(
       net::CookiePartitionKey(*partition_key_site, nonce));
 }
diff --git a/net/cookies/cookie_partition_key_unittest.cc b/net/cookies/cookie_partition_key_unittest.cc
index b500019..c674d8cb 100644
--- a/net/cookies/cookie_partition_key_unittest.cc
+++ b/net/cookies/cookie_partition_key_unittest.cc
@@ -114,79 +114,110 @@
 }
 
 TEST_P(CookiePartitionKeyTest, FromNetworkIsolationKey) {
-  EXPECT_FALSE(
-      CookiePartitionKey::FromNetworkIsolationKey(NetworkIsolationKey()));
-
-  SchemefulSite top_level_site =
-      SchemefulSite(GURL("https://toplevelsite.com"));
-  absl::optional<CookiePartitionKey> got =
-      CookiePartitionKey::FromNetworkIsolationKey(NetworkIsolationKey(
-          top_level_site, SchemefulSite(GURL("https://cookiesite.com"))));
-
-  bool partitioned_cookies_enabled = PartitionedCookiesEnabled();
-  EXPECT_EQ(partitioned_cookies_enabled, got.has_value());
-  if (partitioned_cookies_enabled) {
-    EXPECT_FALSE(got->from_script());
-    EXPECT_EQ(CookiePartitionKey::FromURLForTesting(top_level_site.GetURL()),
-              got.value());
-  }
-}
-
-TEST_P(CookiePartitionKeyTest, FromNetworkIsolationKey_WithNonce) {
   const SchemefulSite kTopLevelSite =
       SchemefulSite(GURL("https://toplevelsite.com"));
+  const SchemefulSite kCookieSite =
+      SchemefulSite(GURL("https://cookiesite.com"));
+  const SchemefulSite kFirstPartySetOwnerSite =
+      SchemefulSite(GURL("https://setowner.com"));
   const base::UnguessableToken kNonce = base::UnguessableToken::Create();
 
-  absl::optional<CookiePartitionKey> got =
-      CookiePartitionKey::FromNetworkIsolationKey(NetworkIsolationKey(
-          kTopLevelSite, SchemefulSite(GURL("https://cookiesite.com")),
-          &kNonce));
-  bool partitioned_cookies_enabled = PartitionedCookiesEnabled();
-  EXPECT_EQ(partitioned_cookies_enabled, got.has_value());
-  if (!partitioned_cookies_enabled)
-    return;
+  struct TestCase {
+    const std::string desc;
+    const NetworkIsolationKey network_isolation_key;
+    bool use_first_party_sets;
+    bool allow_nonced_partition_keys;
+    const absl::optional<CookiePartitionKey> expected;
+  } test_cases[] = {
+      {
+          "Empty",
+          NetworkIsolationKey(),
+          /*use_first_party_sets=*/false,
+          /*allow_nonced_partition_keys=*/false,
+          absl::nullopt,
+      },
+      {
+          "WithTopLevelSite",
+          NetworkIsolationKey(kTopLevelSite, kCookieSite),
+          /*use_first_party_sets=*/false,
+          /*allow_nonced_partition_keys=*/false,
+          CookiePartitionKey::FromURLForTesting(kTopLevelSite.GetURL()),
+      },
+      {
+          "WithFirstPartySetOwner",
+          NetworkIsolationKey(kTopLevelSite, kCookieSite),
+          /*use_first_party_sets=*/true,
+          /*allow_nonced_partition_keys=*/false,
+          CookiePartitionKey::FromURLForTesting(
+              kFirstPartySetOwnerSite.GetURL()),
+      },
+      {
+          "WithNonce",
+          NetworkIsolationKey(kTopLevelSite, kCookieSite, &kNonce),
+          /*use_first_party_sets=*/false,
+          /*allow_nonced_partition_keys=*/false,
+          CookiePartitionKey::FromURLForTesting(kTopLevelSite.GetURL(), kNonce),
+      },
+      {
+          "FirstPartySetWithNonce",
+          NetworkIsolationKey(kTopLevelSite, kCookieSite, &kNonce),
+          /*use_first_party_sets=*/true,
+          /*allow_nonced_partition_keys=*/false,
+          CookiePartitionKey::FromURLForTesting(
+              kFirstPartySetOwnerSite.GetURL(), kNonce),
+      },
+      {
+          "NoncedAllowed_KeyWithoutNonce",
+          NetworkIsolationKey(kTopLevelSite, kCookieSite),
+          /*use_first_party_sets=*/false,
+          /*allow_nonced_partition_keys=*/true,
+          CookiePartitionKey::FromURLForTesting(kTopLevelSite.GetURL()),
+      },
+      {
+          "NoncedAllowed_KeyWithoutNonce",
+          NetworkIsolationKey(kTopLevelSite, kCookieSite, &kNonce),
+          /*use_first_party_sets=*/false,
+          /*allow_nonced_partition_keys=*/true,
+          CookiePartitionKey::FromURLForTesting(kTopLevelSite.GetURL(), kNonce),
+      },
+  };
 
-  EXPECT_FALSE(got->from_script());
-  EXPECT_TRUE(got->nonce());
-  EXPECT_EQ(kTopLevelSite, got->site());
-  EXPECT_EQ(kNonce, got->nonce().value());
-}
+  for (const auto& test_case : test_cases) {
+    SCOPED_TRACE(test_case.desc);
 
-TEST_P(CookiePartitionKeyTest, FromNetworkIsolationKey_WithFirstPartySetOwner) {
-  SchemefulSite kTopLevelSite = SchemefulSite(GURL("https://setmember.com"));
-  SchemefulSite kFirstPartySetOwnerSite =
-      SchemefulSite(GURL("https://setowner.com"));
-  SchemefulSite kCookieSite = SchemefulSite(GURL("https://cookiesite.com"));
-
-  {
-    // Without a nonce.
-    absl::optional<CookiePartitionKey> got =
-        CookiePartitionKey::FromNetworkIsolationKey(
-            NetworkIsolationKey(kTopLevelSite, kCookieSite),
-            &kFirstPartySetOwnerSite);
-    bool partitioned_cookies_enabled = PartitionedCookiesEnabled();
-    EXPECT_EQ(partitioned_cookies_enabled, got.has_value());
-    if (partitioned_cookies_enabled) {
-      EXPECT_FALSE(got->from_script());
-      EXPECT_EQ(kFirstPartySetOwnerSite, got->site());
-      EXPECT_FALSE(got->nonce());
+    base::test::ScopedFeatureList feature_list;
+    std::vector<base::Feature> enabled_features;
+    std::vector<base::Feature> disabled_features;
+    if (PartitionedCookiesEnabled()) {
+      enabled_features.push_back(features::kPartitionedCookies);
+    } else {
+      disabled_features.push_back(features::kPartitionedCookies);
     }
-  }
+    if (test_case.allow_nonced_partition_keys) {
+      enabled_features.push_back(features::kNoncedPartitionedCookies);
+    } else {
+      disabled_features.push_back(features::kNoncedPartitionedCookies);
+    }
+    feature_list.InitWithFeatures(enabled_features, disabled_features);
 
-  {
-    // With a nonce.
-    base::UnguessableToken nonce = base::UnguessableToken::Create();
     absl::optional<CookiePartitionKey> got =
         CookiePartitionKey::FromNetworkIsolationKey(
-            NetworkIsolationKey(kTopLevelSite, kCookieSite, &nonce),
-            &kFirstPartySetOwnerSite);
-    bool partitioned_cookies_enabled = PartitionedCookiesEnabled();
-    EXPECT_EQ(partitioned_cookies_enabled, got.has_value());
-    if (partitioned_cookies_enabled) {
+            test_case.network_isolation_key, test_case.use_first_party_sets
+                                                 ? &kFirstPartySetOwnerSite
+                                                 : nullptr);
+
+    if (got)
       EXPECT_FALSE(got->from_script());
-      EXPECT_EQ(kFirstPartySetOwnerSite, got->site());
-      EXPECT_TRUE(got->nonce());
-      EXPECT_EQ(nonce, got->nonce().value());
+
+    if (PartitionedCookiesEnabled()) {
+      EXPECT_EQ(test_case.expected, got);
+    } else if (test_case.allow_nonced_partition_keys) {
+      EXPECT_EQ(test_case.network_isolation_key.GetNonce().has_value(),
+                got.has_value());
+      if (got)
+        EXPECT_EQ(test_case.expected, got);
+    } else {
+      EXPECT_FALSE(got);
     }
   }
 }
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 4d1aa39..0d77a9dc 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -346,8 +346,6 @@
                   quic_params->allow_server_migration);
   dict.SetBoolKey("race_stale_dns_on_connection",
                   quic_params->race_stale_dns_on_connection);
-  dict.SetBoolKey("go_away_on_path_degrading",
-                  quic_params->go_away_on_path_degrading);
   dict.SetBoolKey("estimate_initial_rtt", quic_params->estimate_initial_rtt);
   dict.SetBoolKey("server_push_cancellation",
                   params_.enable_server_push_cancellation);
diff --git a/net/http/transport_security_state.h b/net/http/transport_security_state.h
index e2d9b82..e8d50db 100644
--- a/net/http/transport_security_state.h
+++ b/net/http/transport_security_state.h
@@ -487,6 +487,10 @@
     ct_emergency_disable_ = emergency_disable;
   }
 
+  bool is_ct_emergency_disabled_for_testing() const {
+    return ct_emergency_disable_;
+  }
+
   void SetCTLogListUpdateTime(base::Time update_time);
 
   // |pinsets| should include all known pinsets, |host_pins| the information
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index 3ec4716..94f03c80 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -1747,9 +1747,35 @@
   }
 }
 
-// Tests that the emergency disable flag causes CT to stop being required
+enum class CTEmergencyDisableSwitchKind {
+  kFinchDrivenFeature,
+  kComponentUpdaterDrivenSwitch,
+};
+
+class CTEmergencyDisableTest
+    : public TransportSecurityStateTest,
+      public testing::WithParamInterface<CTEmergencyDisableSwitchKind> {
+ public:
+  void SetUp() override {
+    if (GetParam() ==
+        CTEmergencyDisableSwitchKind::kComponentUpdaterDrivenSwitch) {
+      state_.SetCTEmergencyDisabled(true);
+      scoped_feature_list_.Init();
+    } else {
+      ASSERT_EQ(GetParam(), CTEmergencyDisableSwitchKind::kFinchDrivenFeature);
+      scoped_feature_list_.InitAndDisableFeature(
+          TransportSecurityState::kCertificateTransparencyEnforcement);
+    }
+  }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  TransportSecurityState state_;
+};
+
+// Tests that the emergency disable flags cause CT to stop being required
 // regardless of host or delegate status.
-TEST_F(TransportSecurityStateTest, CTEmergencyDisable) {
+TEST_P(CTEmergencyDisableTest, CTEmergencyDisable) {
   using ::testing::_;
   using ::testing::Return;
   using CTRequirementLevel =
@@ -1764,47 +1790,42 @@
   hashes.push_back(
       HashValue(X509Certificate::CalculateFingerprint256(cert->cert_buffer())));
 
-  TransportSecurityState state;
-
-  // Set CT emergency disable flag.
-  state.SetCTEmergencyDisabled(true);
-
   MockRequireCTDelegate always_require_delegate;
   EXPECT_CALL(always_require_delegate, IsCTRequiredForHost(_, _, _))
       .WillRepeatedly(Return(CTRequirementLevel::REQUIRED));
-  state.SetRequireCTDelegate(&always_require_delegate);
+  state_.SetRequireCTDelegate(&always_require_delegate);
   EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED,
-            state.CheckCTRequirements(
+            state_.CheckCTRequirements(
                 HostPortPair("www.example.com", 443), true, hashes, cert.get(),
                 cert.get(), SignedCertificateTimestampAndStatusList(),
                 TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
                 ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
                 NetworkIsolationKey()));
   EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED,
-            state.CheckCTRequirements(
+            state_.CheckCTRequirements(
                 HostPortPair("www.example.com", 443), true, hashes, cert.get(),
                 cert.get(), SignedCertificateTimestampAndStatusList(),
                 TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
                 ct::CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
                 NetworkIsolationKey()));
   EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED,
-            state.CheckCTRequirements(
+            state_.CheckCTRequirements(
                 HostPortPair("www.example.com", 443), true, hashes, cert.get(),
                 cert.get(), SignedCertificateTimestampAndStatusList(),
                 TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
                 ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
                 NetworkIsolationKey()));
   EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED,
-            state.CheckCTRequirements(
+            state_.CheckCTRequirements(
                 HostPortPair("www.example.com", 443), true, hashes, cert.get(),
                 cert.get(), SignedCertificateTimestampAndStatusList(),
                 TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
                 ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY,
                 NetworkIsolationKey()));
 
-  state.SetRequireCTDelegate(nullptr);
+  state_.SetRequireCTDelegate(nullptr);
   EXPECT_EQ(TransportSecurityState::CT_NOT_REQUIRED,
-            state.CheckCTRequirements(
+            state_.CheckCTRequirements(
                 HostPortPair("www.example.com", 443), true, hashes, cert.get(),
                 cert.get(), SignedCertificateTimestampAndStatusList(),
                 TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
@@ -1812,6 +1833,12 @@
                 NetworkIsolationKey()));
 }
 
+INSTANTIATE_TEST_SUITE_P(
+    CTEmergencyDisable,
+    CTEmergencyDisableTest,
+    testing::Values(CTEmergencyDisableSwitchKind::kComponentUpdaterDrivenSwitch,
+                    CTEmergencyDisableSwitchKind::kFinchDrivenFeature));
+
 // Tests that the if the CT log list last update time is set, it is used for
 // enforcement decisions.
 TEST_F(TransportSecurityStateTest, CTTimestampUpdate) {
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index 351bb09..14ddbf4 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -1988,9 +1988,6 @@
 //   }
 EVENT_TYPE(QUIC_SESSION_GOAWAY_FRAME_SENT)
 
-// Session detected path degrading and decided to mark itself as goaway.
-EVENT_TYPE(QUIC_SESSION_CLIENT_GOAWAY_ON_PATH_DEGRADING)
-
 // Session received a PING frame.
 EVENT_TYPE(QUIC_SESSION_PING_FRAME_RECEIVED)
 
diff --git a/net/quic/bidirectional_stream_quic_impl_unittest.cc b/net/quic/bidirectional_stream_quic_impl_unittest.cc
index 88060770..a4ad88b 100644
--- a/net/quic/bidirectional_stream_quic_impl_unittest.cc
+++ b/net/quic/bidirectional_stream_quic_impl_unittest.cc
@@ -575,7 +575,6 @@
         kQuicYieldAfterPacketsRead,
         quic::QuicTime::Delta::FromMilliseconds(
             kQuicYieldAfterDurationMilliseconds),
-        /*go_away_on_path_degrading*/ false,
         client_headers_include_h2_stream_dependency_, /*cert_verify_flags=*/0,
         quic::test::DefaultQuicConfig(),
         std::make_unique<TestQuicCryptoClientConfigHandle>(&crypto_config_),
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index 23a3e8d..8d8eac09 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -937,7 +937,6 @@
     int max_migrations_to_non_default_network_on_path_degrading,
     int yield_after_packets,
     quic::QuicTime::Delta yield_after_duration,
-    bool go_away_on_path_degrading,
     bool headers_include_h2_stream_dependency,
     int cert_verify_flags,
     const quic::QuicConfig& config,
@@ -973,7 +972,6 @@
       clock_(clock),
       yield_after_packets_(yield_after_packets),
       yield_after_duration_(yield_after_duration),
-      go_away_on_path_degrading_(go_away_on_path_degrading),
       most_recent_path_degrading_timestamp_(base::TimeTicks()),
       most_recent_network_disconnected_timestamp_(base::TimeTicks()),
       tick_clock_(tick_clock),
@@ -1017,11 +1015,6 @@
       last_key_update_reason_(quic::KeyUpdateReason::kInvalid),
       push_promise_index_(std::move(push_promise_index)),
       path_validation_writer_delegate_(this, task_runner_) {
-  // Make sure connection migration and goaway on path degrading are not turned
-  // on at the same time.
-  DCHECK(!(migrate_session_early_v2_ && go_away_on_path_degrading_));
-  DCHECK(!(allow_port_migration_ && go_away_on_path_degrading_));
-
   default_network_ = default_network;
   auto* socket_raw = socket.get();
   sockets_.push_back(std::move(socket));
@@ -2772,24 +2765,9 @@
   if (most_recent_path_degrading_timestamp_ == base::TimeTicks())
     most_recent_path_degrading_timestamp_ = tick_clock_->NowTicks();
 
-  if (go_away_on_path_degrading_ && OneRttKeysAvailable()) {
-    net_log_.AddEvent(
-        NetLogEventType::QUIC_SESSION_CLIENT_GOAWAY_ON_PATH_DEGRADING);
-    NotifyFactoryOfSessionGoingAway();
-    UMA_HISTOGRAM_COUNTS_1M(
-        "Net.QuicSession.ActiveStreamsOnGoAwayAfterPathDegrading",
-        GetNumActiveStreams());
-    UMA_HISTOGRAM_COUNTS_1M(
-        "Net.QuicSession.DrainingStreamsOnGoAwayAfterPathDegrading",
-        num_outgoing_draining_streams());
-    return;
-  }
-
-  if (!go_away_on_path_degrading_) {
-    NetworkChangeNotifier::NetworkHandle current_network = GetCurrentNetwork();
-    for (auto& observer : connectivity_observer_list_)
-      observer.OnSessionPathDegrading(this, current_network);
-  }
+  NetworkChangeNotifier::NetworkHandle current_network = GetCurrentNetwork();
+  for (auto& observer : connectivity_observer_list_)
+    observer.OnSessionPathDegrading(this, current_network);
 
   if (!stream_factory_)
     return;
@@ -2804,9 +2782,6 @@
 }
 
 void QuicChromiumClientSession::OnForwardProgressMadeAfterPathDegrading() {
-  if (go_away_on_path_degrading_)
-    return;
-
   NetworkChangeNotifier::NetworkHandle current_network = GetCurrentNetwork();
   for (auto& observer : connectivity_observer_list_)
     observer.OnSessionResumedPostPathDegrading(this, current_network);
diff --git a/net/quic/quic_chromium_client_session.h b/net/quic/quic_chromium_client_session.h
index 3c8a751..f234370 100644
--- a/net/quic/quic_chromium_client_session.h
+++ b/net/quic/quic_chromium_client_session.h
@@ -564,7 +564,6 @@
       int max_migrations_to_non_default_network_on_path_degrading,
       int yield_after_packets,
       quic::QuicTime::Delta yield_after_duration,
-      bool go_away_on_path_degrading,
       bool headers_include_h2_stream_dependency,
       int cert_verify_flags,
       const quic::QuicConfig& config,
@@ -1001,7 +1000,6 @@
   raw_ptr<const quic::QuicClock> clock_;  // Unowned.
   int yield_after_packets_;
   quic::QuicTime::Delta yield_after_duration_;
-  bool go_away_on_path_degrading_;
 
   base::TimeTicks most_recent_path_degrading_timestamp_;
   base::TimeTicks most_recent_network_disconnected_timestamp_;
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc
index 1fc3f89..92eba7d 100644
--- a/net/quic/quic_chromium_client_session_test.cc
+++ b/net/quic/quic_chromium_client_session_test.cc
@@ -161,8 +161,7 @@
                       kServerHostname,
                       quic::Perspective::IS_SERVER,
                       false),
-        migrate_session_early_v2_(false),
-        go_away_on_path_degrading_(false) {
+        migrate_session_early_v2_(false) {
     FLAGS_quic_enable_http3_grease_randomness = false;
     quic::QuicEnableVersion(version_);
     // Advance the time, because timers do not like uninitialized times.
@@ -207,7 +206,6 @@
         kQuicYieldAfterPacketsRead,
         quic::QuicTime::Delta::FromMilliseconds(
             kQuicYieldAfterDurationMilliseconds),
-        go_away_on_path_degrading_,
         client_headers_include_h2_stream_dependency_,
         /*cert_verify_flags=*/0, config_,
         std::make_unique<TestQuicCryptoClientConfigHandle>(&crypto_config_),
@@ -319,7 +317,6 @@
   ProofVerifyDetailsChromium verify_details_;
   bool migrate_session_early_v2_;
   quic::test::NoopQpackStreamSenderDelegate noop_qpack_stream_sender_delegate_;
-  bool go_away_on_path_degrading_;
 };
 
 INSTANTIATE_TEST_SUITE_P(VersionIncludeStreamDependencySequence,
@@ -2285,25 +2282,6 @@
   EXPECT_TRUE(quic_data2.AllWriteDataConsumed());
 }
 
-TEST_P(QuicChromiumClientSessionTest,
-       GoAwayOnPathDegradingOnlyWhenHandshakeConfirmed) {
-  go_away_on_path_degrading_ = true;
-  MockQuicData quic_data(version_);
-  if (VersionUsesHttp3(version_.transport_version))
-    quic_data.AddWrite(SYNCHRONOUS, client_maker_.MakeInitialSettingsPacket(1));
-  quic_data.AddRead(ASYNC, ERR_IO_PENDING);
-  quic_data.AddRead(ASYNC, ERR_CONNECTION_CLOSED);
-  quic_data.AddSocketDataToFactory(&socket_factory_);
-  Initialize();
-  session_->ReallyOnPathDegrading();
-  EXPECT_FALSE(
-      QuicChromiumClientSessionPeer::GetSessionGoingAway(session_.get()));
-  CompleteCryptoHandshake();
-  session_->ReallyOnPathDegrading();
-  EXPECT_TRUE(
-      QuicChromiumClientSessionPeer::GetSessionGoingAway(session_.get()));
-}
-
 TEST_P(QuicChromiumClientSessionTest, RetransmittableOnWireTimeout) {
   migrate_session_early_v2_ = true;
 
diff --git a/net/quic/quic_context.h b/net/quic/quic_context.h
index b03c5fa..52e6325e 100644
--- a/net/quic/quic_context.h
+++ b/net/quic/quic_context.h
@@ -160,8 +160,6 @@
   // If true, the quic stream factory may race connection from stale dns
   // result with the original dns resolution
   bool race_stale_dns_on_connection = false;
-  // If true, the quic session may mark itself as GOAWAY on path degrading.
-  bool go_away_on_path_degrading = false;
   // If true, bidirectional streams over QUIC will be disabled.
   bool disable_bidirectional_streams = false;
   // If true, estimate the initial RTT for QUIC connections based on network.
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 5ace3e7..ae22384 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -419,7 +419,6 @@
         kQuicYieldAfterPacketsRead,
         quic::QuicTime::Delta::FromMilliseconds(
             kQuicYieldAfterDurationMilliseconds),
-        /*go_away_on_path_degrading*/ false,
         client_headers_include_h2_stream_dependency_, /*cert_verify_flags=*/0,
         quic::test::DefaultQuicConfig(),
         std::make_unique<TestQuicCryptoClientConfigHandle>(&crypto_config_),
diff --git a/net/quic/quic_proxy_client_socket_unittest.cc b/net/quic/quic_proxy_client_socket_unittest.cc
index 6cb6a22..36b3aa7 100644
--- a/net/quic/quic_proxy_client_socket_unittest.cc
+++ b/net/quic/quic_proxy_client_socket_unittest.cc
@@ -281,7 +281,6 @@
         kQuicYieldAfterPacketsRead,
         quic::QuicTime::Delta::FromMilliseconds(
             kQuicYieldAfterDurationMilliseconds),
-        /*go_away_on_path_degrading*/ false,
         client_headers_include_h2_stream_dependency_, /*cert_verify_flags=*/0,
         quic::test::DefaultQuicConfig(),
         std::make_unique<TestQuicCryptoClientConfigHandle>(&crypto_config_),
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index a3f1bcca..e46ca70 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -1872,7 +1872,6 @@
       params_.max_migrations_to_non_default_network_on_write_error,
       params_.max_migrations_to_non_default_network_on_path_degrading,
       yield_after_packets_, yield_after_duration_,
-      params_.go_away_on_path_degrading,
       params_.headers_include_h2_stream_dependency, cert_verify_flags, config,
       std::move(crypto_config_handle),
       network_connection_.connection_description(), dns_resolution_start_time,
@@ -2007,9 +2006,6 @@
   params_.retry_on_alternate_network_before_handshake = false;
   params_.migrate_idle_sessions = false;
 
-  DCHECK(!(migrate_sessions_early && params_.go_away_on_path_degrading));
-  DCHECK(!(allow_port_migration && params_.go_away_on_path_degrading));
-
   // TODO(zhongyi): deprecate |goaway_sessions_on_ip_change| if the experiment
   // is no longer needed.
   // goaway_sessions_on_ip_change and close_sessions_on_ip_change should never
diff --git a/net/quic/quic_stream_factory_fuzzer.cc b/net/quic/quic_stream_factory_fuzzer.cc
index 3fce1d5..00217bd0 100644
--- a/net/quic/quic_stream_factory_fuzzer.cc
+++ b/net/quic/quic_stream_factory_fuzzer.cc
@@ -110,7 +110,6 @@
   params.migrate_sessions_on_network_change_v2 = false;
   params.retry_on_alternate_network_before_handshake = false;
   params.migrate_idle_sessions = false;
-  params.go_away_on_path_degrading = false;
 
   if (!params.close_sessions_on_ip_change) {
     params.goaway_sessions_on_ip_change = data_provider.ConsumeBool();
@@ -126,10 +125,6 @@
     }
   }
 
-  if (!params.migrate_sessions_early_v2) {
-    params.go_away_on_path_degrading = data_provider.ConsumeBool();
-  }
-
   std::unique_ptr<QuicStreamFactory> factory =
       std::make_unique<QuicStreamFactory>(
           env->net_log.net_log(), host_resolver.get(),
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index aebe748..35337f1 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -5918,124 +5918,6 @@
   EXPECT_TRUE(quic_data2.AllWriteDataConsumed());
 }
 
-// This test verifies that the session marks itself GOAWAY on path degrading
-// and it does not receive any new request
-TEST_P(QuicStreamFactoryTest, GoawayOnPathDegrading) {
-  quic_params_->go_away_on_path_degrading = true;
-  Initialize();
-  ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
-  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-  crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
-
-  MockQuicData quic_data1(version_);
-  int packet_num = 1;
-  if (VersionUsesHttp3(version_.transport_version)) {
-    quic_data1.AddWrite(SYNCHRONOUS,
-                        ConstructInitialSettingsPacket(packet_num++));
-  }
-  quic_data1.AddWrite(
-      SYNCHRONOUS,
-      ConstructGetRequestPacket(packet_num,
-                                GetNthClientInitiatedBidirectionalStreamId(0),
-                                true, true));
-  quic_data1.AddRead(ASYNC, ERR_IO_PENDING);  // Pause
-  quic_data1.AddRead(
-      ASYNC,
-      ConstructOkResponsePacket(
-          1, GetNthClientInitiatedBidirectionalStreamId(0), false, true));
-  quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read.
-  quic_data1.AddSocketDataToFactory(socket_factory_.get());
-
-  client_maker_.Reset();
-  MockQuicData quic_data2(version_);
-  quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING);  // Hanging read.
-  if (VersionUsesHttp3(version_.transport_version))
-    quic_data2.AddWrite(SYNCHRONOUS, ConstructInitialSettingsPacket());
-  quic_data2.AddSocketDataToFactory(socket_factory_.get());
-
-  // Creat request and QuicHttpStream.
-  QuicStreamRequest request(factory_.get());
-  EXPECT_EQ(ERR_IO_PENDING,
-            request.Request(
-                scheme_host_port_, version_, privacy_mode_, DEFAULT_PRIORITY,
-                SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow,
-                true /* use_dns_aliases */,
-                /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_,
-                failed_on_default_network_callback_, callback_.callback()));
-  EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream = CreateStream(&request);
-  EXPECT_TRUE(stream.get());
-
-  // Cause QUIC stream to be created.
-  HttpRequestInfo request_info;
-  request_info.method = "GET";
-  request_info.url = url_;
-  request_info.traffic_annotation =
-      MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
-  EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY,
-                                         net_log_, CompletionOnceCallback()));
-
-  // Ensure that session is alive and active.
-  QuicChromiumClientSession* session = GetActiveSession(scheme_host_port_);
-  EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
-  EXPECT_TRUE(HasActiveSession(scheme_host_port_));
-
-  // Send GET request on stream.
-  HttpResponseInfo response;
-  HttpRequestHeaders request_headers;
-  EXPECT_EQ(OK, stream->SendRequest(request_headers, &response,
-                                    callback_.callback()));
-
-  EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get()));
-
-  // Trigger the connection to report path degrading to the session.
-  // Session will mark itself GOAWAY.
-  session->connection()->OnPathDegradingDetected();
-
-  /// Path degrading detection on go_away_on_path_degrading detection is
-  // disabled.
-  EXPECT_EQ(0u, QuicStreamFactoryPeer::GetNumDegradingSessions(factory_.get()));
-
-  // The connection should still be alive, but marked as going away.
-  EXPECT_FALSE(HasActiveSession(scheme_host_port_));
-  EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
-  EXPECT_EQ(1u, session->GetNumActiveStreams());
-
-  // Second request should be sent on a new connection.
-  QuicStreamRequest request2(factory_.get());
-  EXPECT_EQ(ERR_IO_PENDING,
-            request2.Request(
-                scheme_host_port_, version_, privacy_mode_, DEFAULT_PRIORITY,
-                SocketTag(), NetworkIsolationKey(), SecureDnsPolicy::kAllow,
-                true /* use_dns_aliases */,
-                /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_,
-                failed_on_default_network_callback_, callback_.callback()));
-  EXPECT_THAT(callback_.WaitForResult(), IsOk());
-  std::unique_ptr<HttpStream> stream2 = CreateStream(&request2);
-  EXPECT_TRUE(stream2.get());
-
-  // Resume the data, verify old request can read response on the old session
-  // successfully.
-  quic_data1.Resume();
-  EXPECT_EQ(OK, stream->ReadResponseHeaders(callback_.callback()));
-  EXPECT_EQ(200, response.headers->response_code());
-  EXPECT_EQ(0U, session->GetNumActiveStreams());
-
-  // Check an active session exists for the destination.
-  EXPECT_TRUE(HasActiveSession(scheme_host_port_));
-  EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
-  QuicChromiumClientSession* session2 = GetActiveSession(scheme_host_port_);
-  EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session2));
-  EXPECT_NE(session, session2);
-
-  stream.reset();
-  stream2.reset();
-  EXPECT_TRUE(quic_data1.AllReadDataConsumed());
-  EXPECT_TRUE(quic_data1.AllWriteDataConsumed());
-  EXPECT_TRUE(quic_data2.AllReadDataConsumed());
-  EXPECT_TRUE(quic_data2.AllWriteDataConsumed());
-}
-
 // This test verifies that the connection will not migrate to a bad socket
 // when path degrading is detected.
 TEST_P(QuicStreamFactoryTest, DoNotMigrateToBadSocketOnPathDegrading) {
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 2a56500..7c24d9a 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -393,7 +393,6 @@
     // QUIC connection migration should not be enabled when binding a context
     // to a network.
     quic_params->migrate_sessions_on_network_change_v2 = false;
-    quic_params->go_away_on_path_degrading = false;
 
     // Objects used by network sessions for this context shouldn't listen to
     // network changes.
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc
index 0bedd50b..0fea715 100644
--- a/pdf/pdf_view_web_plugin.cc
+++ b/pdf/pdf_view_web_plugin.cc
@@ -285,10 +285,6 @@
   return nullptr;
 }
 
-bool PdfViewWebPlugin::Client::IsUseZoomForDSFEnabled() const {
-  return false;
-}
-
 PdfViewWebPlugin::PdfViewWebPlugin(
     std::unique_ptr<Client> client,
     mojo::AssociatedRemote<pdf::mojom::PdfService> pdf_service_remote,
@@ -473,10 +469,8 @@
   OnViewportChanged(window_rect, container_wrapper_->DeviceScaleFactor());
 
   gfx::PointF scroll_position = container_wrapper_->GetScrollPosition();
-  if (client_->IsUseZoomForDSFEnabled()) {
-    // Convert back to CSS pixels.
-    scroll_position.Scale(1.0f / device_scale());
-  }
+  // Convert back to CSS pixels.
+  scroll_position.Scale(1.0f / device_scale());
   UpdateScroll(scroll_position);
 }
 
@@ -889,13 +883,8 @@
 }
 
 void PdfViewWebPlugin::UpdateScale(float scale) {
-  if (client_->IsUseZoomForDSFEnabled()) {
-    viewport_to_dip_scale_ = scale;
-    device_to_css_scale_ = 1.0f;
-  } else {
-    viewport_to_dip_scale_ = 1.0f;
-    device_to_css_scale_ = scale;
-  }
+  viewport_to_dip_scale_ = scale;
+  device_to_css_scale_ = 1.0f;
   UpdateScaledValues();
 }
 
@@ -1048,11 +1037,7 @@
 
   // `plugin_rect_in_css_pixel` needs to be converted to device pixels before
   // getting passed into PdfViewPluginBase::UpdateGeometryOnPluginRectChanged().
-  UpdateGeometryOnPluginRectChanged(
-      gfx::ScaleToEnclosingRect(
-          plugin_rect_in_css_pixel,
-          client_->IsUseZoomForDSFEnabled() ? 1.0f : new_device_scale),
-      new_device_scale);
+  UpdateGeometryOnPluginRectChanged(plugin_rect_in_css_pixel, new_device_scale);
 }
 
 void PdfViewWebPlugin::InvalidatePluginContainer() {
diff --git a/pdf/pdf_view_web_plugin.h b/pdf/pdf_view_web_plugin.h
index 75b5e49a..05662f3 100644
--- a/pdf/pdf_view_web_plugin.h
+++ b/pdf/pdf_view_web_plugin.h
@@ -162,9 +162,6 @@
     virtual std::unique_ptr<PdfAccessibilityDataHandler>
     CreateAccessibilityDataHandler(
         PdfAccessibilityActionHandler* action_handler);
-
-    // Indicates whether to use zoom for DSF (device scale factor).
-    virtual bool IsUseZoomForDSFEnabled() const;
   };
 
   PdfViewWebPlugin(
diff --git a/pdf/pdf_view_web_plugin_unittest.cc b/pdf/pdf_view_web_plugin_unittest.cc
index 5c93b01e..c4d7e0b9 100644
--- a/pdf/pdf_view_web_plugin_unittest.cc
+++ b/pdf/pdf_view_web_plugin_unittest.cc
@@ -253,7 +253,6 @@
               (const base::Value&, v8::Local<v8::Context>),
               (override));
   MOCK_METHOD(base::WeakPtr<Client>, GetWeakPtr, (), (override));
-  MOCK_METHOD(bool, IsUseZoomForDSFEnabled, (), (const, override));
 
  private:
   base::WeakPtrFactory<FakePdfViewWebPluginClient> weak_factory_{this};
@@ -443,9 +442,7 @@
       plugin_->InitializeForTesting(std::move(wrapper), std::move(engine)));
 }
 
-TEST_F(PdfViewWebPluginTest, UpdateGeometrySetsPluginRectUseZoomForDSFEnabled) {
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(true));
+TEST_F(PdfViewWebPluginTest, UpdateGeometrySetsPluginRect) {
   EXPECT_CALL(*engine_ptr_, ZoomUpdated(2.0f));
   TestUpdateGeometrySetsPluginRect(
       /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(4, 4, 12, 12),
@@ -454,17 +451,6 @@
 }
 
 TEST_F(PdfViewWebPluginTest,
-       UpdateGeometrySetsPluginRectUseZoomForDSFDisabled) {
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*engine_ptr_, ZoomUpdated(2.0f));
-  TestUpdateGeometrySetsPluginRect(
-      /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(4, 4, 12, 12),
-      /*expected_device_scale=*/2.0f,
-      /*expected_plugin_rect=*/gfx::Rect(8, 8, 24, 24));
-}
-
-TEST_F(PdfViewWebPluginTest,
        UpdateGeometrySetsPluginRectOnVariousDeviceScales) {
   struct UpdateGeometryParams {
     // The plugin container's device scale.
@@ -480,10 +466,6 @@
     gfx::Rect expected_plugin_rect;
   };
 
-  // Keep the using zoom for DSF setting consistent within the test.
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(true));
-
   static constexpr UpdateGeometryParams kUpdateGeometryParams[] = {
       {1.0f, gfx::Rect(3, 4, 5, 6), 1.0f, gfx::Rect(3, 4, 5, 6)},
       {2.0f, gfx::Rect(3, 4, 5, 6), 2.0f, gfx::Rect(3, 4, 5, 6)},
@@ -496,9 +478,7 @@
   }
 }
 
-TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollsUseZoomForDSFEnabled) {
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(true));
+TEST_F(PdfViewWebPluginTest, UpdateGeometryScroll) {
   SetDocumentDimensions({100, 200});
 
   EXPECT_CALL(*wrapper_ptr_, GetScrollPosition)
@@ -508,38 +488,14 @@
   UpdatePluginGeometryWithoutWaiting(2.0f, gfx::Rect(3, 4, 5, 6));
 }
 
-TEST_F(PdfViewWebPluginTest, UpdateGeometryScrollsUseZoomForDSFDisabled) {
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(false));
-  SetDocumentDimensions({100, 200});
-
-  EXPECT_CALL(*wrapper_ptr_, GetScrollPosition)
-      .WillRepeatedly(Return(gfx::PointF(2.0f, 3.0f)));
-  EXPECT_CALL(*engine_ptr_, ScrolledToXPosition(4));
-  EXPECT_CALL(*engine_ptr_, ScrolledToYPosition(6));
-  UpdatePluginGeometryWithoutWaiting(2.0f, gfx::Rect(3, 4, 5, 6));
-}
-
-class PdfViewWebPluginTestUseZoomForDSF
-    : public PdfViewWebPluginTest,
-      public testing::WithParamInterface<bool> {
- public:
-  void SetUp() override {
-    PdfViewWebPluginTest::SetUp();
-    ON_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-        .WillByDefault(Return(GetParam()));
-  }
-};
-
-TEST_P(PdfViewWebPluginTestUseZoomForDSF,
-       UpdateGeometrySetsPluginRectWithEmptyWindow) {
+TEST_F(PdfViewWebPluginTest, UpdateGeometrySetsPluginRectWithEmptyWindow) {
   EXPECT_CALL(*engine_ptr_, ZoomUpdated).Times(0);
   TestUpdateGeometrySetsPluginRect(
       /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(2, 2, 0, 0),
       /*expected_device_scale=*/1.0f, /*expected_plugin_rect=*/gfx::Rect());
 }
 
-TEST_P(PdfViewWebPluginTestUseZoomForDSF, SetCaretPositionIgnoresOrigin) {
+TEST_F(PdfViewWebPluginTest, SetCaretPositionIgnoresOrigin) {
   SetDocumentDimensions({16, 9});
   UpdatePluginGeometryWithoutWaiting(1.0f, {10, 20, 20, 5});
 
@@ -547,22 +503,21 @@
   plugin_->SetCaretPosition({4.0f, 3.0f});
 }
 
-TEST_P(PdfViewWebPluginTestUseZoomForDSF, PaintEmptySnapshots) {
+TEST_F(PdfViewWebPluginTest, PaintEmptySnapshots) {
   TestPaintEmptySnapshots(/*device_scale=*/4.0f,
                           /*window_rect=*/gfx::Rect(10, 10, 20, 20),
                           /*paint_rect=*/gfx::Rect(5, 5, 15, 15),
                           /*expected_clipped_rect=*/gfx::Rect(10, 10, 10, 10));
 }
 
-TEST_P(PdfViewWebPluginTestUseZoomForDSF, PaintSnapshots) {
+TEST_F(PdfViewWebPluginTest, PaintSnapshots) {
   TestPaintSnapshots(/*device_scale=*/4.0f,
                      /*window_rect=*/gfx::Rect(10, 10, 20, 20),
                      /*paint_rect=*/gfx::Rect(5, 5, 15, 15),
                      /*expected_clipped_rect=*/gfx::Rect(10, 10, 10, 10));
 }
 
-TEST_P(PdfViewWebPluginTestUseZoomForDSF,
-       PaintSnapshotsWithVariousDeviceScales) {
+TEST_F(PdfViewWebPluginTest, PaintSnapshotsWithVariousDeviceScales) {
   static constexpr PaintParams kPaintWithVariousScalesParams[] = {
       {0.4f, gfx::Rect(8, 8, 30, 30), gfx::Rect(10, 10, 30, 30),
        gfx::Rect(10, 10, 28, 28)},
@@ -578,8 +533,7 @@
   }
 }
 
-TEST_P(PdfViewWebPluginTestUseZoomForDSF,
-       PaintSnapshotsWithVariousRectPositions) {
+TEST_F(PdfViewWebPluginTest, PaintSnapshotsWithVariousRectPositions) {
   static constexpr PaintParams kPaintWithVariousPositionsParams[] = {
       // The window origin falls outside the `paint_rect` area.
       {4.0f, gfx::Rect(10, 10, 20, 20), gfx::Rect(5, 5, 15, 15),
@@ -595,7 +549,7 @@
   }
 }
 
-TEST_P(PdfViewWebPluginTestUseZoomForDSF, UpdateLayerTransformWithIdentity) {
+TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithIdentity) {
   plugin_->UpdateLayerTransform(1.0f, gfx::Vector2dF());
   TestPaintSnapshots(/*device_scale=*/4.0f,
                      /*window_rect=*/gfx::Rect(10, 10, 20, 20),
@@ -603,7 +557,7 @@
                      /*expected_clipped_rect=*/gfx::Rect(10, 10, 20, 20));
 }
 
-TEST_P(PdfViewWebPluginTestUseZoomForDSF, UpdateLayerTransformWithScale) {
+TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithScale) {
   plugin_->UpdateLayerTransform(0.5f, gfx::Vector2dF());
   TestPaintSnapshots(/*device_scale=*/4.0f,
                      /*window_rect=*/gfx::Rect(10, 10, 20, 20),
@@ -611,23 +565,7 @@
                      /*expected_clipped_rect=*/gfx::Rect(10, 10, 10, 10));
 }
 
-TEST_F(PdfViewWebPluginTest,
-       UpdateLayerTransformWithTranslateUseZoomForDSFDisabled) {
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(false));
-
-  plugin_->UpdateLayerTransform(1.0f, gfx::Vector2dF(-5, 5));
-  TestPaintSnapshots(/*device_scale=*/4.0f,
-                     /*window_rect=*/gfx::Rect(10, 10, 20, 20),
-                     /*paint_rect=*/gfx::Rect(10, 10, 20, 20),
-                     /*expected_clipped_rect=*/gfx::Rect(10, 15, 15, 15));
-}
-
-TEST_F(PdfViewWebPluginTest,
-       UpdateLayerTransformWithTranslateUseZoomForDSFEnabled) {
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(true));
-
+TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithTranslate) {
   plugin_->UpdateLayerTransform(1.0f, gfx::Vector2dF(-1.25, 1.25));
   TestPaintSnapshots(/*device_scale=*/4.0f,
                      /*window_rect=*/gfx::Rect(10, 10, 20, 20),
@@ -635,23 +573,7 @@
                      /*expected_clipped_rect=*/gfx::Rect(10, 15, 15, 15));
 }
 
-TEST_F(PdfViewWebPluginTest,
-       UpdateLayerTransformWithScaleAndTranslateUseZoomForDSFDisabled) {
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(false));
-
-  plugin_->UpdateLayerTransform(0.5f, gfx::Vector2dF(-5, 5));
-  TestPaintSnapshots(/*device_scale=*/4.0f,
-                     /*window_rect=*/gfx::Rect(10, 10, 20, 20),
-                     /*paint_rect=*/gfx::Rect(10, 10, 20, 20),
-                     /*expected_clipped_rect=*/gfx::Rect(10, 15, 5, 10));
-}
-
-TEST_F(PdfViewWebPluginTest,
-       UpdateLayerTransformWithScaleAndTranslateUseZoomForDSFEnabled) {
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(true));
-
+TEST_F(PdfViewWebPluginTest, UpdateLayerTransformWithScaleAndTranslate) {
   plugin_->UpdateLayerTransform(0.5f, gfx::Vector2dF(-1.25, 1.25));
   TestPaintSnapshots(/*device_scale=*/4.0f,
                      /*window_rect=*/gfx::Rect(10, 10, 20, 20),
@@ -659,10 +581,6 @@
                      /*expected_clipped_rect=*/gfx::Rect(10, 15, 5, 10));
 }
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         PdfViewWebPluginTestUseZoomForDSF,
-                         testing::Bool());
-
 class PdfViewWebPluginMouseEventsTest : public PdfViewWebPluginTest {
  public:
   class TestPDFiumEngineForMouseEvents : public TestPDFiumEngine {
@@ -701,11 +619,7 @@
   }
 };
 
-TEST_F(PdfViewWebPluginMouseEventsTest,
-       HandleInputEventWithUseZoomForDSFEnabled) {
-  // Test when using zoom for DSF is enabled.
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(true));
+TEST_F(PdfViewWebPluginMouseEventsTest, HandleInputEvent) {
   wrapper_ptr_->set_device_scale(kDeviceScale);
   UpdatePluginGeometry(kDeviceScale, gfx::Rect(20, 20));
 
@@ -720,25 +634,6 @@
   EXPECT_EQ(gfx::PointF(-10.0f, 0.0f), event->PositionInWidget());
 }
 
-TEST_F(PdfViewWebPluginMouseEventsTest,
-       HandleInputEventWithUseZoomForDSFDisabled) {
-  // Test when using zoom for DSF is disabled.
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(false));
-  wrapper_ptr_->set_device_scale(kDeviceScale);
-  UpdatePluginGeometry(kDeviceScale, gfx::Rect(20, 20));
-
-  ui::Cursor dummy_cursor;
-  plugin_->HandleInputEvent(
-      blink::WebCoalescedInputEvent(CreateDefaultMouseDownEvent(),
-                                    ui::LatencyInfo()),
-      &dummy_cursor);
-
-  const blink::WebMouseEvent* event = engine()->GetScaledMouseEvent();
-  ASSERT_TRUE(event);
-  EXPECT_EQ(gfx::PointF(-20.0f, 0.0f), event->PositionInWidget());
-}
-
 class PdfViewWebPluginImeTest : public PdfViewWebPluginTest {
  public:
   void TestImeSetCompositionForPlugin(const blink::WebString& text) {
@@ -950,9 +845,7 @@
   ASSERT_TRUE(plugin_->ShouldDispatchImeEventsToPlugin());
 }
 
-TEST_F(PdfViewWebPluginTest, CaretChangeUseZoomForDSFEnabled) {
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(true));
+TEST_F(PdfViewWebPluginTest, CaretChange) {
   EXPECT_CALL(*engine_ptr_, ZoomUpdated(2.0f));
   UpdatePluginGeometry(
       /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(12, 24, 36, 48));
@@ -960,16 +853,6 @@
   EXPECT_EQ(gfx::Rect(28, 20, 30, 40), plugin_->GetPluginCaretBounds());
 }
 
-TEST_F(PdfViewWebPluginTest, CaretChangeUseZoomForDSFDisabled) {
-  EXPECT_CALL(*client_ptr_, IsUseZoomForDSFEnabled)
-      .WillRepeatedly(Return(false));
-  EXPECT_CALL(*engine_ptr_, ZoomUpdated(2.0f));
-  UpdatePluginGeometry(
-      /*device_scale=*/2.0f, /*window_rect=*/gfx::Rect(12, 24, 36, 48));
-  plugin_->CaretChanged(gfx::Rect(10, 20, 30, 40));
-  EXPECT_EQ(gfx::Rect(23, 10, 15, 20), plugin_->GetPluginCaretBounds());
-}
-
 TEST_F(PdfViewWebPluginTest, NotifyNumberOfFindResultsChanged) {
   plugin_->StartFind("x", /*case_sensitive=*/false, /*identifier=*/123);
 
diff --git a/printing/backend/printing_restrictions.h b/printing/backend/printing_restrictions.h
index 44f4587..365f04d 100644
--- a/printing/backend/printing_restrictions.h
+++ b/printing/backend/printing_restrictions.h
@@ -29,7 +29,7 @@
 
 // Dictionary key for printing policies.
 // Must coincide with the name of field in `print_preview.Policies` in
-// chrome/browser/resources/print_preview/data/destination.js
+// chrome/browser/resources/print_preview/data/destination.ts
 COMPONENT_EXPORT(PRINT_BACKEND) extern const char kAllowedColorModes[];
 COMPONENT_EXPORT(PRINT_BACKEND) extern const char kAllowedDuplexModes[];
 COMPONENT_EXPORT(PRINT_BACKEND) extern const char kAllowedPinModes[];
diff --git a/printing/mojom/print.mojom b/printing/mojom/print.mojom
index 5ef087c..b0f32d7 100644
--- a/printing/mojom/print.mojom
+++ b/printing/mojom/print.mojom
@@ -146,10 +146,10 @@
 };
 
 // Matches print_preview.PrinterType in
-// chrome/browser/resources/print_preview/data/destination_match.js
+// chrome/browser/resources/print_preview/data/destination_match.ts
 [Stable, Extensible]
 enum PrinterType {
-  kPrivet,
+  kPrivetDeprecated,
   kExtension,
   kPdf,
   kLocal,
diff --git a/printing/print_job_constants.h b/printing/print_job_constants.h
index 1df500ee..b54dbd92 100644
--- a/printing/print_job_constants.h
+++ b/printing/print_job_constants.h
@@ -179,7 +179,7 @@
 enum VerticalHeaderFooterPosition { TOP, BOTTOM };
 
 // Must match print_preview.ScalingType in
-// chrome/browser/resources/print_preview/data/scaling.js
+// chrome/browser/resources/print_preview/data/scaling.ts
 enum ScalingType {
   DEFAULT,
   FIT_TO_PAGE,
diff --git a/printing/printing_context.cc b/printing/printing_context.cc
index 3d8281c8a..aacb466 100644
--- a/printing/printing_context.cc
+++ b/printing/printing_context.cc
@@ -133,14 +133,17 @@
 
   mojom::PrinterType printer_type = static_cast<mojom::PrinterType>(
       job_settings.FindIntKey(kSettingPrinterType).value());
-  bool print_with_privet = printer_type == mojom::PrinterType::kPrivet;
+  if (printer_type == mojom::PrinterType::kPrivetDeprecated) {
+    NOTREACHED();
+    return OnError();
+  }
+
   bool print_to_cloud = !!job_settings.FindKey(kSettingCloudPrintId);
   bool open_in_external_preview =
       !!job_settings.FindKey(kSettingOpenPDFInPreview);
 
   if (!open_in_external_preview &&
-      (print_to_cloud || print_with_privet ||
-       printer_type == mojom::PrinterType::kPdf ||
+      (print_to_cloud || printer_type == mojom::PrinterType::kPdf ||
        printer_type == mojom::PrinterType::kCloud ||
        printer_type == mojom::PrinterType::kExtension)) {
     settings_->set_dpi(kDefaultPdfDpi);
@@ -156,7 +159,7 @@
                         device_microns_per_device_unit);
     }
     gfx::Rect paper_rect(0, 0, paper_size.width(), paper_size.height());
-    if (print_to_cloud || print_with_privet) {
+    if (print_to_cloud) {
       paper_rect.Inset(
           kCloudPrintMarginInch * settings_->device_units_per_inch(),
           kCloudPrintMarginInch * settings_->device_units_per_inch());
diff --git a/remoting/BUILD.gn b/remoting/BUILD.gn
index 6e3fcad..a1770e31 100644
--- a/remoting/BUILD.gn
+++ b/remoting/BUILD.gn
@@ -150,7 +150,7 @@
   }
 
   # TODO(crbug.com/1052397): Change to !is_chromeos once lacros-chrome is switched to target_os=chromeos.
-  if (!is_chromeos_ash && !is_chromeos_lacros) {
+  if (!is_chromeos) {
     deps += [ "//remoting/client/display:unit_tests" ]
   }
 }
diff --git a/remoting/client/BUILD.gn b/remoting/client/BUILD.gn
index 89b43ae5..4915ef5 100644
--- a/remoting/client/BUILD.gn
+++ b/remoting/client/BUILD.gn
@@ -66,7 +66,7 @@
 
   libs = []
 
-  if (!is_chromeos_ash && !is_chromeos_lacros) {
+  if (!is_chromeos) {
     # GestureInterpreter depends on //remoting/client/display, which currently
     # doesn't build on CrOS. crbug.com/869578
     sources += [
diff --git a/remoting/client/ui/BUILD.gn b/remoting/client/ui/BUILD.gn
index 08b336d..8338d3c 100644
--- a/remoting/client/ui/BUILD.gn
+++ b/remoting/client/ui/BUILD.gn
@@ -22,7 +22,7 @@
     "//third_party/webrtc_overrides:webrtc_component",
   ]
 
-  if (!is_chromeos_ash && !is_chromeos_lacros) {
+  if (!is_chromeos) {
     deps += [ "//remoting/client/display" ]
   }
 }
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 22ebcbc1..4f9efe2 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -25,7 +25,7 @@
     deps += [ ":remoting_host_branded" ]
   }
 
-  if (!is_chromeos_ash && !is_chromeos_lacros && !is_android && !is_ios) {
+  if (!is_chromeos && !is_android && !is_ios) {
     deps += [
       "//remoting/host:remoting_native_messaging_host",
       "//remoting/host:remoting_native_messaging_manifests",
@@ -487,8 +487,7 @@
     }
   }
 
-  if (is_linux &&
-      (!remoting_use_x11 || is_chromeos_ash || is_chromeos_lacros)) {
+  if (is_linux && (!remoting_use_x11 || is_chromeos)) {
     # On Linux, exactly one of desktop_resizer_{linux,x11}.cc should be
     # compiled in. The _linux version is a no-op and should be used on
     # platforms without X11.
diff --git a/remoting/host/it2me/BUILD.gn b/remoting/host/it2me/BUILD.gn
index 5e95b6aa..476ef83 100644
--- a/remoting/host/it2me/BUILD.gn
+++ b/remoting/host/it2me/BUILD.gn
@@ -123,7 +123,7 @@
   }
 }
 
-if (is_chromeos_ash || is_chromeos_lacros) {
+if (is_chromeos) {
   source_set("chrome_os_host") {
     sources = [
       "it2me_native_messaging_host_allowed_origins.cc",
diff --git a/remoting/host/linux/BUILD.gn b/remoting/host/linux/BUILD.gn
index eb85c1a4..f256444d 100644
--- a/remoting/host/linux/BUILD.gn
+++ b/remoting/host/linux/BUILD.gn
@@ -103,7 +103,7 @@
   }
 }
 
-if (!is_chromeos_ash && !is_chromeos_lacros) {
+if (!is_chromeos) {
   executable("remoting_native_messaging_host") {
     configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
diff --git a/remoting/remoting_locales.gni b/remoting/remoting_locales.gni
index ae04369..5397a718 100644
--- a/remoting/remoting_locales.gni
+++ b/remoting/remoting_locales.gni
@@ -72,7 +72,7 @@
 # TODO(yuweih): Our build script doesn't seem to work with en-US and Chrome
 # on iOS doesn't seem to have en-US.lproj. Add is_ios back if we do need to
 # work with en-US.
-if (is_chromeos_ash || is_chromeos_lacros) {
+if (is_chromeos) {
   # Support Icelandic in ChromeOS
   remoting_locales_without_pseudolocales += [
     "af",
diff --git a/services/data_decoder/public/mojom/BUILD.gn b/services/data_decoder/public/mojom/BUILD.gn
index af95b981..60b9cb1 100644
--- a/services/data_decoder/public/mojom/BUILD.gn
+++ b/services/data_decoder/public/mojom/BUILD.gn
@@ -25,7 +25,7 @@
     "//url/mojom:url_mojom_gurl",
   ]
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [ "ble_scan_parser.mojom" ]
     public_deps += [ "//device/bluetooth/public/mojom" ]
   }
diff --git a/services/device/usb/BUILD.gn b/services/device/usb/BUILD.gn
index 1cde7fa..952e013 100644
--- a/services/device/usb/BUILD.gn
+++ b/services/device/usb/BUILD.gn
@@ -159,7 +159,7 @@
     ]
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     deps += [
       "//chromeos/dbus/permission_broker",
       "//dbus",
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 775d697..ad863b3d 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -29,6 +29,7 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "build/chromecast_buildflags.h"
 #include "build/chromeos_buildflags.h"
@@ -428,7 +429,8 @@
   // Path to a data file should always be a plain filename.
   DCHECK_EQ(relative_file_path->BaseName(), *relative_file_path);
 
-  full_path = file_paths->data_directory.Append(relative_file_path->value());
+  full_path =
+      file_paths->data_directory.path().Append(relative_file_path->value());
   return true;
 }
 
@@ -483,6 +485,16 @@
            "the network service.";
   }
 #endif  // BUILDFLAG(IS_WIN) && DCHECK_IS_ON()
+
+#if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+  if (params_->file_paths) {
+    EnsureMounted(&params_->file_paths->data_directory);
+  }
+  if (params_->http_cache_directory) {
+    EnsureMounted(&*params_->http_cache_directory);
+  }
+#endif  // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
   mojo::PendingRemote<mojom::URLLoaderFactory>
       url_loader_factory_for_cert_net_fetcher;
   mojo::PendingReceiver<mojom::URLLoaderFactory>
@@ -650,6 +662,20 @@
     }
   }
 #endif
+
+#if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+  if (!dismount_closures_.empty()) {
+    // Dismount all mounted directories after a generous delay, so that
+    // pending asynchronous IO tasks have a chance to complete before the
+    // directory is unmounted.
+    constexpr base::TimeDelta kDismountDelay = base::Minutes(5);
+
+    for (auto& dismount_closure : dismount_closures_) {
+      std::ignore = base::ThreadPool::PostDelayedTask(
+          FROM_HERE, std::move(dismount_closure), kDismountDelay);
+    }
+  }
+#endif  // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
 }
 
 // static
@@ -2403,7 +2429,7 @@
       cache_params.type =
           net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY;
     } else {
-      cache_params.path = *params_->http_cache_directory;
+      cache_params.path = params_->http_cache_directory->path();
       cache_params.type = network_session_configurator::ChooseCacheType();
     }
     cache_params.reset_cache = params_->reset_http_cache_backend;
@@ -2833,6 +2859,14 @@
 }
 #endif
 
+#if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+void NetworkContext::EnsureMounted(network::TransferableDirectory* directory) {
+  if (directory->NeedsMount()) {
+    dismount_closures_.push_back(directory->Mount());
+  }
+}
+#endif  // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
 void NetworkContext::InitializeCorsParams() {
   for (const auto& pattern : params_->cors_origin_access_list) {
     cors_origin_access_list_.SetAllowListForOrigin(pattern->source_origin,
diff --git a/services/network/network_context.h b/services/network/network_context.h
index b626831..53e3f293 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -48,6 +48,7 @@
 #include "services/network/origin_policy/origin_policy_manager.h"
 #include "services/network/public/cpp/cors/origin_access_list.h"
 #include "services/network/public/cpp/network_service_buildflags.h"
+#include "services/network/public/cpp/transferable_directory.h"
 #include "services/network/public/mojom/cookie_access_observer.mojom.h"
 #include "services/network/public/mojom/cookie_manager.mojom-shared.h"
 #include "services/network/public/mojom/host_resolver.mojom.h"
@@ -685,6 +686,10 @@
       const net::NetworkIsolationKey& network_isolation_key);
 #endif  // BUILDFLAG(IS_CT_SUPPORTED)
 
+#if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+  void EnsureMounted(network::TransferableDirectory* directory);
+#endif  // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
   void InitializeCorsParams();
 
   // If |trust_token_store_| is backed by an asynchronously-constructed (e.g.,
@@ -816,6 +821,12 @@
   CertVerifierWithTrustAnchors* cert_verifier_with_trust_anchors_ = nullptr;
 #endif
 
+#if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+  // Contains a list of closures that, when run, will dismount the shared
+  // directories used by this NetworkClosure.
+  std::vector<base::OnceClosure> dismount_closures_;
+#endif  // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
   // CertNetFetcher used by the context's CertVerifier. May be nullptr if
   // CertNetFetcher is not used by the current platform, or if the actual
   // net::CertVerifier is instantiated outside of the network service.
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 73e73e70..3e98493 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -1112,6 +1112,86 @@
   ASSERT_TRUE(temp_dir.Delete());
 }
 
+#if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
+TEST_F(NetworkContextTest, DataDirectoryAsHandle) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath file_path = temp_dir.GetPath().AppendASCII("foo");
+  ASSERT_TRUE(base::CreateDirectory(file_path.DirName()));
+
+  const url::SchemeHostPort kSchemeHostPort("https", "foo", 443);
+
+  // Create a context with on-disk storage of HTTP server properties.
+  mojom::NetworkContextParamsPtr context_params =
+      CreateNetworkContextParamsForTesting();
+  context_params->file_paths = mojom::NetworkContextFilePaths::New();
+
+  // Make |data_directory| into a path-less directory handle.
+  // Moving a TransferableDirectory once it's been opened will drop the
+  // path from the original.
+  context_params->file_paths->data_directory =
+      TransferableDirectory(file_path.DirName());
+  context_params->file_paths->data_directory.OpenForTransfer();
+  EXPECT_TRUE(context_params->file_paths->data_directory.NeedsMount());
+
+  context_params->file_paths->http_server_properties_file_name =
+      file_path.BaseName();
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(std::move(context_params));
+
+  // Wait for properties to load from disk, and sanity check initial state.
+  task_environment_.RunUntilIdle();
+  EXPECT_FALSE(
+      network_context->url_request_context()
+          ->http_server_properties()
+          ->GetSupportsSpdy(kSchemeHostPort, net::NetworkIsolationKey()));
+
+  // Set a property.
+  network_context->url_request_context()
+      ->http_server_properties()
+      ->SetSupportsSpdy(kSchemeHostPort, net::NetworkIsolationKey(), true);
+  // Deleting the context will cause it to flush state. Wait for the pref
+  // service to flush to disk.
+  network_context.reset();
+  task_environment_.RunUntilIdle();
+
+  // Create a new NetworkContext using the same path for HTTP server properties.
+  context_params = CreateNetworkContextParamsForTesting();
+  context_params->file_paths = mojom::NetworkContextFilePaths::New();
+  context_params->file_paths->data_directory = file_path.DirName();
+  context_params->file_paths->http_server_properties_file_name =
+      file_path.BaseName();
+  network_context = CreateContextWithParams(std::move(context_params));
+
+  // Wait for properties to load from disk.
+  task_environment_.RunUntilIdle();
+
+  EXPECT_TRUE(
+      network_context->url_request_context()
+          ->http_server_properties()
+          ->GetSupportsSpdy(kSchemeHostPort, net::NetworkIsolationKey()));
+
+  // Now check that ClearNetworkingHistoryBetween clears the data.
+  base::RunLoop run_loop2;
+  network_context->ClearNetworkingHistoryBetween(
+      base::Time::Now() - base::Hours(1), base::Time::Max(),
+      run_loop2.QuitClosure());
+  run_loop2.Run();
+  EXPECT_FALSE(
+      network_context->url_request_context()
+          ->http_server_properties()
+          ->GetSupportsSpdy(kSchemeHostPort, net::NetworkIsolationKey()));
+
+  // Destroy the network context and let any pending writes complete before
+  // destroying |temp_dir|, to avoid leaking any files.
+  network_context.reset();
+  task_environment_.RunUntilIdle();
+  ASSERT_TRUE(temp_dir.Delete());
+}
+
+#endif  // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
 // Checks that ClearNetworkingHistoryBetween() clears in-memory pref stores and
 // invokes the closure passed to it.
 TEST_F(NetworkContextTest, ClearHttpServerPropertiesInMemory) {
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
index 22f521a4..07fa37a7 100644
--- a/services/network/network_service.cc
+++ b/services/network/network_service.cc
@@ -450,6 +450,12 @@
 
   if (doh_probe_activator_)
     doh_probe_activator_->MaybeActivateDohProbes(network_context);
+
+#if BUILDFLAG(IS_CT_SUPPORTED)
+  network_context->url_request_context()
+      ->transport_security_state()
+      ->SetCTEmergencyDisabled(!ct_enforcement_enabled_);
+#endif  // BUILDFLAG(IS_CT_SUPPORTED)
 }
 
 void NetworkService::DeregisterNetworkContext(NetworkContext* network_context) {
@@ -733,13 +739,14 @@
 }
 
 void NetworkService::SetCtEnforcementEnabled(bool enabled) {
+  ct_enforcement_enabled_ = enabled;
   DCHECK(base::FeatureList::IsEnabled(
       certificate_transparency::features::
           kCertificateTransparencyComponentUpdater));
   for (auto* context : network_contexts_) {
     context->url_request_context()
         ->transport_security_state()
-        ->SetCTEmergencyDisabled(!enabled);
+        ->SetCTEmergencyDisabled(!ct_enforcement_enabled_);
   }
 }
 
diff --git a/services/network/network_service.h b/services/network/network_service.h
index f8b7275..10ced5a 100644
--- a/services/network/network_service.h
+++ b/services/network/network_service.h
@@ -276,6 +276,10 @@
   base::Time ct_log_list_update_time() const {
     return ct_log_list_update_time_;
   }
+
+  bool is_ct_enforcement_enabled_for_testing() const {
+    return ct_enforcement_enabled_;
+  }
 #endif
 
   bool pins_list_updated() const { return pins_list_updated_; }
@@ -411,6 +415,8 @@
   std::unique_ptr<CtLogListDistributor> ct_log_list_distributor_;
 
   base::Time ct_log_list_update_time_;
+
+  bool ct_enforcement_enabled_ = true;
 #endif
 
   bool pins_list_updated_ = false;
diff --git a/services/network/network_service_unittest.cc b/services/network/network_service_unittest.cc
index 15197c4e..bb0f5f7 100644
--- a/services/network/network_service_unittest.cc
+++ b/services/network/network_service_unittest.cc
@@ -42,6 +42,7 @@
 #include "net/http/http_auth_scheme.h"
 #include "net/http/http_network_session.h"
 #include "net/http/http_transaction_factory.h"
+#include "net/http/transport_security_state.h"
 #include "net/net_buildflags.h"
 #include "net/socket/client_socket_pool_manager.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -954,6 +955,32 @@
   service()->SetMaxConnectionsPerProxy(kDefault);
 }
 
+#if BUILDFLAG(IS_CT_SUPPORTED)
+// Tests that disabling CT enforcement disables the feature for both existing
+// and new network contexts.
+TEST_F(NetworkServiceTest, DisableCTEnforcement) {
+  mojo::Remote<mojom::NetworkContext> network_context_remote;
+  NetworkContext network_context(
+      service(), network_context_remote.BindNewPipeAndPassReceiver(),
+      CreateContextParams());
+  net::TransportSecurityState* transport_security_state =
+      network_context.url_request_context()->transport_security_state();
+  EXPECT_FALSE(
+      transport_security_state->is_ct_emergency_disabled_for_testing());
+
+  service()->SetCtEnforcementEnabled(false);
+  EXPECT_TRUE(transport_security_state->is_ct_emergency_disabled_for_testing());
+
+  mojo::Remote<mojom::NetworkContext> new_network_context_remote;
+  NetworkContext new_network_context(
+      service(), new_network_context_remote.BindNewPipeAndPassReceiver(),
+      CreateContextParams());
+  transport_security_state =
+      new_network_context.url_request_context()->transport_security_state();
+  EXPECT_TRUE(transport_security_state->is_ct_emergency_disabled_for_testing());
+}
+#endif  // BUILDFLAG(IS_CT_SUPPORTED)
+
 class NetworkServiceTestWithService : public testing::Test {
  public:
   NetworkServiceTestWithService()
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn
index b5a296e..2d68387 100644
--- a/services/network/public/cpp/BUILD.gn
+++ b/services/network/public/cpp/BUILD.gn
@@ -7,11 +7,13 @@
 import("//services/network/public/cpp/features.gni")
 import("//testing/libfuzzer/fuzzer_test.gni")
 
+_is_directory_transfer_required = is_fuchsia
 buildflag_header("buildflags") {
   header = "network_service_buildflags.h"
   flags = [
     "IS_CT_SUPPORTED=$is_ct_supported",
     "IS_P2P_ENABLED=$is_p2p_enabled",
+    "IS_DIRECTORY_TRANSFER_REQUIRED=$_is_directory_transfer_required",
   ]
 }
 
@@ -157,6 +159,7 @@
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
   public_deps = [
+    ":buildflags",
     ":cpp_base",
     "//net",
     "//services/network/public/mojom",
@@ -313,6 +316,8 @@
     "resource_request.h",
     "resource_request_body.cc",
     "resource_request_body.h",
+    "transferable_directory.cc",
+    "transferable_directory.h",
     "trust_token_parameterization.h",
     "url_loader_completion_status.cc",
     "url_loader_completion_status.h",
@@ -342,6 +347,7 @@
     "//url/mojom:url_mojom_origin",
   ]
   deps = [
+    ":buildflags",
     "//base",
     "//ipc",
     "//mojo/public/mojom/base",
@@ -361,6 +367,10 @@
     public_deps += [ "//third_party/webrtc_overrides:webrtc_component" ]
   }
 
+  if (is_fuchsia) {
+    sources += [ "transferable_directory_fuchsia.cc" ]
+  }
+
   # Since URLLoader is typedmapped in mojo and the class also uses the mojo
   # interfaces a circular dependency exists. Allow this and ignore windows
   # errors from it.
@@ -440,6 +450,7 @@
     "source_stream_to_data_pipe_unittest.cc",
     "supports_loading_mode/supports_loading_mode_parser_unittest.cc",
     "timing_allow_origin_parser_unittest.cc",
+    "transferable_directory_unittest.cc",
     "url_loader_completion_status_mojom_traits_unittest.cc",
     "url_request_mojom_traits_unittest.cc",
     "web_sandbox_flags_unittests.cc",
diff --git a/services/network/public/cpp/transferable_directory.cc b/services/network/public/cpp/transferable_directory.cc
new file mode 100644
index 0000000..db66c0a
--- /dev/null
+++ b/services/network/public/cpp/transferable_directory.cc
@@ -0,0 +1,88 @@
+// 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 "services/network/public/cpp/transferable_directory.h"
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "services/network/public/cpp/network_service_buildflags.h"
+
+namespace network {
+
+TransferableDirectory::TransferableDirectory() = default;
+
+TransferableDirectory::TransferableDirectory(TransferableDirectory&& other) {
+  *this = std::move(other);
+}
+
+TransferableDirectory::TransferableDirectory(const base::FilePath& path)
+    : path_(path) {}
+
+TransferableDirectory::TransferableDirectory(mojo::PlatformHandle handle)
+    : handle_(std::move(handle)) {}
+
+TransferableDirectory::~TransferableDirectory() = default;
+
+void TransferableDirectory::operator=(TransferableDirectory&& other) {
+  if (other.HasValidHandle()) {
+    handle_ = other.TakeHandle();
+    path_ = {};
+  } else {
+    handle_ = {};
+    path_ = other.path();
+  }
+}
+
+void TransferableDirectory::operator=(const base::FilePath& path) {
+  // Path cannot be mutated if OpenForTransfer() was called.
+  DCHECK(!HasValidHandle());
+
+  path_ = path;
+}
+
+const base::FilePath& TransferableDirectory::path() const {
+  return path_;
+}
+
+void TransferableDirectory::ClearPath() {
+  path_ = {};
+}
+
+// static
+bool TransferableDirectory::IsOpenForTransferRequired() {
+#if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool TransferableDirectory::NeedsMount() const {
+  if (HasValidHandle()) {
+    return true;
+  }
+  return false;
+}
+
+mojo::PlatformHandle TransferableDirectory::TakeHandle() {
+  DCHECK(HasValidHandle());
+
+  mojo::PlatformHandle output;
+  std::swap(handle_, output);
+  return output;
+}
+
+#if !BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
+void TransferableDirectory::OpenForTransfer() {
+  NOTREACHED() << "Directory transfer not supported on this platform.";
+}
+
+[[nodiscard]] base::OnceClosure TransferableDirectory::Mount() {
+  NOTREACHED() << "Directory transfer not supported on this platform.";
+  return {};
+}
+
+#endif  // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
+}  // namespace network
diff --git a/services/network/public/cpp/transferable_directory.h b/services/network/public/cpp/transferable_directory.h
new file mode 100644
index 0000000..8e92856
--- /dev/null
+++ b/services/network/public/cpp/transferable_directory.h
@@ -0,0 +1,104 @@
+// 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 SERVICES_NETWORK_PUBLIC_CPP_TRANSFERABLE_DIRECTORY_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_TRANSFERABLE_DIRECTORY_H_
+
+#include "base/callback_helpers.h"
+#include "base/component_export.h"
+#include "base/files/file_path.h"
+#include "mojo/public/cpp/bindings/union_traits.h"
+#include "mojo/public/cpp/platform/platform_handle.h"
+
+namespace network {
+class TransferableDirectory;
+}
+namespace network::mojom {
+class TransferableDirectoryDataView;
+}
+namespace mojo {
+template <>
+struct UnionTraits<network::mojom::TransferableDirectoryDataView,
+                   network::TransferableDirectory>;
+}
+
+namespace network {
+
+// Represents a directory that, on some platforms, can be sent as a handle
+// across process boundaries to be later mounted to a process-local path.
+//
+// Platforms which use the same filesystem across process boundaries can simply
+// use the path as-is, with no handle marshaling steps required.
+//
+// Example usage:
+//  SENDER:
+//   TransferableDirectory dir = base::FilePath("/dir/to/share");
+//   if (dir.IsOpenForTransferRequired())
+//     dir.OpenForTransfer();
+//   mojo_client->UseDirectory(std::move(dir));
+//
+//  RECEIVER:
+//   AutoClosureRunner dismounter;
+//   if (dir.NeedsMount())
+//     dismounter = AutoClosureRunner(dir.Mount());
+//
+//   base::File file(dir.path().Append("shared_file.txt"));
+//   ...use |file| normally...
+class COMPONENT_EXPORT(NETWORK_CPP_BASE) TransferableDirectory {
+ public:
+  TransferableDirectory();
+  explicit TransferableDirectory(const base::FilePath& path);
+  TransferableDirectory(TransferableDirectory&& other);
+  ~TransferableDirectory();
+
+  void operator=(TransferableDirectory&& other);
+  void operator=(const base::FilePath& path);
+
+  const base::FilePath& path() const;
+  void ClearPath();
+
+  static bool IsOpenForTransferRequired();
+
+  // Gets a directory handle for |path_| to be sent over Mojo.
+  // Call may block, so should be called on an IO thread.
+  // Should be prefaced with a check against IsOpenForTransferRequired().
+  void OpenForTransfer();
+
+  // Returns true if |this| contains a handle that needs to be mounted before
+  // the path can be accessed.
+  bool NeedsMount() const;
+
+  // Mounts |handle_| to a location on the filesystem.
+  // Should be prefaced with a check against NeedsMount().
+  // Returns a task that, when run, will dismount the directory.
+  // The task should not be run while I/O is occurring to the directory from
+  // any thread.
+  // Deleting the task should not unmount the directory, so that during
+  // shutdown the unmounting can be skipped with no adverse effects.
+  [[nodiscard]] base::OnceClosure Mount();
+
+ private:
+  friend struct mojo::UnionTraits<network::mojom::TransferableDirectoryDataView,
+                                  network::TransferableDirectory>;
+
+  // Handle manipulation calls, hidden from callers and only surfaced to
+  // UnionTraits.
+  explicit TransferableDirectory(mojo::PlatformHandle handle);
+  bool HasValidHandle() const { return handle_.is_valid(); }
+  mojo::PlatformHandle TakeHandle();
+
+  // The path to the source directory for the producer, or the mounted location
+  // for the consumer.  Initially empty on the consumer unitil Mount() is
+  // called.
+  base::FilePath path_;
+
+  // Contains a handle to the directory, populated by calling OpenForTransfer()
+  // just prior to sending over Mojo.  On the directory consumer, calling
+  // Mount() will mount |handle_| at |path_|, and |handle_| will be cleared.
+  mojo::PlatformHandle handle_;
+};
+
+}  // namespace network
+
+#endif  // SERVICES_NETWORK_PUBLIC_CPP_TRANSFERABLE_DIRECTORY_H_
diff --git a/services/network/public/cpp/transferable_directory_fuchsia.cc b/services/network/public/cpp/transferable_directory_fuchsia.cc
new file mode 100644
index 0000000..5e0e9fc
--- /dev/null
+++ b/services/network/public/cpp/transferable_directory_fuchsia.cc
@@ -0,0 +1,55 @@
+// 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 <lib/fdio/namespace.h>
+
+#include "base/check.h"
+#include "base/files/file_util.h"
+#include "base/fuchsia/file_utils.h"
+#include "base/fuchsia/fuchsia_logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/unguessable_token.h"
+#include "services/network/public/cpp/transferable_directory.h"
+
+namespace network {
+namespace {
+
+fdio_ns_t* GetNamespace() {
+  fdio_ns_t* global_namespace = nullptr;
+  zx_status_t status = fdio_ns_get_installed(&global_namespace);
+  ZX_CHECK(status == ZX_OK, status) << "fdio_ns_get_installed";
+  return global_namespace;
+}
+
+}  // namespace
+
+void TransferableDirectory::OpenForTransfer() {
+  handle_ = mojo::PlatformHandle(
+      base::OpenWritableDirectoryHandle(path_).TakeChannel());
+}
+
+[[nodiscard]] base::OnceClosure TransferableDirectory::Mount() {
+  DCHECK(NeedsMount());
+
+  constexpr char kMountFormatString[] = "/sandbox-mnt/%s";
+  path_ = base::FilePath(base::StringPrintf(
+      kMountFormatString, base::UnguessableToken::Create().ToString().c_str()));
+  CHECK(!base::PathExists(path_));
+
+  zx_status_t status = fdio_ns_bind(GetNamespace(), path_.value().data(),
+                                    handle_.ReleaseHandle());
+  ZX_CHECK(status == ZX_OK, status) << "fdio_ns_bind";
+  handle_ = {};
+  DCHECK(base::PathExists(path_));
+
+  return base::BindOnce(
+      [](base::FilePath path) {
+        zx_status_t status =
+            fdio_ns_unbind(GetNamespace(), path.value().data());
+        ZX_CHECK(status == ZX_OK, status) << "fdio_ns_unbind";
+      },
+      path_);
+}
+
+}  // namespace network
diff --git a/services/network/public/cpp/transferable_directory_mojom_traits.cc b/services/network/public/cpp/transferable_directory_mojom_traits.cc
new file mode 100644
index 0000000..e26949d
--- /dev/null
+++ b/services/network/public/cpp/transferable_directory_mojom_traits.cc
@@ -0,0 +1,54 @@
+// 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 "services/network/public/cpp/transferable_directory_mojom_traits.h"
+
+#include "mojo/public/cpp/base/file_path_mojom_traits.h"
+
+namespace mojo {
+
+network::mojom::TransferableDirectoryDataView::Tag UnionTraits<
+    network::mojom::TransferableDirectoryDataView,
+    network::TransferableDirectory>::GetTag(network::TransferableDirectory&
+                                                input) {
+  if (input.HasValidHandle()) {
+    return network::mojom::TransferableDirectoryDataView::Tag::HANDLE_FOR_IPC;
+  } else {
+    return network::mojom::TransferableDirectoryDataView::Tag::PATH;
+  }
+}
+
+base::FilePath UnionTraits<network::mojom::TransferableDirectoryDataView,
+                           network::TransferableDirectory>::
+    path(const network::TransferableDirectory& value) {
+  return value.path();
+}
+
+mojo::PlatformHandle UnionTraits<network::mojom::TransferableDirectoryDataView,
+                                 network::TransferableDirectory>::
+    handle_for_ipc(network::TransferableDirectory& value) {
+  return value.TakeHandle();
+}
+
+bool UnionTraits<network::mojom::TransferableDirectoryDataView,
+                 network::TransferableDirectory>::
+    Read(network::mojom::TransferableDirectoryDataView in,
+         network::TransferableDirectory* out) {
+  switch (in.tag()) {
+    case network::mojom::TransferableDirectoryDataView::Tag::HANDLE_FOR_IPC:
+      *out = network::TransferableDirectory(in.TakeHandleForIpc());
+      return true;
+
+    case network::mojom::TransferableDirectoryDataView::Tag::PATH: {
+      base::FilePath path;
+      if (!in.ReadPath(&path)) {
+        return false;
+      }
+      *out = network::TransferableDirectory(path);
+      return true;
+    }
+  }
+}
+
+}  // namespace mojo
diff --git a/services/network/public/cpp/transferable_directory_mojom_traits.h b/services/network/public/cpp/transferable_directory_mojom_traits.h
new file mode 100644
index 0000000..42fb7e44
--- /dev/null
+++ b/services/network/public/cpp/transferable_directory_mojom_traits.h
@@ -0,0 +1,29 @@
+// 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 SERVICES_NETWORK_PUBLIC_CPP_TRANSFERABLE_DIRECTORY_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_TRANSFERABLE_DIRECTORY_MOJOM_TRAITS_H_
+
+#include "mojo/public/cpp/bindings/union_traits.h"
+#include "net/http/http_auth_preferences.h"
+#include "services/network/public/cpp/transferable_directory.h"
+#include "services/network/public/mojom/transferable_directory.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct UnionTraits<network::mojom::TransferableDirectoryDataView,
+                   network::TransferableDirectory> {
+  static network::mojom::TransferableDirectoryDataView::Tag GetTag(
+      network::TransferableDirectory& input);
+  static base::FilePath path(const network::TransferableDirectory& value);
+  static mojo::PlatformHandle handle_for_ipc(
+      network::TransferableDirectory& value);
+  static bool Read(network::mojom::TransferableDirectoryDataView in,
+                   network::TransferableDirectory* out);
+};
+
+}  // namespace mojo
+
+#endif  // SERVICES_NETWORK_PUBLIC_CPP_TRANSFERABLE_DIRECTORY_MOJOM_TRAITS_H_
diff --git a/services/network/public/cpp/transferable_directory_unittest.cc b/services/network/public/cpp/transferable_directory_unittest.cc
new file mode 100644
index 0000000..37c91d8
--- /dev/null
+++ b/services/network/public/cpp/transferable_directory_unittest.cc
@@ -0,0 +1,150 @@
+// 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 "services/network/public/cpp/transferable_directory.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
+#include "services/network/public/cpp/network_service_buildflags.h"
+#include "services/network/public/mojom/transferable_directory.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+namespace {
+
+using TransferableDirectoryTest = testing::Test;
+
+const base::FilePath kDirPath(FILE_PATH_LITERAL("/some/directory"));
+
+TEST_F(TransferableDirectoryTest, ManipulatePathOnly) {
+  // Initialize empty TransferableDirectory with path.
+  TransferableDirectory dir;
+  EXPECT_TRUE(dir.path().empty());
+  dir = kDirPath;
+  EXPECT_EQ(dir.path(), kDirPath);
+
+  // Reassign to path.
+  const base::FilePath kReassignedPath(FILE_PATH_LITERAL("/reassigned/path"));
+  dir = base::FilePath(kReassignedPath);
+  EXPECT_EQ(dir.path(), kReassignedPath);
+
+  // Reassign to another TransferableDirectory.
+  TransferableDirectory assigned;
+  assigned = std::move(dir);
+  EXPECT_EQ(assigned.path(), kReassignedPath);
+
+  // Construct with path.
+  TransferableDirectory constructed(kDirPath);
+  EXPECT_EQ(constructed.path(), kDirPath);
+}
+
+TEST_F(TransferableDirectoryTest, MojoTraitsWithPath) {
+  TransferableDirectory dir(kDirPath);
+  TransferableDirectory roundtripped;
+  ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::TransferableDirectory>(
+      dir, roundtripped));
+
+  EXPECT_EQ(dir.path(), roundtripped.path());
+}
+
+#if BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
+class TransferableDirectoryTestWithHandle : public testing::Test {
+ public:
+  TransferableDirectoryTestWithHandle() = default;
+  ~TransferableDirectoryTestWithHandle() override = default;
+
+  static constexpr char kFileFromParent[] = "from_parent";
+  static constexpr char kFileFromChild[] = "from_child";
+  static constexpr char kData[] = "yarr yee";
+
+  void SetUp() override {
+    // Create a temporary directory and publish a file into it.
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(
+        base::WriteFile(temp_dir_.GetPath().Append(kFileFromParent), kData));
+
+    // Construct a TransferableDirectory from the temp dir and prepare it for
+    // mounting.
+    transferable_temp_dir_ = TransferableDirectory(temp_dir_.GetPath());
+    EXPECT_TRUE(transferable_temp_dir_.IsOpenForTransferRequired());
+    EXPECT_FALSE(transferable_temp_dir_.NeedsMount());
+    transferable_temp_dir_.OpenForTransfer();
+    EXPECT_TRUE(transferable_temp_dir_.NeedsMount());
+  }
+
+ protected:
+  base::ScopedTempDir temp_dir_;
+  TransferableDirectory transferable_temp_dir_;
+};
+
+TEST_F(TransferableDirectoryTestWithHandle, OpenMountAndUnmount) {
+  {
+    // Mount the directory and verify that the parent-published file can be
+    // seen.
+    base::ScopedClosureRunner scoped_mount(transferable_temp_dir_.Mount());
+    EXPECT_NE(transferable_temp_dir_.path(), temp_dir_.GetPath());
+
+    EXPECT_TRUE(base::PathExists(transferable_temp_dir_.path()));
+    ASSERT_FALSE(transferable_temp_dir_.path().empty());
+    ASSERT_TRUE(base::PathExists(transferable_temp_dir_.path()));
+    EXPECT_TRUE(base::PathExists(
+        transferable_temp_dir_.path().Append(kFileFromParent)));
+
+    // Write a file into the directory, for the parent to see.
+    EXPECT_FALSE(
+        base::PathExists(transferable_temp_dir_.path().Append(kFileFromChild)));
+    ASSERT_TRUE(
+        base::WriteFile(temp_dir_.GetPath().Append(kFileFromChild), kData));
+    EXPECT_TRUE(
+        base::PathExists(transferable_temp_dir_.path().Append(kFileFromChild)));
+  }
+
+  // |scoped_mount| is no longer in scope, so verify that the directory was
+  // unmounted.
+  EXPECT_FALSE(base::PathExists(transferable_temp_dir_.path()));
+
+  // The child-published file should still be available in the original tempdir.
+  EXPECT_TRUE(base::PathExists(temp_dir_.GetPath().Append(kFileFromChild)));
+}
+
+TEST_F(TransferableDirectoryTestWithHandle, SupportsMoveAsHandle) {
+  // Mount the directory and verify that the published file exists.
+  TransferableDirectory moved_temp_dir = std::move(transferable_temp_dir_);
+  auto scoped_mount = moved_temp_dir.Mount();
+  EXPECT_TRUE(base::PathExists(moved_temp_dir.path()));
+  ASSERT_FALSE(moved_temp_dir.path().empty());
+  EXPECT_TRUE(base::PathExists(moved_temp_dir.path().Append(kFileFromParent)));
+}
+
+TEST_F(TransferableDirectoryTestWithHandle, MojoTraitsWithHandle) {
+  // Verify that the handle is preserved when transmitted using
+  // mojo::TransferableDirectory.
+  TransferableDirectory roundtripped;
+  ASSERT_TRUE(mojo::test::SerializeAndDeserialize<mojom::TransferableDirectory>(
+      transferable_temp_dir_, roundtripped));
+
+  auto scoped_mount = roundtripped.Mount();
+  ASSERT_TRUE(base::PathExists(roundtripped.path()));
+  EXPECT_TRUE(base::PathExists(roundtripped.path().Append(kFileFromParent)));
+}
+
+#else
+
+TEST_F(TransferableDirectoryTest, OpenAndMountNotSupportedForPlatform) {
+  const base::FilePath kDirPath(FILE_PATH_LITERAL("/some/directory"));
+  TransferableDirectory dir;
+  dir = kDirPath;
+  EXPECT_EQ(dir.path(), kDirPath);
+
+  EXPECT_FALSE(dir.IsOpenForTransferRequired());
+  EXPECT_FALSE(dir.NeedsMount());
+}
+
+#endif  // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
+}  // namespace
+}  // namespace network
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index 385094a..ecc3002 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -909,6 +909,7 @@
     "supports_loading_mode.mojom",
     "tcp_socket.mojom",
     "tls_socket.mojom",
+    "transferable_directory.mojom",
     "udp_socket.mojom",
     "url_loader_factory.mojom",
   ]
@@ -1077,6 +1078,21 @@
           [ "//services/network/public/cpp/net_log_mojom_traits.cc" ]
       traits_public_deps = [ "//net" ]
     },
+    {
+      types = [
+        {
+          mojom = "network.mojom.TransferableDirectory"
+          cpp = "::network::TransferableDirectory"
+          move_only = true
+        },
+      ]
+      traits_headers = [
+        "//services/network/public/cpp/transferable_directory_mojom_traits.h",
+      ]
+      traits_sources = [
+        "//services/network/public/cpp/transferable_directory_mojom_traits.cc",
+      ]
+    },
   ]
 
   if (enable_reporting) {
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 1089083..b2beaa76 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -43,6 +43,7 @@
 import "services/network/public/mojom/site_for_cookies.mojom";
 import "services/network/public/mojom/ssl_config.mojom";
 import "services/network/public/mojom/tcp_socket.mojom";
+import "services/network/public/mojom/transferable_directory.mojom";
 import "services/network/public/mojom/trust_tokens.mojom";
 import "services/network/public/mojom/udp_socket.mojom";
 import "services/network/public/mojom/url_loader.mojom";
@@ -206,7 +207,7 @@
   // since the sandboxed network service will have full access to this path.
   // This should be a different path for each different network context running
   // inside the network service.
-  mojo_base.mojom.FilePath data_directory;
+  TransferableDirectory data_directory;
 
   // Points to a path that might contain existing network service data files and
   // databases from network contexts created with the same `data_directory`.
@@ -340,7 +341,7 @@
   int32 http_cache_max_size = 0;
   // Points to the HTTP cache directory. Ignored if the cache is disabled.
   // If null and the cache is enabled, an in-memory database is used.
-  mojo_base.mojom.FilePath? http_cache_directory;
+  TransferableDirectory? http_cache_directory;
 
   // A factory to broker file operations needed for the HTTP cache on some
   // platforms (depending on the sandboxing mechanism the platform provides).
diff --git a/services/network/public/mojom/transferable_directory.mojom b/services/network/public/mojom/transferable_directory.mojom
new file mode 100644
index 0000000..7eb4ccc
--- /dev/null
+++ b/services/network/public/mojom/transferable_directory.mojom
@@ -0,0 +1,22 @@
+// 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.
+
+module network.mojom;
+
+import "mojo/public/mojom/base/file_path.mojom";
+import "mojo/public/mojom/base/values.mojom";
+
+// Represents a directory that, on platforms like Fuchsia, can be sent
+// over Mojo as a handle. On other platforms, the path will be used
+// directly on both ends.
+// Calling code should use the class network::TransferableDirectory instead
+// of directly manipulating this union.
+union TransferableDirectory {
+  // A handle to the directory, populated by the method
+  // network::TransferableDirectory::OpenForTransfer().
+  handle<platform> handle_for_ipc;
+
+  // The path to the directory.
+  mojo_base.mojom.FilePath path;
+};
diff --git a/services/shape_detection/BUILD.gn b/services/shape_detection/BUILD.gn
index b61237b..021d9288 100644
--- a/services/shape_detection/BUILD.gn
+++ b/services/shape_detection/BUILD.gn
@@ -5,7 +5,7 @@
 import("//build/config/chromeos/ui_mode.gni")
 import("//testing/test.gni")
 
-use_barhopper = is_chrome_branded && (is_chromeos_ash || is_chromeos_lacros)
+use_barhopper = is_chrome_branded && is_chromeos
 
 source_set("lib") {
   sources = [
diff --git a/services/shape_detection/public/mojom/BUILD.gn b/services/shape_detection/public/mojom/BUILD.gn
index 2a75d2d1..0ff9f37 100644
--- a/services/shape_detection/public/mojom/BUILD.gn
+++ b/services/shape_detection/public/mojom/BUILD.gn
@@ -22,7 +22,7 @@
   ]
 
   # Platforms except Chrome OS host shape detection in the GPU process.
-  if ((is_chromeos_ash || is_chromeos_lacros) && is_chrome_branded) {
+  if (is_chromeos && is_chrome_branded) {
     enabled_features = [ "has_shape_detection_utility" ]
   }
 }
diff --git a/sql/database_unittest.cc b/sql/database_unittest.cc
index 8c1db52..0ee1301 100644
--- a/sql/database_unittest.cc
+++ b/sql/database_unittest.cc
@@ -29,6 +29,7 @@
 #include "sql/test/database_test_peer.h"
 #include "sql/test/scoped_error_expecter.h"
 #include "sql/test/test_helpers.h"
+#include "sql/transaction.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/sqlite/sqlite3.h"
@@ -364,15 +365,6 @@
   EXPECT_EQ(12, s.ColumnInt(0));
 }
 
-TEST_P(SQLDatabaseTest, Rollback) {
-  ASSERT_TRUE(db_->BeginTransaction());
-  ASSERT_TRUE(db_->BeginTransaction());
-  EXPECT_EQ(2, db_->transaction_nesting());
-  db_->RollbackTransaction();
-  EXPECT_FALSE(db_->CommitTransaction());
-  EXPECT_TRUE(db_->BeginTransaction());
-}
-
 // Test the scoped error expecter by attempting to insert a duplicate
 // value into an index.
 TEST_P(SQLDatabaseTest, ScopedErrorExpecter) {
@@ -848,57 +840,61 @@
   ASSERT_EQ(0, SqliteSchemaCount(&other_db));
 }
 
-TEST_P(SQLDatabaseTest, RazeLocked) {
-  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
-  ASSERT_TRUE(db_->Execute(kCreateSql));
+TEST_P(SQLDatabaseTest, Raze_OtherConnectionHasWriteLock) {
+  ASSERT_TRUE(db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY)"));
 
-  // Open a transaction and write some data in a second connection.
-  // This will acquire a PENDING or EXCLUSIVE transaction, which will
-  // cause the raze to fail.
   Database other_db(GetDBOptions());
   ASSERT_TRUE(other_db.Open(db_path_));
-  ASSERT_TRUE(other_db.BeginTransaction());
-  const char* kInsertSql = "INSERT INTO foo VALUES (1, 'data')";
-  ASSERT_TRUE(other_db.Execute(kInsertSql));
 
-  ASSERT_FALSE(db_->Raze());
+  Transaction other_db_transaction(&other_db);
+  ASSERT_TRUE(other_db_transaction.Begin());
+  ASSERT_TRUE(other_db.Execute("INSERT INTO rows(id) VALUES(1)"));
 
-  // Works after COMMIT.
-  ASSERT_TRUE(other_db.CommitTransaction());
-  ASSERT_TRUE(db_->Raze());
+  EXPECT_FALSE(db_->Raze())
+      << "Raze() should fail while another connection has a write lock";
 
-  // Re-create the database.
-  ASSERT_TRUE(db_->Execute(kCreateSql));
-  ASSERT_TRUE(db_->Execute(kInsertSql));
-
-  // An unfinished read transaction in the other connection also
-  // blocks raze.
-  // This doesn't happen in WAL mode because reads are no longer blocked by
-  // write operations when using a WAL.
-  if (!IsWALEnabled()) {
-    const char* kQuery = "SELECT COUNT(*) FROM foo";
-    Statement s(other_db.GetUniqueStatement(kQuery));
-    ASSERT_TRUE(s.Step());
-    ASSERT_FALSE(db_->Raze());
-
-    // Completing the statement unlocks the database.
-    ASSERT_FALSE(s.Step());
-    ASSERT_TRUE(db_->Raze());
-  }
+  ASSERT_TRUE(other_db_transaction.Commit());
+  EXPECT_TRUE(db_->Raze())
+      << "Raze() should succeed after the other connection releases the lock";
 }
 
-// Verify that Raze() can handle an empty file.  SQLite should treat
-// this as an empty database.
-TEST_P(SQLDatabaseTest, RazeEmptyDB) {
-  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
-  ASSERT_TRUE(db_->Execute(kCreateSql));
+TEST_P(SQLDatabaseTest, Raze_OtherConnectionHasReadLock) {
+  ASSERT_TRUE(db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY)"));
+  ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(1)"));
+
+  if (IsWALEnabled()) {
+    // In WAL mode, read transactions in other connections do not block a write
+    // transaction.
+    return;
+  }
+
+  Database other_db(GetDBOptions());
+  ASSERT_TRUE(other_db.Open(db_path_));
+
+  Statement select(other_db.GetUniqueStatement("SELECT id FROM rows"));
+  ASSERT_TRUE(select.Step());
+  EXPECT_FALSE(db_->Raze())
+      << "Raze() should fail while another connection has a read lock";
+
+  ASSERT_FALSE(select.Step())
+      << "The SELECT statement should not produce more than one row";
+  EXPECT_TRUE(db_->Raze())
+      << "Raze() should succeed after the other connection releases the lock";
+}
+
+TEST_P(SQLDatabaseTest, Raze_EmptyDatabaseFile) {
+  ASSERT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
   db_->Close();
 
   ASSERT_TRUE(TruncateDatabase());
+  ASSERT_TRUE(db_->Open(db_path_))
+      << "Failed to reopen database after truncating";
 
-  ASSERT_TRUE(db_->Open(db_path_));
-  ASSERT_TRUE(db_->Raze());
-  EXPECT_EQ(0, SqliteSchemaCount(db_.get()));
+  EXPECT_TRUE(db_->Raze()) << "Raze() failed on an empty file";
+  EXPECT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
+      << "Raze() did not produce a healthy empty database";
 }
 
 // Verify that Raze() can handle a file of junk.
@@ -991,102 +987,185 @@
   EXPECT_EQ(0, SqliteSchemaCount(db_.get()));
 }
 
-// Basic test of RazeAndClose() operation.
-TEST_P(SQLDatabaseTest, RazeAndClose) {
-  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
-  const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)";
-
-  // Test that RazeAndClose() closes the database, and that the
-  // database is empty when re-opened.
-  ASSERT_TRUE(db_->Execute(kCreateSql));
-  ASSERT_TRUE(db_->Execute(kPopulateSql));
+TEST_P(SQLDatabaseTest, RazeAndClose_DeletesData) {
+  ASSERT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
+  ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
   ASSERT_TRUE(db_->RazeAndClose());
-  ASSERT_FALSE(db_->is_open());
-  db_->Close();
-  ASSERT_TRUE(db_->Open(db_path_));
-  ASSERT_EQ(0, SqliteSchemaCount(db_.get()));
 
-  // Test that RazeAndClose() can break transactions.
-  ASSERT_TRUE(db_->Execute(kCreateSql));
-  ASSERT_TRUE(db_->Execute(kPopulateSql));
-  ASSERT_TRUE(db_->BeginTransaction());
-  ASSERT_TRUE(db_->RazeAndClose());
-  ASSERT_FALSE(db_->is_open());
-  ASSERT_FALSE(db_->CommitTransaction());
+  // RazeAndClose() actually Poison()s. We need to call Close() in order to
+  // re-Open(). crbug.com/1311771 tracks renaming RazeAndClose().
   db_->Close();
-  ASSERT_TRUE(db_->Open(db_path_));
-  ASSERT_EQ(0, SqliteSchemaCount(db_.get()));
+  ASSERT_TRUE(db_->Open(db_path_))
+      << "RazeAndClose() did not produce a healthy database";
+  EXPECT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
+      << "RazeAndClose() did not produce a healthy empty database";
 }
 
-// Test that various operations fail without crashing after
-// RazeAndClose().
-TEST_P(SQLDatabaseTest, RazeAndCloseDiagnostics) {
-  const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
-  const char* kPopulateSql = "INSERT INTO foo (value) VALUES (12)";
-  const char* kSimpleSql = "SELECT 1";
-
-  ASSERT_TRUE(db_->Execute(kCreateSql));
-  ASSERT_TRUE(db_->Execute(kPopulateSql));
-
-  // Test baseline expectations.
-  db_->Preload();
-  ASSERT_TRUE(db_->DoesTableExist("foo"));
-  ASSERT_TRUE(db_->IsSQLValid(kSimpleSql));
-  ASSERT_TRUE(db_->Execute(kSimpleSql));
-  ASSERT_TRUE(db_->is_open());
-  {
-    Statement s(db_->GetUniqueStatement(kSimpleSql));
-    ASSERT_TRUE(s.Step());
-  }
-  {
-    Statement s(db_->GetCachedStatement(SQL_FROM_HERE, kSimpleSql));
-    ASSERT_TRUE(s.Step());
-  }
-  ASSERT_TRUE(db_->BeginTransaction());
-  ASSERT_TRUE(db_->CommitTransaction());
-  ASSERT_TRUE(db_->BeginTransaction());
-  db_->RollbackTransaction();
-
+TEST_P(SQLDatabaseTest, RazeAndClose_IsOpen) {
+  ASSERT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
+  ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
   ASSERT_TRUE(db_->RazeAndClose());
 
-  // At this point, they should all fail, but not crash.
-  db_->Preload();
-  ASSERT_FALSE(db_->DoesTableExist("foo"));
-  ASSERT_FALSE(db_->IsSQLValid(kSimpleSql));
-  ASSERT_FALSE(db_->Execute(kSimpleSql));
-  ASSERT_FALSE(db_->is_open());
-  {
-    Statement s(db_->GetUniqueStatement(kSimpleSql));
-    ASSERT_FALSE(s.Step());
-  }
-  {
-    Statement s(db_->GetCachedStatement(SQL_FROM_HERE, kSimpleSql));
-    ASSERT_FALSE(s.Step());
-  }
-  ASSERT_FALSE(db_->BeginTransaction());
-  ASSERT_FALSE(db_->CommitTransaction());
-  ASSERT_FALSE(db_->BeginTransaction());
-  db_->RollbackTransaction();
-
-  // Close normally to reset the poisoned flag.
-  db_->Close();
-
-// DEATH tests not supported on Android, iOS, or Fuchsia.
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_FUCHSIA)
-  // Once the real Close() has been called, various calls enforce API
-  // usage by becoming fatal in debug mode.  Since DEATH tests are
-  // expensive, just test one of them.
-  if (DLOG_IS_ON(FATAL)) {
-    ASSERT_DEATH({ db_->IsSQLValid(kSimpleSql); },
-                 "Illegal use of Database without a db");
-  }
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) &&
-        // !BUILDFLAG(IS_FUCHSIA)
+  EXPECT_FALSE(db_->is_open())
+      << "RazeAndClose() did not mark the database as closed";
 }
 
-// TODO(shess): Spin up a background thread to hold other_db, to more
-// closely match real life.  That would also allow testing
-// RazeWithTimeout().
+TEST_P(SQLDatabaseTest, RazeAndClose_Reopen_NoChanges) {
+  ASSERT_TRUE(db_->RazeAndClose());
+  EXPECT_FALSE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
+      << "Execute() should return false after RazeAndClose()";
+
+  // RazeAndClose() actually Poison()s. We need to call Close() in order to
+  // re-Open(). crbug.com/1311771 tracks renaming RazeAndClose().
+  db_->Close();
+  ASSERT_TRUE(db_->Open(db_path_))
+      << "RazeAndClose() did not produce a healthy database";
+  EXPECT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
+      << "Execute() returned false but went through after RazeAndClose()";
+}
+
+TEST_P(SQLDatabaseTest, RazeAndClose_OpenTransaction) {
+  ASSERT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
+  ASSERT_TRUE(db_->Execute("INSERT INTO rows(id) VALUES(12)"));
+
+  Transaction transaction(db_.get());
+  ASSERT_TRUE(transaction.Begin());
+  ASSERT_TRUE(db_->RazeAndClose());
+
+  EXPECT_FALSE(db_->is_open())
+      << "RazeAndClose() did not mark the database as closed";
+  EXPECT_FALSE(transaction.Commit())
+      << "RazeAndClose() did not cancel the transaction";
+
+  // RazeAndClose() actually Poison()s. We need to call Close() in order to
+  // re-Open(). crbug.com/1311771 tracks renaming RazeAndClose().
+  db_->Close();
+
+  ASSERT_TRUE(db_->Open(db_path_));
+  EXPECT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
+      << "RazeAndClose() did not produce a healthy empty database";
+}
+
+TEST_P(SQLDatabaseTest, RazeAndClose_Preload_NoCrash) {
+  db_->Preload();
+  db_->RazeAndClose();
+  db_->Preload();
+}
+
+TEST_P(SQLDatabaseTest, RazeAndClose_DoesTableExist) {
+  ASSERT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
+  ASSERT_TRUE(db_->DoesTableExist("rows")) << "Incorrect test setup";
+
+  ASSERT_TRUE(db_->RazeAndClose());
+  EXPECT_FALSE(db_->DoesTableExist("rows"))
+      << "DoesTableExist() should return false after RazeAndClose()";
+}
+
+TEST_P(SQLDatabaseTest, RazeAndClose_IsSQLValid) {
+  ASSERT_TRUE(db_->IsSQLValid("SELECT 1")) << "Incorrect test setup";
+
+  ASSERT_TRUE(db_->RazeAndClose());
+  EXPECT_FALSE(db_->IsSQLValid("SELECT 1"))
+      << "IsSQLValid() should return false after RazeAndClose()";
+}
+
+TEST_P(SQLDatabaseTest, RazeAndClose_Execute) {
+  ASSERT_TRUE(db_->Execute("SELECT 1")) << "Incorrect test setup";
+
+  ASSERT_TRUE(db_->RazeAndClose());
+  EXPECT_FALSE(db_->Execute("SELECT 1"))
+      << "Execute() should return false after RazeAndClose()";
+}
+
+TEST_P(SQLDatabaseTest, RazeAndClose_GetUniqueStatement) {
+  {
+    Statement select(db_->GetUniqueStatement("SELECT 1"));
+    ASSERT_TRUE(select.Step()) << "Incorrect test setup";
+  }
+
+  ASSERT_TRUE(db_->RazeAndClose());
+  {
+    Statement select(db_->GetUniqueStatement("SELECT 1"));
+    EXPECT_FALSE(select.Step())
+        << "GetUniqueStatement() should return an invalid Statement after "
+        << "RazeAndClose()";
+  }
+}
+
+TEST_P(SQLDatabaseTest, RazeAndClose_GetCachedStatement) {
+  {
+    Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
+    ASSERT_TRUE(select.Step()) << "Incorrect test setup";
+  }
+
+  ASSERT_TRUE(db_->RazeAndClose());
+  {
+    Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
+    EXPECT_FALSE(select.Step())
+        << "GetCachedStatement() should return an invalid Statement after "
+        << "RazeAndClose()";
+  }
+}
+
+TEST_P(SQLDatabaseTest, RazeAndClose_InvalidatesUniqueStatement) {
+  Statement select(db_->GetUniqueStatement("SELECT 1"));
+  ASSERT_TRUE(select.is_valid()) << "Incorrect test setup";
+  ASSERT_TRUE(select.Step()) << "Incorrect test setup";
+  select.Reset(/*clear_bound_vars=*/true);
+
+  ASSERT_TRUE(db_->RazeAndClose());
+  EXPECT_FALSE(select.is_valid())
+      << "RazeAndClose() should invalidate live Statements";
+  EXPECT_FALSE(select.Step())
+      << "RazeAndClose() should invalidate live Statements";
+}
+
+TEST_P(SQLDatabaseTest, RazeAndClose_InvalidatesCachedStatement) {
+  Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
+  ASSERT_TRUE(select.is_valid()) << "Incorrect test setup";
+  ASSERT_TRUE(select.Step()) << "Incorrect test setup";
+  select.Reset(/*clear_bound_vars=*/true);
+
+  ASSERT_TRUE(db_->RazeAndClose());
+  EXPECT_FALSE(select.is_valid())
+      << "RazeAndClose() should invalidate live Statements";
+  EXPECT_FALSE(select.Step())
+      << "RazeAndClose() should invalidate live Statements";
+}
+
+TEST_P(SQLDatabaseTest, RazeAndClose_TransactionBegin) {
+  {
+    Transaction transaction(db_.get());
+    ASSERT_TRUE(transaction.Begin()) << "Incorrect test setup";
+    ASSERT_TRUE(transaction.Commit()) << "Incorrect test setup";
+  }
+
+  ASSERT_TRUE(db_->RazeAndClose());
+  {
+    Transaction transaction(db_.get());
+    EXPECT_FALSE(transaction.Begin())
+        << "Transaction::Begin() should return false after RazeAndClose()";
+    EXPECT_FALSE(transaction.IsActiveForTesting())
+        << "RazeAndClose() should block transactions from starting";
+  }
+}
+
+TEST_P(SQLDatabaseTest, Close_IsSQLValid) {
+  ASSERT_TRUE(db_->IsSQLValid("SELECT 1")) << "Incorrect test setup";
+
+  db_->Close();
+
+  EXPECT_DCHECK_DEATH_WITH({ std::ignore = db_->IsSQLValid("SELECT 1"); },
+                           "Illegal use of Database without a db");
+}
 
 // On Windows, truncate silently fails against a memory-mapped file.  One goal
 // of Raze() is to truncate the file to remove blocks which generate I/O errors.
@@ -1210,116 +1289,204 @@
 }
 #endif  // BUILDFLAG(IS_POSIX)
 
-// Test that errors start happening once Poison() is called.
-TEST_P(SQLDatabaseTest, Poison) {
-  EXPECT_TRUE(db_->Execute("CREATE TABLE x (x)"));
+TEST_P(SQLDatabaseTest, Poison_IsOpen) {
+  db_->Poison();
+  EXPECT_FALSE(db_->is_open())
+      << "Poison() did not mark the database as closed";
+}
 
-  // Before the Poison() call, things generally work.
-  EXPECT_TRUE(db_->IsSQLValid("INSERT INTO x VALUES ('x')"));
-  EXPECT_TRUE(db_->Execute("INSERT INTO x VALUES ('x')"));
-  {
-    Statement s(db_->GetUniqueStatement("SELECT COUNT(*) FROM x"));
-    ASSERT_TRUE(s.is_valid());
-    ASSERT_TRUE(s.Step());
-  }
+TEST_P(SQLDatabaseTest, Poison_Close_Reopen_NoChanges) {
+  db_->Poison();
+  EXPECT_FALSE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
+      << "Execute() should return false after Poison()";
 
-  // Get a statement which is valid before and will exist across Poison().
-  Statement valid_statement(
-      db_->GetUniqueStatement("SELECT COUNT(*) FROM sqlite_schema"));
-  ASSERT_TRUE(valid_statement.is_valid());
-  ASSERT_TRUE(valid_statement.Step());
-  valid_statement.Reset(true);
+  db_->Close();
+  ASSERT_TRUE(db_->Open(db_path_)) << "Poison() damaged the database";
+  EXPECT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"))
+      << "Execute() returned false but went through after Poison()";
+}
+
+TEST_P(SQLDatabaseTest, Poison_Preload_NoCrash) {
+  db_->Preload();
+  db_->Poison();
+  db_->Preload();
+}
+
+TEST_P(SQLDatabaseTest, Poison_DoesTableExist) {
+  ASSERT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
+  ASSERT_TRUE(db_->DoesTableExist("rows")) << "Incorrect test setup";
 
   db_->Poison();
+  EXPECT_FALSE(db_->DoesTableExist("rows"))
+      << "DoesTableExist() should return false after Poison()";
+}
 
-  // After the Poison() call, things fail.
-  EXPECT_FALSE(db_->IsSQLValid("INSERT INTO x VALUES ('x')"));
-  EXPECT_FALSE(db_->Execute("INSERT INTO x VALUES ('x')"));
+TEST_P(SQLDatabaseTest, Poison_IsSQLValid) {
+  ASSERT_TRUE(db_->IsSQLValid("SELECT 1")) << "Incorrect test setup";
+
+  db_->Poison();
+  EXPECT_FALSE(db_->IsSQLValid("SELECT 1"))
+      << "IsSQLValid() should return false after Poison()";
+}
+
+TEST_P(SQLDatabaseTest, Poison_Execute) {
+  ASSERT_TRUE(db_->Execute("SELECT 1")) << "Incorrect test setup";
+
+  db_->Poison();
+  EXPECT_FALSE(db_->Execute("SELECT 1"))
+      << "Execute() should return false after Poison()";
+}
+
+TEST_P(SQLDatabaseTest, Poison_GetUniqueStatement) {
   {
-    Statement s(db_->GetUniqueStatement("SELECT COUNT(*) FROM x"));
-    ASSERT_FALSE(s.is_valid());
-    ASSERT_FALSE(s.Step());
+    Statement select(db_->GetUniqueStatement("SELECT 1"));
+    ASSERT_TRUE(select.Step()) << "Incorrect test setup";
   }
 
-  // The existing statement has become invalid.
-  ASSERT_FALSE(valid_statement.is_valid());
-  ASSERT_FALSE(valid_statement.Step());
+  db_->Poison();
+  {
+    Statement select(db_->GetUniqueStatement("SELECT 1"));
+    EXPECT_FALSE(select.Step())
+        << "GetUniqueStatement() should return an invalid Statement after "
+        << "Poison()";
+  }
+}
 
-  // Test that poisoning the database during a transaction works (with errors).
-  // RazeErrorCallback() poisons the database, the extra COMMIT causes
-  // CommitTransaction() to throw an error while committing.
-  db_->set_error_callback(
-      base::BindRepeating(&RazeErrorCallback, db_.get(), SQLITE_ERROR));
-  db_->Close();
-  ASSERT_TRUE(db_->Open(db_path_));
-  EXPECT_TRUE(db_->BeginTransaction());
-  EXPECT_TRUE(db_->Execute("INSERT INTO x VALUES ('x')"));
-  EXPECT_TRUE(db_->Execute("COMMIT"));
-  EXPECT_FALSE(db_->CommitTransaction());
+TEST_P(SQLDatabaseTest, Poison_GetCachedStatement) {
+  {
+    Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
+    ASSERT_TRUE(select.Step()) << "Incorrect test setup";
+  }
+
+  db_->Poison();
+  {
+    Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
+    EXPECT_FALSE(select.Step())
+        << "GetCachedStatement() should return an invalid Statement after "
+        << "Poison()";
+  }
+}
+
+TEST_P(SQLDatabaseTest, Poison_InvalidatesUniqueStatement) {
+  Statement select(db_->GetUniqueStatement("SELECT 1"));
+  ASSERT_TRUE(select.is_valid()) << "Incorrect test setup";
+  ASSERT_TRUE(select.Step()) << "Incorrect test setup";
+  select.Reset(/*clear_bound_vars=*/true);
+
+  db_->Poison();
+  EXPECT_FALSE(select.is_valid())
+      << "Poison() should invalidate live Statements";
+  EXPECT_FALSE(select.Step()) << "Poison() should invalidate live Statements";
+}
+
+TEST_P(SQLDatabaseTest, Poison_InvalidatesCachedStatement) {
+  Statement select(db_->GetCachedStatement(SQL_FROM_HERE, "SELECT 1"));
+  ASSERT_TRUE(select.is_valid()) << "Incorrect test setup";
+  ASSERT_TRUE(select.Step()) << "Incorrect test setup";
+  select.Reset(/*clear_bound_vars=*/true);
+
+  db_->Poison();
+  EXPECT_FALSE(select.is_valid())
+      << "Poison() should invalidate live Statements";
+  EXPECT_FALSE(select.Step()) << "Poison() should invalidate live Statements";
+}
+
+TEST_P(SQLDatabaseTest, Poison_TransactionBegin) {
+  {
+    Transaction transaction(db_.get());
+    ASSERT_TRUE(transaction.Begin()) << "Incorrect test setup";
+    ASSERT_TRUE(transaction.Commit()) << "Incorrect test setup";
+  }
+
+  db_->Poison();
+  {
+    Transaction transaction(db_.get());
+    EXPECT_FALSE(transaction.Begin())
+        << "Transaction::Begin() should return false after Poison()";
+    EXPECT_FALSE(transaction.IsActiveForTesting())
+        << "Poison() should block transactions from starting";
+  }
+}
+
+TEST_P(SQLDatabaseTest, Poison_OpenTransaction) {
+  Transaction transaction(db_.get());
+  ASSERT_TRUE(transaction.Begin());
+
+  db_->Poison();
+  EXPECT_FALSE(transaction.Commit())
+      << "Poison() did not cancel the transaction";
 }
 
 TEST_P(SQLDatabaseTest, AttachDatabase) {
-  EXPECT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
+  ASSERT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
 
   // Create a database to attach to.
   base::FilePath attach_path =
-      db_path_.DirName().AppendASCII("SQLDatabaseAttach.db");
-  static const char kAttachmentPoint[] = "other";
+      db_path_.DirName().AppendASCII("attach_database_test.db");
+  static constexpr char kAttachmentPoint[] = "other";
   {
     Database other_db;
     ASSERT_TRUE(other_db.Open(attach_path));
-    EXPECT_TRUE(other_db.Execute("CREATE TABLE bar (a, b)"));
-    EXPECT_TRUE(other_db.Execute("INSERT INTO bar VALUES ('hello', 'world')"));
+    ASSERT_TRUE(
+        other_db.Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
+    ASSERT_TRUE(other_db.Execute("INSERT INTO rows VALUES(42)"));
   }
 
   // Cannot see the attached database, yet.
-  EXPECT_FALSE(db_->IsSQLValid("SELECT count(*) from other.bar"));
+  EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
 
   EXPECT_TRUE(DatabaseTestPeer::AttachDatabase(db_.get(), attach_path,
                                                kAttachmentPoint));
-  EXPECT_TRUE(db_->IsSQLValid("SELECT count(*) from other.bar"));
+  EXPECT_TRUE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
 
   // Queries can touch both databases after the ATTACH.
-  EXPECT_TRUE(db_->Execute("INSERT INTO foo SELECT a, b FROM other.bar"));
+  EXPECT_TRUE(db_->Execute("INSERT INTO rows SELECT id FROM other.rows"));
   {
-    Statement s(db_->GetUniqueStatement("SELECT COUNT(*) FROM foo"));
-    ASSERT_TRUE(s.Step());
-    EXPECT_EQ(1, s.ColumnInt(0));
+    Statement select(db_->GetUniqueStatement("SELECT COUNT(*) FROM rows"));
+    ASSERT_TRUE(select.Step());
+    EXPECT_EQ(1, select.ColumnInt(0));
   }
 
   EXPECT_TRUE(DatabaseTestPeer::DetachDatabase(db_.get(), kAttachmentPoint));
-  EXPECT_FALSE(db_->IsSQLValid("SELECT count(*) from other.bar"));
+  EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
 }
 
 TEST_P(SQLDatabaseTest, AttachDatabaseWithOpenTransaction) {
-  EXPECT_TRUE(db_->Execute("CREATE TABLE foo (a, b)"));
+  ASSERT_TRUE(
+      db_->Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
 
   // Create a database to attach to.
   base::FilePath attach_path =
-      db_path_.DirName().AppendASCII("SQLDatabaseAttach.db");
-  static const char kAttachmentPoint[] = "other";
+      db_path_.DirName().AppendASCII("attach_database_test.db");
+  static constexpr char kAttachmentPoint[] = "other";
   {
     Database other_db;
     ASSERT_TRUE(other_db.Open(attach_path));
-    EXPECT_TRUE(other_db.Execute("CREATE TABLE bar (a, b)"));
-    EXPECT_TRUE(other_db.Execute("INSERT INTO bar VALUES ('hello', 'world')"));
+    ASSERT_TRUE(
+        other_db.Execute("CREATE TABLE rows(id INTEGER PRIMARY KEY NOT NULL)"));
+    ASSERT_TRUE(other_db.Execute("INSERT INTO rows VALUES(42)"));
   }
 
   // Cannot see the attached database, yet.
-  EXPECT_FALSE(db_->IsSQLValid("SELECT count(*) from other.bar"));
+  EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
 
   // Attach succeeds in a transaction.
-  EXPECT_TRUE(db_->BeginTransaction());
+  Transaction transaction(db_.get());
+  EXPECT_TRUE(transaction.Begin());
   EXPECT_TRUE(DatabaseTestPeer::AttachDatabase(db_.get(), attach_path,
                                                kAttachmentPoint));
-  EXPECT_TRUE(db_->IsSQLValid("SELECT count(*) from other.bar"));
+  EXPECT_TRUE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
 
   // Queries can touch both databases after the ATTACH.
-  EXPECT_TRUE(db_->Execute("INSERT INTO foo SELECT a, b FROM other.bar"));
+  EXPECT_TRUE(db_->Execute("INSERT INTO rows SELECT id FROM other.rows"));
   {
-    Statement s(db_->GetUniqueStatement("SELECT COUNT(*) FROM foo"));
-    ASSERT_TRUE(s.Step());
-    EXPECT_EQ(1, s.ColumnInt(0));
+    Statement select(db_->GetUniqueStatement("SELECT COUNT(*) FROM rows"));
+    ASSERT_TRUE(select.Step());
+    EXPECT_EQ(1, select.ColumnInt(0));
   }
 
   // Detaching the same database fails, database is locked in the transaction.
@@ -1327,14 +1494,14 @@
     sql::test::ScopedErrorExpecter expecter;
     expecter.ExpectError(SQLITE_ERROR);
     EXPECT_FALSE(DatabaseTestPeer::DetachDatabase(db_.get(), kAttachmentPoint));
-    EXPECT_TRUE(db_->IsSQLValid("SELECT count(*) from other.bar"));
     ASSERT_TRUE(expecter.SawExpectedErrors());
   }
+  EXPECT_TRUE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
 
   // Detach succeeds when the transaction is closed.
-  db_->RollbackTransaction();
+  transaction.Rollback();
   EXPECT_TRUE(DatabaseTestPeer::DetachDatabase(db_.get(), kAttachmentPoint));
-  EXPECT_FALSE(db_->IsSQLValid("SELECT count(*) from other.bar"));
+  EXPECT_FALSE(db_->IsSQLValid("SELECT COUNT(*) from other.rows"));
 }
 
 TEST_P(SQLDatabaseTest, FullIntegrityCheck) {
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index ef34c21..1976030f 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -9581,7 +9581,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M100",
-              "revision": "version:100.0.4896.64"
+              "revision": "version:100.0.4896.65"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -10085,7 +10085,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M100",
-              "revision": "version:100.0.4896.64"
+              "revision": "version:100.0.4896.65"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index d3b03e7e..90c98d56 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -44881,7 +44881,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M100",
-              "revision": "version:100.0.4896.64"
+              "revision": "version:100.0.4896.65"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -45385,7 +45385,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M100",
-              "revision": "version:100.0.4896.64"
+              "revision": "version:100.0.4896.65"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -45893,7 +45893,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M100",
-              "revision": "version:100.0.4896.64"
+              "revision": "version:100.0.4896.65"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46397,7 +46397,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M100",
-              "revision": "version:100.0.4896.64"
+              "revision": "version:100.0.4896.65"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46972,7 +46972,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M100",
-              "revision": "version:100.0.4896.64"
+              "revision": "version:100.0.4896.65"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47476,7 +47476,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M100",
-              "revision": "version:100.0.4896.64"
+              "revision": "version:100.0.4896.65"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48051,7 +48051,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M100",
-              "revision": "version:100.0.4896.64"
+              "revision": "version:100.0.4896.65"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48555,7 +48555,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M100",
-              "revision": "version:100.0.4896.64"
+              "revision": "version:100.0.4896.65"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 64d3d6d..9c4b6cd5 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -1804,7 +1804,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -1825,7 +1825,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -1845,7 +1845,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -1866,7 +1866,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -5273,7 +5273,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5294,7 +5294,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5316,7 +5316,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5338,7 +5338,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5359,7 +5359,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5380,7 +5380,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -5402,7 +5402,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5423,7 +5423,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5446,7 +5446,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5467,7 +5467,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5488,7 +5488,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5509,7 +5509,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5530,7 +5530,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5551,7 +5551,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5573,7 +5573,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5594,7 +5594,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5615,7 +5615,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5637,7 +5637,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -5662,7 +5662,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -5685,7 +5685,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5706,7 +5706,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5727,7 +5727,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5748,7 +5748,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5769,7 +5769,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5790,7 +5790,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5811,7 +5811,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5832,7 +5832,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5853,7 +5853,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5874,7 +5874,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5895,7 +5895,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5916,7 +5916,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -5938,7 +5938,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -5960,7 +5960,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -5981,7 +5981,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6002,7 +6002,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6023,7 +6023,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6044,7 +6044,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6065,7 +6065,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6086,7 +6086,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6107,7 +6107,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6128,7 +6128,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6149,7 +6149,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6170,7 +6170,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6191,7 +6191,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6212,7 +6212,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6233,7 +6233,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6254,7 +6254,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6275,7 +6275,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6296,7 +6296,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -6318,7 +6318,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6339,7 +6339,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6360,7 +6360,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6381,7 +6381,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6402,7 +6402,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6423,7 +6423,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6444,7 +6444,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6465,7 +6465,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6486,7 +6486,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6507,7 +6507,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6528,7 +6528,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6549,7 +6549,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6570,7 +6570,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -6593,7 +6593,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6614,7 +6614,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6635,7 +6635,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6656,7 +6656,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6677,7 +6677,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6698,7 +6698,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6719,7 +6719,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6740,7 +6740,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6761,7 +6761,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6782,7 +6782,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6803,7 +6803,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6824,7 +6824,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6845,7 +6845,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6866,7 +6866,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6887,7 +6887,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6908,7 +6908,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6929,7 +6929,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6950,7 +6950,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6971,7 +6971,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -6992,7 +6992,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7013,7 +7013,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -7035,7 +7035,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7057,7 +7057,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7078,7 +7078,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7099,7 +7099,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7120,7 +7120,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7141,7 +7141,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7162,7 +7162,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7183,7 +7183,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7204,7 +7204,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7229,7 +7229,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7250,7 +7250,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7272,7 +7272,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7294,7 +7294,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7315,7 +7315,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7336,7 +7336,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7357,7 +7357,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7378,7 +7378,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7399,7 +7399,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7420,7 +7420,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7442,7 +7442,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7463,7 +7463,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7484,7 +7484,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7505,7 +7505,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -7528,7 +7528,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7549,7 +7549,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7570,7 +7570,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7591,7 +7591,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7612,7 +7612,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7633,7 +7633,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7654,7 +7654,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7675,7 +7675,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7696,7 +7696,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7717,7 +7717,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -7739,7 +7739,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7760,7 +7760,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7781,7 +7781,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7802,7 +7802,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7823,7 +7823,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7844,7 +7844,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7865,7 +7865,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7886,7 +7886,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7907,7 +7907,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7928,7 +7928,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7949,7 +7949,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7970,7 +7970,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -7991,7 +7991,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8012,7 +8012,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8033,7 +8033,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8054,7 +8054,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8075,7 +8075,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8096,7 +8096,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8117,7 +8117,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8138,7 +8138,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8159,7 +8159,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -8181,7 +8181,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8202,7 +8202,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8223,7 +8223,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8244,7 +8244,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8265,7 +8265,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8286,7 +8286,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8307,7 +8307,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8328,7 +8328,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8349,7 +8349,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8370,7 +8370,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8391,7 +8391,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8412,7 +8412,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8433,7 +8433,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8454,7 +8454,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8475,7 +8475,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8496,7 +8496,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8517,7 +8517,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8538,7 +8538,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8559,7 +8559,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8580,7 +8580,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8601,7 +8601,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8622,7 +8622,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8643,7 +8643,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8664,7 +8664,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8685,7 +8685,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8706,7 +8706,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8727,7 +8727,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8748,7 +8748,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8769,7 +8769,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8790,7 +8790,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8811,7 +8811,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8832,7 +8832,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8853,7 +8853,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8874,7 +8874,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8895,7 +8895,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8916,7 +8916,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8937,7 +8937,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8958,7 +8958,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -8979,7 +8979,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -9001,7 +9001,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -9022,7 +9022,7 @@
           "dimension_sets": [
             {
               "cpu": "x86-64",
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -12519,7 +12519,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "os": "Ubuntu-18.04"
+              "os": "Ubuntu-16.04"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
diff --git a/testing/buildbot/filters/fuchsia.browser_tests.filter b/testing/buildbot/filters/fuchsia.browser_tests.filter
index a7e54fa..b1294ffb8 100644
--- a/testing/buildbot/filters/fuchsia.browser_tests.filter
+++ b/testing/buildbot/filters/fuchsia.browser_tests.filter
@@ -564,8 +564,8 @@
 -ZoomBubbleDialogTest.InvokeUi_default
 -ZoomControllerBrowserTest.RestoredPageScaleFromNavigation
 
-# TODO(crbug.com/1306610): Remove this condition and merge the deps once PDF
-# rendering no longer requires PPAPI support.
+# TODO(crbug.com/1306610): crbug.com/1306610: Enable once PDF rendering can be
+# enabled without PPAPI.
 -All/PrintBackendPrintBrowserTest.UpdatePrintSettings/0
 -All/PrintBackendPrintBrowserTest.UpdatePrintSettings/1
 -BackForwardCachePrintBrowserTest.DisableCaching
diff --git a/testing/buildbot/filters/fuchsia.content_browsertests.filter b/testing/buildbot/filters/fuchsia.content_browsertests.filter
index e595174..efba574 100644
--- a/testing/buildbot/filters/fuchsia.content_browsertests.filter
+++ b/testing/buildbot/filters/fuchsia.content_browsertests.filter
@@ -56,7 +56,8 @@
 -DatabaseTest.ReloadPage
 -DatabaseTest.UpdateRecord
 
-# crbug.com/702993: PDF is disabled until it has been migrated off PPAPI
+# TODO(crbug.com/1306610): crbug.com/1306610: Enable once PDF rendering can be
+# enabled without PPAPI.
 -All/BlockedSchemeNavigationBrowserTest.PDF_BrowserInitiatedNavigation_Allow/*
 -All/BlockedSchemeNavigationBrowserTest.PDF_FormPost_Block/*
 -All/BlockedSchemeNavigationBrowserTest.PDF_NavigationFromFrame_Block/*
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json
index f9bc60e..cc069f0 100644
--- a/testing/buildbot/internal.chromeos.fyi.json
+++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1217,9 +1217,9 @@
     "skylab_tests": [
       {
         "args": [],
-        "cros_board": "kevin",
-        "cros_img": "kevin-release/R102-14637.0.0",
-        "name": "lacros_all_tast_tests_KEVIN_RELEASE_LKGM",
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R101-14583.0.0",
+        "name": "lacros_all_tast_tests_STRONGBAD_RELEASE_LKGM",
         "swarming": {},
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_all_tast_tests",
@@ -1228,9 +1228,9 @@
       },
       {
         "args": [],
-        "cros_board": "hana",
-        "cros_img": "hana-release/R102-14637.0.0",
-        "name": "lacros_all_tast_tests_HANA_RELEASE_LKGM",
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R101-14588.11.0",
+        "name": "lacros_all_tast_tests_strongbad_RELEASE_DEV",
         "swarming": {},
         "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
         "test": "lacros_all_tast_tests",
@@ -1239,9 +1239,31 @@
       },
       {
         "args": [],
-        "cros_board": "kevin",
-        "cros_img": "kevin-release/R102-14637.0.0",
-        "name": "ozone_unittests_KEVIN_RELEASE_LKGM",
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R100-14526.28.0",
+        "name": "lacros_all_tast_tests_STRONGBAD_RELEASE_BETA",
+        "swarming": {},
+        "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
+        "test": "lacros_all_tast_tests",
+        "test_id_prefix": "ninja://chromeos/lacros:lacros_all_tast_tests/",
+        "timeout_sec": 10800
+      },
+      {
+        "args": [],
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R99-14469.58.0",
+        "name": "lacros_all_tast_tests_STRONGBAD_RELEASE_STABLE",
+        "swarming": {},
+        "tast_expr": "(\"group:mainline\" && \"dep:lacros\" && !informational)",
+        "test": "lacros_all_tast_tests",
+        "test_id_prefix": "ninja://chromeos/lacros:lacros_all_tast_tests/",
+        "timeout_sec": 10800
+      },
+      {
+        "args": [],
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R101-14583.0.0",
+        "name": "ozone_unittests_STRONGBAD_RELEASE_LKGM",
         "swarming": {},
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -1249,9 +1271,9 @@
       },
       {
         "args": [],
-        "cros_board": "hana",
-        "cros_img": "hana-release/R102-14637.0.0",
-        "name": "ozone_unittests_HANA_RELEASE_LKGM",
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R101-14588.11.0",
+        "name": "ozone_unittests_strongbad_RELEASE_DEV",
         "swarming": {},
         "test": "ozone_unittests",
         "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
@@ -1259,9 +1281,29 @@
       },
       {
         "args": [],
-        "cros_board": "kevin",
-        "cros_img": "kevin-release/R102-14637.0.0",
-        "name": "viz_unittests_KEVIN_RELEASE_LKGM",
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R100-14526.28.0",
+        "name": "ozone_unittests_STRONGBAD_RELEASE_BETA",
+        "swarming": {},
+        "test": "ozone_unittests",
+        "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
+        "timeout_sec": 3600
+      },
+      {
+        "args": [],
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R99-14469.58.0",
+        "name": "ozone_unittests_STRONGBAD_RELEASE_STABLE",
+        "swarming": {},
+        "test": "ozone_unittests",
+        "test_id_prefix": "ninja://ui/ozone:ozone_unittests/",
+        "timeout_sec": 3600
+      },
+      {
+        "args": [],
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R101-14583.0.0",
+        "name": "viz_unittests_STRONGBAD_RELEASE_LKGM",
         "swarming": {},
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
@@ -1269,9 +1311,29 @@
       },
       {
         "args": [],
-        "cros_board": "hana",
-        "cros_img": "hana-release/R102-14637.0.0",
-        "name": "viz_unittests_HANA_RELEASE_LKGM",
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R101-14588.11.0",
+        "name": "viz_unittests_strongbad_RELEASE_DEV",
+        "swarming": {},
+        "test": "viz_unittests",
+        "test_id_prefix": "ninja://components/viz:viz_unittests/",
+        "timeout_sec": 3600
+      },
+      {
+        "args": [],
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R100-14526.28.0",
+        "name": "viz_unittests_STRONGBAD_RELEASE_BETA",
+        "swarming": {},
+        "test": "viz_unittests",
+        "test_id_prefix": "ninja://components/viz:viz_unittests/",
+        "timeout_sec": 3600
+      },
+      {
+        "args": [],
+        "cros_board": "strongbad",
+        "cros_img": "strongbad-release/R99-14469.58.0",
+        "name": "viz_unittests_STRONGBAD_RELEASE_STABLE",
         "swarming": {},
         "test": "viz_unittests",
         "test_id_prefix": "ninja://components/viz:viz_unittests/",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index bcc8eb76..ce07072 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -7468,8 +7468,10 @@
     'lacros_skylab_arm_fyi': {
       'lacros_skylab_arm_tests_fyi': {
         'variants': [
-          'CROS_KEVIN_RELEASE_LKGM',
-          'CROS_HANA_RELEASE_LKGM',
+          'CROS_STRONGBAD_RELEASE_LKGM',
+          'CROS_STRONGBAD_RELEASE_DEV',
+          'CROS_STRONGBAD_RELEASE_BETA',
+          'CROS_STRONGBAD_RELEASE_STABLE',
         ]
       },
     },
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index b4b688c..55e6777 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -483,7 +483,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M100',
-          'revision': 'version:100.0.4896.64',
+          'revision': 'version:100.0.4896.65',
         }
       ],
     },
@@ -627,7 +627,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M100',
-          'revision': 'version:100.0.4896.64',
+          'revision': 'version:100.0.4896.65',
         }
       ],
     },
@@ -771,7 +771,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M100',
-          'revision': 'version:100.0.4896.64',
+          'revision': 'version:100.0.4896.65',
         }
       ],
     },
@@ -953,15 +953,6 @@
     'enabled': True,
     'identifier': 'EVE_FULL',
   },
-  'CROS_KEVIN_RELEASE_LKGM': {
-    'skylab': {
-      'cros_board': 'kevin',
-      'cros_chrome_version': '102.0.4964.0',
-      'cros_img': 'kevin-release/R102-14637.0.0',
-    },
-    'enabled': True,
-    'identifier': 'KEVIN_RELEASE_LKGM',
-  },
   'CROS_HANA_RELEASE_LKGM': {
     'skylab': {
       'cros_board': 'hana',
@@ -1079,6 +1070,42 @@
     'enabled': True,
     'identifier': 'OCTOPUS_RELEASE_STABLE',
   },
+  'CROS_STRONGBAD_RELEASE_LKGM': {
+    'skylab': {
+      'cros_board': 'strongbad',
+      'cros_chrome_version': '101.0.4943.0',
+      'cros_img': 'strongbad-release/R101-14583.0.0',
+    },
+    'enabled': True,
+    'identifier': 'STRONGBAD_RELEASE_LKGM',
+  },
+  'CROS_STRONGBAD_RELEASE_DEV': {
+    'skylab': {
+      'cros_board': 'strongbad',
+      'cros_chrome_version': '101.0.4951.6',
+      'cros_img': 'strongbad-release/R101-14588.11.0',
+    },
+    'enabled': True,
+    'identifier': 'strongbad_RELEASE_DEV',
+  },
+  'CROS_STRONGBAD_RELEASE_BETA': {
+    'skylab': {
+      'cros_board': 'strongbad',
+      'cros_chrome_version': '100.0.4896.39',
+      'cros_img': 'strongbad-release/R100-14526.28.0',
+    },
+    'enabled': True,
+    'identifier': 'STRONGBAD_RELEASE_BETA',
+  },
+  'CROS_STRONGBAD_RELEASE_STABLE': {
+    'skylab': {
+      'cros_board': 'strongbad',
+      'cros_chrome_version': '99.0.4844.86',
+      'cros_img': 'strongbad-release/R99-14469.58.0',
+    },
+    'enabled': True,
+    'identifier': 'STRONGBAD_RELEASE_STABLE',
+  },
   'LACROS_AMD64_GENERIC': {
     'args': [
       '--board=amd64-generic',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index bf602366..42defb8 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -5455,7 +5455,7 @@
       },
       'Linux ASan Tests (sandboxed)': {
         'mixins': [
-          'linux-bionic',
+          'linux-xenial',
         ],
         'test_suites': {
           'gtest_tests': 'sandboxed_chromium_memory_linux_gtests',
@@ -5485,7 +5485,7 @@
       },
       'Linux ChromiumOS MSan Tests': {
         'mixins': [
-          'linux-bionic',
+          'linux-xenial',
           'x86-64',
         ],
         'test_suites': {
@@ -5499,7 +5499,7 @@
       },
       'Linux MSan Tests': {
         'mixins': [
-          'linux-bionic',
+          'linux-xenial',
           'x86-64',
         ],
         'test_suites': {
@@ -5533,7 +5533,7 @@
       },
       'WebKit Linux ASAN': {
         'mixins': [
-          'linux-bionic',
+          'linux-xenial',
         ],
         'test_suites': {
           'isolated_scripts': 'chromium_webkit_isolated_scripts',
diff --git a/testing/scripts/get_compile_targets.py b/testing/scripts/get_compile_targets.py
index 76ef48a5..9928724 100755
--- a/testing/scripts/get_compile_targets.py
+++ b/testing/scripts/get_compile_targets.py
@@ -35,7 +35,6 @@
                     'variations_seed_access_helper.py',
                     'wpt_android_lib.py',
                     'wpt_common.py',
-                    'wpt_common_unittest.py',
                     'run_variations_smoke_tests.py',
                     'run_performance_tests_unittest.py'):
       continue
diff --git a/testing/scripts/wpt_common.py b/testing/scripts/wpt_common.py
index 74474f6..20f2be0 100644
--- a/testing/scripts/wpt_common.py
+++ b/testing/scripts/wpt_common.py
@@ -2,14 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import base64
-import json
 import os
 import posixpath
 import sys
-import time
-
-import six
 
 import common
 
@@ -30,13 +25,6 @@
     sys.path.append(TYP_DIR)
 
 from blinkpy.common.host import Host
-from blinkpy.common.html_diff import html_diff
-from blinkpy.common.system.filesystem import FileSystem
-from blinkpy.common.unified_diff import unified_diff
-from blinkpy.web_tests.models import test_failures
-from typ.artifacts import Artifacts
-from typ.json_results import Result
-from typ.result_sink import ResultSinkReporter
 
 
 def strip_wpt_root_prefix(path):
@@ -68,12 +56,10 @@
             host = Host()
         self.fs = host.filesystem
         self.port = host.port_factory.get()
-        self.wpt_manifest = self.port.wpt_manifest("external/wpt")
         # Path to the output of the test run. Comes from the args passed to the
         # run, parsed after this constructor. Can be overwritten by tests.
         self.wpt_output = None
         self.wptreport = None
-        self.sink = ResultSinkReporter()
         self.layout_test_results_subdir = 'layout-test-results'
         default_wpt_binary = os.path.join(
             common.SRC_DIR, "third_party", "wpt_tools", "wpt", "wpt")
@@ -105,450 +91,18 @@
         if not self.wpt_output and self.options:
             self.wpt_output = self.options.isolated_script_test_output
 
-        # Move json results into layout-test-results directory
-        results_dir = os.path.dirname(self.wpt_output)
-        layout_test_results = os.path.join(results_dir,
-                                           self.layout_test_results_subdir)
-        if self.fs.exists(layout_test_results):
-            self.fs.rmtree(layout_test_results)
-        self.fs.maybe_make_directory(layout_test_results)
-
-        # Perform post-processing of wptrunner output
-        self.process_wptrunner_output(
-            os.path.join(layout_test_results, 'full_results.json'),
-            os.path.join(layout_test_results, 'full_results_jsonp.js'),
-            # NOTE: Despite the name, this is actually a JSONP file.
-            # https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/tools/blinkpy/web_tests/controllers/manager.py;l=636;drc=3b93609b2498af0e9dc298f64e2b4f6204af68fa
-            os.path.join(layout_test_results, 'failing_results.json'),
-        )
-
-        # Copy layout test results viewer to layout-test-results directory
-        self.fs.copyfile(
-            os.path.join(WEB_TESTS_DIR, 'fast', 'harness', 'results.html'),
-            os.path.join(layout_test_results, 'results.html'))
-
+        command = [
+            sys.executable,
+            os.path.join(BLINK_TOOLS_DIR, 'wpt_process_results.py'),
+            '--verbose',
+            '--web-tests-dir',
+            WEB_TESTS_DIR,
+            '--artifacts-dir',
+            os.path.join(os.path.dirname(self.wpt_output),
+                         self.layout_test_results_subdir),
+            '--wpt-results',
+            self.wpt_output,
+        ]
         if self.wptreport:
-            command = [
-                sys.executable,
-                os.path.join(BLINK_TOOLS_DIR, 'wpt_process_results.py'),
-                '--verbose',
-                '--web-tests-dir',
-                WEB_TESTS_DIR,
-                '--artifacts-dir',
-                os.path.join(os.path.dirname(self.wpt_output),
-                             self.layout_test_results_subdir),
-                '--wpt-report',
-                self.wptreport,
-            ]
-            common.run_command(command)
-            self._process_wpt_report(self.wptreport)
-
-    def _process_wpt_report(self, wptreport):
-        layout_test_results = os.path.join(os.path.dirname(self.wpt_output),
-                                           self.layout_test_results_subdir)
-        dst = os.path.join(layout_test_results,
-                           os.path.basename(wptreport))
-        # upload the report to ResultDB
-        artifact = {
-            os.path.basename(wptreport): {
-                'filePath': dst
-            }
-        }
-        self.sink.report_invocation_level_artifacts(artifact)
-
-    def process_wptrunner_output(self,
-                                 full_results_json,
-                                 full_results_jsonp,
-                                 failing_results_jsonp):
-        """Post-process the output generated by wptrunner.
-
-        This output contains a single large json file containing the raw content
-        or artifacts which need to be extracted into their own files and removed
-        from the json file (to avoid duplication)."""
-        # output_json is modified *in place* throughout this function.
-        with self.fs.open_text_file_for_reading(self.wpt_output) as f:
-            output_json = json.load(f)
-
-        # Wptrunner test names exclude the 'external/wpt' directories, but add
-        # them back in at this point to reflect the actual location of tests in
-        # Chromium.
-        output_json['tests'] = {'external': {'wpt': output_json['tests']}}
-
-        results_dir = os.path.dirname(self.wpt_output)
-        self._process_test_leaves(results_dir, output_json['path_delimiter'],
-                                  output_json['tests'], '')
-        # Write output_json back to the same file after modifying it in memory
-        full_results = json.dumps(output_json)
-        self.fs.write_text_file(self.wpt_output, full_results)
-        # Also copy to full_results.json
-        self.fs.copyfile(self.wpt_output, full_results_json)
-
-        # JSONP paddings need to be the same as
-        # https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/tools/blinkpy/web_tests/controllers/manager.py;l=629;drc=3b93609b2498af0e9dc298f64e2b4f6204af68fa
-        # Write to full_results.jsonp
-        with self.fs.open_text_file_for_writing(full_results_jsonp) as f:
-            f.write('ADD_FULL_RESULTS(')
-            f.write(full_results)
-            f.write(');')
-        # Trim the results and write to failing_results.jsonp
-        self._trim_to_regressions(output_json['tests'])
-        with self.fs.open_text_file_for_writing(failing_results_jsonp) as f:
-            f.write('ADD_RESULTS(')
-            json.dump(output_json, f)
-            f.write(');')
-
-    def _handle_text_outputs(self, actual_metadata, root_node, results_dir,
-                             path_so_far):
-        """Produces actual, expected and diff text outputs."""
-        # If the test passed, there are no artifacts to output. Note that if a
-        # baseline file (*.ini file) exists, an actual of PASS means that the
-        # test matched the baseline, not that the test itself passed. As such,
-        # we still correctly produce artifacts in the case where someone fixes a
-        # baselined test.
-        if root_node["actual"] == "PASS":
-            return
-
-        # Note that the actual_metadata is a list of strings, so we join
-        # them on new lines when writing to file.
-        actual_text = "\n".join(actual_metadata)
-        actual_subpath = self._write_text_artifact(
-            test_failures.FILENAME_SUFFIX_ACTUAL,
-            results_dir, path_so_far, actual_text)
-        root_node["artifacts"]["actual_text"] = [actual_subpath]
-
-        # Try to locate the expected output of this test, if it exists.
-        expected_subpath, expected_text = \
-            self._maybe_write_expected_output(results_dir, path_so_far)
-        if expected_subpath:
-            root_node["artifacts"]["expected_text"] = [expected_subpath]
-            diff_content = unified_diff(expected_text, actual_text,
-                                        expected_subpath, actual_subpath)
-            diff_subpath = self._write_text_artifact(
-                test_failures.FILENAME_SUFFIX_DIFF, results_dir,
-                path_so_far, diff_content)
-            root_node["artifacts"]["text_diff"] = [diff_subpath]
-
-            # The html_diff library requires str arguments but the file
-            # contents is read-in as unicode. In python3 the contents comes
-            # in as a str, but in python2 it remains type unicode, so we
-            # have to encode it to get the str version.
-            if six.PY2:
-                expected_text = expected_text.encode('utf8')
-                actual_text = actual_text.encode('utf8')
-
-            html_diff_content = html_diff(expected_text, actual_text)
-            if six.PY2:
-                # Ensure the diff itself is properly decoded, to avoid
-                # UnicodeDecodeErrors when writing to file. This can happen if
-                # the diff contains unicode characters but the file is written
-                # as ascii because of the default system-level encoding.
-                html_diff_content = unicode(html_diff_content, 'utf8')
-
-            html_diff_subpath = self._write_text_artifact(
-                test_failures.FILENAME_SUFFIX_HTML_DIFF, results_dir,
-                path_so_far, html_diff_content, extension=".html")
-            root_node["artifacts"]["pretty_text_diff"] = [html_diff_subpath]
-
-    def _process_test_leaves(self, results_dir, delim, root_node, path_so_far):
-        """Finds and processes each test leaf below the specified root.
-
-        This will recursively traverse the trie of results in the json output,
-        keeping track of the path to each test and identifying leaves by the
-        presence of certain attributes.
-
-        Args:
-            results_dir: str path to the dir that results are stored
-            delim: str delimiter to be used for test names
-            root_node: dict representing the root of the trie we're currently
-                looking at
-            path_so_far: str the path to the current root_node in the trie
-        """
-        if "actual" in root_node:
-            # Found a leaf, process it
-            if "artifacts" not in root_node:
-                return
-
-            root_node["artifacts"].pop("wpt_actual_status", None)
-            root_node["artifacts"].pop("wpt_subtest_failure", None)
-
-            actual_metadata = root_node["artifacts"].pop(
-                "wpt_actual_metadata", None)
-            if actual_metadata:
-                self._handle_text_outputs(
-                    actual_metadata, root_node, results_dir, path_so_far)
-
-            screenshot_artifact = root_node["artifacts"].pop(
-                "screenshots", None)
-            if screenshot_artifact:
-                screenshot_paths_dict = self._write_screenshot_artifact(
-                    results_dir, path_so_far, screenshot_artifact)
-                for screenshot_key, path in screenshot_paths_dict.items():
-                    root_node["artifacts"][screenshot_key] = [path]
-
-            log_artifact = root_node["artifacts"].pop("wpt_log", None)
-            if log_artifact:
-                artifact_subpath = self._write_text_artifact(
-                    test_failures.FILENAME_SUFFIX_STDERR,
-                    results_dir, path_so_far, "\n".join(log_artifact))
-                if artifact_subpath:
-                    # Required by fast/harness/results.html to show stderr.
-                    root_node["has_stderr"] = True
-                    root_node["artifacts"]["stderr"] = [artifact_subpath]
-
-            crashlog_artifact = root_node["artifacts"].pop(
-                "wpt_crash_log", None)
-            if crashlog_artifact:
-                # Note that the crashlog_artifact is a list of strings, so we
-                # join them on new lines when writing to file.
-                artifact_subpath = self._write_text_artifact(
-                    test_failures.FILENAME_SUFFIX_CRASH_LOG,
-                    results_dir, path_so_far, "\n".join(crashlog_artifact))
-                if artifact_subpath:
-                    root_node["artifacts"]["crash_log"] = [artifact_subpath]
-
-            self._add_result_to_sink(path_so_far, root_node)
-            return
-
-        # We're not at a leaf node, continue traversing the trie.
-        for key in root_node:
-            # Append the key to the path, separated by the delimiter. However if
-            # the path is empty, skip the delimiter to avoid a leading slash in
-            # the path.
-            new_path = path_so_far + delim + key if path_so_far else key
-            self._process_test_leaves(results_dir, delim, root_node[key],
-                                      new_path)
-
-    def _add_result_to_sink(self, test_name, result_node):
-        """Add's test results to results sink
-
-        Args:
-          test_name: Name of the test to add to results sink.
-          result_node: Dictionary containing the actual result, expected result
-              and an artifacts dictionary.
-        """
-
-        artifacts = Artifacts(
-            output_dir=self.wpt_output,
-            host=self.sink.host,
-            artifacts_base_dir=self.layout_test_results_subdir)
-
-        assert len(result_node['actual'].split()) == 1, (
-            ('There should be only one result, however test %s has the '
-             'following results "%s"') % (test_name, result_node['actual']))
-        unexpected = result_node['actual'] not in result_node['expected']
-
-        for artifact_name, paths in result_node.get('artifacts', {}).items():
-            for path in paths:
-                artifacts.AddArtifact(artifact_name, path)
-
-        # Test timeouts are a special case of aborts. We must report ABORT to
-        # result sink for tests that timed out.
-        result = Result(name=test_name,
-                        actual=(result_node['actual']
-                                if result_node['actual'] != 'TIMEOUT'
-                                else 'ABORT'),
-                        started=time.time() - result_node.get('time', 0),
-                        took=result_node.get('time', 0),
-                        worker=0,
-                        expected=set(result_node['expected'].split()),
-                        unexpected=unexpected,
-                        artifacts=artifacts.artifacts)
-
-        index = test_name.find('?')
-        test_path = test_name[:index] if index != -1 else test_name
-
-        self.sink.report_individual_test_result(
-            test_name, result, os.path.dirname(self.wpt_output),
-            None, os.path.join(WEB_TESTS_DIR, test_path))
-
-    def _maybe_write_expected_output(self, results_dir, test_name):
-        """Attempts to create an expected output artifact for the test.
-
-        The expected output of tests is checked-in to the source tree beside the
-        test itself, with a .ini extension. Not all tests have expected output.
-
-        Args:
-            results_dir: str path to the dir to write the output to
-            test_name: str name of the test to write expected output for
-
-        Returns:
-            two strings:
-            - first is the path to the artifact file that the expected output
-              was written to, relative to the directory that the original output
-              is located. Returns empty string if there is no expected output
-              for this test.
-            - second is the text that is written to the file, or empty string if
-              there is no expected output for this test.
-        """
-        # When looking into the WPT manifest, we omit "external/wpt" from the
-        # test name, since that part of the path is only in Chromium.
-        wpt_test_name = strip_wpt_root_prefix(test_name)
-        test_file_subpath = self.wpt_manifest.file_path_for_test_url(
-            wpt_test_name)
-        if not test_file_subpath:
-            # Not all tests in the output have a corresponding test file. This
-            # could be print-reftests (which are unsupported by the blinkpy
-            # manifest) or .any.js tests (which appear in the output even though
-            # they do not actually run - they have corresponding tests like
-            # .any.worker.html which are covered here).
-            return "", ""
-
-        test_file_path = os.path.join(TESTS_ROOT_DIR, test_file_subpath)
-        expected_ini_path = test_file_path + ".ini"
-        if not self.fs.exists(expected_ini_path):
-            return "", ""
-
-        # This test has checked-in expected output. It needs to be copied to the
-        # results viewer directory and renamed from <test>.ini to
-        # <test>-expected.txt
-        contents = self.fs.read_text_file(expected_ini_path)
-        artifact_subpath = self._write_text_artifact(
-            test_failures.FILENAME_SUFFIX_EXPECTED, results_dir, test_name,
-            contents)
-        return artifact_subpath, contents
-
-    def _trim_to_regressions(self, root_node):
-        """Finds and processes each test leaf below the specified root.
-
-        This will recursively traverse the trie of results in the json output,
-        deleting leaves with is_unexpected=true.
-
-        Args:
-            root_node: dict representing the root of the trie we're currently
-                looking at
-
-        Returns:
-            A boolean, whether to delete the current root_node.
-        """
-        if "actual" in root_node:
-            # Found a leaf. Delete it if it's not a regression (unexpected
-            # failures).
-            return not root_node.get("is_regression")
-
-        # Not a leaf, recurse into the subtree. Note that we make a copy of the
-        # items since we delete from root_node.items() during the loop.
-        for key, node in list(root_node.items()):
-            if self._trim_to_regressions(node):
-                del root_node[key]
-
-        # Delete the current node if empty.
-        return len(root_node) == 0
-
-
-    def _write_text_artifact(self, suffix, results_dir, test_name, artifact,
-                             extension=".txt"):
-        """Writes a text artifact to disk.
-
-        A text artifact contains some form of text output for a test, such as
-        the actual test output, or a diff of the actual and expected outputs.
-        It is written to a txt file with a suffix generated from the log type.
-
-        Args:
-            suffix: str suffix of the artifact to write, e.g.
-                test_failures.FILENAME_SUFFIX_ACTUAL
-            results_dir: str path to the directory that results live in
-            test_name: str name of the test that this artifact is for
-            artifact: string, the text to write for this test.
-            extension: str the filename extension to use. Defaults to ".txt" but
-                can be changed if needed (eg: to ".html" for pretty-diff)
-
-        Returns:
-            string, the path to the artifact file that was written relative
-              to the |results_dir|.
-        """
-        log_artifact_sub_path = (
-            os.path.join(self.layout_test_results_subdir,
-                         self.port.output_filename(
-                             test_name, suffix, extension))
-        )
-        log_artifact_full_path = os.path.join(results_dir,
-                                              log_artifact_sub_path)
-        if not self.fs.exists(os.path.dirname(log_artifact_full_path)):
-            self.fs.maybe_make_directory(
-                os.path.dirname(log_artifact_full_path))
-        self.fs.write_text_file(log_artifact_full_path, artifact)
-
-        return log_artifact_sub_path
-
-    def _write_screenshot_artifact(self, results_dir, test_name,
-                                   screenshot_artifact):
-        """Write screenshot artifact to disk.
-
-        The screenshot artifact is a list of strings, each of which has the
-        format <url>:<base64-encoded PNG>. Each url-png pair is a screenshot of
-        either the test, or one of its refs. We can identify which screenshot is
-        for the test by comparing the url piece to the test name.
-
-        Args:
-           results_dir: str path to the directory that results live in
-           test:name str name of the test that this artifact is for
-           screenshot_artifact: list of strings, each being a url-png pair as
-               described above.
-
-        Returns:
-             A dict mapping the screenshot key (ie: actual, expected) to the
-             path of the file for that screenshot
-        """
-        result={}
-        # Remember the two images so we can diff them later.
-        actual_image_bytes = None
-        expected_image_bytes = None
-        for screenshot_pair in screenshot_artifact:
-            screenshot_split = screenshot_pair.split(":")
-            url = screenshot_split[0]
-            # The url produced by wptrunner will have a leading / which we trim
-            # away for easier comparison to the test_name below.
-            if url.startswith("/"):
-                url = url[1:]
-            image_bytes = base64.b64decode(screenshot_split[1].strip())
-
-            screenshot_key = "expected_image"
-            file_suffix = test_failures.FILENAME_SUFFIX_EXPECTED
-            # When comparing the test name to the image URL, we omit
-            # "external/wpt" from the test name, since that part of the path is
-            # only in Chromium.
-            wpt_test_name = strip_wpt_root_prefix(test_name)
-            if wpt_test_name == url:
-                screenshot_key = "actual_image"
-                file_suffix = test_failures.FILENAME_SUFFIX_ACTUAL
-
-            if screenshot_key == "expected_image":
-                expected_image_bytes = image_bytes
-            else:
-                actual_image_bytes = image_bytes
-
-            screenshot_sub_path = (
-                os.path.join(self.layout_test_results_subdir,
-                             self.port.output_filename(
-                                 test_name, file_suffix, ".png"))
-            )
-            result[screenshot_key] = screenshot_sub_path
-
-            screenshot_full_path = os.path.join(results_dir,screenshot_sub_path)
-            if not self.fs.exists(os.path.dirname(screenshot_full_path)):
-                self.fs.maybe_make_directory(
-                    os.path.dirname(screenshot_full_path))
-            # Note: we are writing raw bytes to this file
-            self.fs.write_binary_file(screenshot_full_path, image_bytes)
-
-        # Diff the two images and output the diff file.
-        diff_bytes, error = self.port.diff_image(expected_image_bytes,
-                                                 actual_image_bytes)
-        if diff_bytes and not error:
-            diff_sub_path = (
-                os.path.join(self.layout_test_results_subdir,
-                             self.port.output_filename(
-                                 test_name, test_failures.FILENAME_SUFFIX_DIFF,
-                                 ".png")))
-            result["image_diff"] = diff_sub_path
-            diff_full_path = os.path.join(results_dir, diff_sub_path)
-            if not self.fs.exists(os.path.dirname(diff_full_path)):
-                self.fs.maybe_make_directory(os.path.dirname(diff_full_path))
-            # Note: we are writing raw bytes to this file
-            self.fs.write_binary_file(diff_full_path, diff_bytes)
-        else:
-            print("Error creating diff image for test %s. "
-                  "Error=%s, diff_bytes is None? %s\n"
-                  % (test_name, error, diff_bytes is None))
-
-        return result
+            command.extend(['--wpt-report', self.wptreport])
+        common.run_command(command)
diff --git a/testing/scripts/wpt_common_unittest.py b/testing/scripts/wpt_common_unittest.py
deleted file mode 100755
index 2e920e2..0000000
--- a/testing/scripts/wpt_common_unittest.py
+++ /dev/null
@@ -1,649 +0,0 @@
-#!/usr/bin/env vpython
-# Copyright (c) 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Unit tests for common functionality of wpt testing scripts."""
-
-import base64
-import json
-import os
-import re
-import unittest
-
-from wpt_common import (
-    BaseWptScriptAdapter, TESTS_ROOT_DIR, WEB_TESTS_DIR)
-
-from blinkpy.common.host_mock import MockHost as BlinkMockHost
-from blinkpy.web_tests.port.factory_mock import MockPortFactory
-from blinkpy.w3c.wpt_manifest import BASE_MANIFEST_NAME
-from typ.fakes.host_fake import FakeHost as TypFakeHost
-
-# The path where the output of a wpt run was written. This is the file that
-# gets processed by BaseWptScriptAdapter.
-OUTPUT_JSON_FILENAME = "out.json"
-
-
-class MockResultSink(object):
-
-    def __init__(self):
-        self.sink_requests = []
-        self.host = TypFakeHost()
-
-    def report_individual_test_result(self, test_name, result,
-                                      artifacts_sub_dir,
-                                      expectation, test_path):
-        del artifacts_sub_dir
-        assert not expectation, 'expectation parameter should always be None'
-        self.sink_requests.append(
-            {'test': test_name,
-             'test_path': test_path,
-             'result': {'actual': result.actual,
-                        'expected': result.expected,
-                        'unexpected': result.unexpected,
-                        'artifacts': result.artifacts}})
-
-class BaseWptScriptAdapterTest(unittest.TestCase):
-    def setUp(self):
-        self.host = BlinkMockHost()
-        self.host.port_factory = MockPortFactory(self.host)
-        self.port = self.host.port_factory.get()
-
-        # Create a testing manifest containing any test files that we
-        # might interact with.
-        self.host.filesystem.write_text_file(
-            self.port.web_tests_dir() + '/external/' + BASE_MANIFEST_NAME,
-            json.dumps({
-                'items': {
-                    'reftest': {
-                        'reftest.html': [
-                            'c3f2fb6f436da59d43aeda0a7e8a018084557033',
-                            [None, [['reftest-ref.html', '==']], {}],
-                        ]
-                    },
-                    'testharness': {
-                        'test.html': [
-                            'd933fd981d4a33ba82fb2b000234859bdda1494e',
-                            [None, {}]
-                        ],
-                        'crash.html': [
-                            'd933fd981d4a33ba82fb2b000234859bdda1494e',
-                            [None, {}]
-                        ],
-                        'variant.html': [
-                            'b8db5972284d1ac6bbda0da81621d9bca5d04ee7',
-                            ['variant.html?foo=bar/abc', {}],
-                            ['variant.html?foo=baz', {}],
-                        ],
-                        'dir': {
-                            'multiglob.https.any.js': [
-                                'd6498c3e388e0c637830fa080cca78b0ab0e5305',
-                                ['dir/multiglob.https.any.window.html', {}],
-                                ['dir/multiglob.https.any.worker.html', {}],
-                            ],
-                        },
-                    },
-                },
-            }))
-        self.host.filesystem.write_text_file(
-            os.path.join(WEB_TESTS_DIR, "fast", "harness", "results.html"),
-            "results-viewer-body")
-        self.wpt_adapter = BaseWptScriptAdapter(self.host)
-        self.wpt_adapter.wpt_output = OUTPUT_JSON_FILENAME
-        self.wpt_adapter.sink = MockResultSink()
-
-    def _create_json_output(self, json_dict):
-        """Writing some json output for processing."""
-        with self.host.filesystem.open_text_file_for_writing(
-            OUTPUT_JSON_FILENAME) as f:
-            json.dump(json_dict, f)
-
-    def _load_json_output(self, filename=OUTPUT_JSON_FILENAME):
-        """Loads the json output after post-processing."""
-        return json.loads(self.host.filesystem.read_text_file(filename))
-
-    def test_result_sink_for_test_expected_result(self):
-        json_dict = {
-            'tests': {
-                'fail': {
-                    'test.html?variant1': {
-                        'expected': 'PASS FAIL',
-                        'actual': 'FAIL',
-                        'artifacts': {
-                            'wpt_actual_status': ['OK'],
-                            'wpt_actual_metadata': ['test.html actual text'],
-                        },
-                    },
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        test_abs_path = os.path.join(WEB_TESTS_DIR,
-                                     'external', 'wpt', 'fail', 'test.html')
-        self._create_json_output(json_dict)
-        self.wpt_adapter.do_post_test_run_tasks()
-
-        baseline_artifacts = {'actual_text': [
-                                  (os.path.join('layout-test-results',
-                                                'external', 'wpt', 'fail',
-                                                'test_variant1-actual.txt'))]}
-        self.assertEqual(self.wpt_adapter.sink.sink_requests,
-                          [{'test': os.path.join('external','wpt', 'fail',
-                                                 'test.html?variant1'),
-                            'test_path': test_abs_path,
-                            'result': {'actual': 'FAIL',
-                                       'expected': set(['PASS', 'FAIL']),
-                                       'unexpected': False,
-                                       'artifacts': baseline_artifacts}}])
-
-    def test_result_sink_for_test_variant(self):
-        json_dict = {
-            'tests': {
-                'fail': {
-                    'test.html?variant1': {
-                        'expected': 'PASS',
-                        'actual': 'FAIL',
-                        'artifacts': {
-                            'wpt_actual_status': ['OK'],
-                            'wpt_actual_metadata': ['test.html actual text'],
-                        },
-                    },
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        test_abs_path = os.path.join(WEB_TESTS_DIR,
-                                     'external', 'wpt', 'fail', 'test.html')
-        self._create_json_output(json_dict)
-        self.wpt_adapter.do_post_test_run_tasks()
-        baseline_artifacts = {'actual_text': [
-                                  (os.path.join('layout-test-results',
-                                                'external', 'wpt', 'fail',
-                                                'test_variant1-actual.txt'))]}
-        self.assertEqual(self.wpt_adapter.sink.sink_requests,
-                          [{'test': os.path.join('external', 'wpt', 'fail',
-                                                 'test.html?variant1'),
-                            'test_path': test_abs_path,
-                            'result': {'actual': 'FAIL',
-                                       'expected': set(['PASS']),
-                                       'unexpected': True,
-                                       'artifacts': baseline_artifacts}}])
-
-    def test_result_sink_artifacts(self):
-        json_dict = {
-            'tests': {
-                'fail': {
-                    'test.html': {
-                        'expected': 'PASS',
-                        'actual': 'FAIL',
-                        'artifacts': {
-                            'wpt_actual_status': ['OK'],
-                            'wpt_actual_metadata': ['test.html actual text'],
-                        },
-                    },
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        self._create_json_output(json_dict)
-        self.wpt_adapter.do_post_test_run_tasks()
-        test_abs_path = os.path.join(WEB_TESTS_DIR,
-                                     'external', 'wpt', 'fail', 'test.html')
-        baseline_artifacts = {'actual_text': [
-                                  os.path.join('layout-test-results',
-                                               'external', 'wpt', 'fail',
-                                               'test-actual.txt')]}
-        self.assertEqual(self.wpt_adapter.sink.sink_requests,
-                          [{'test': os.path.join('external', 'wpt', 'fail',
-                                                 'test.html'),
-                            'test_path': test_abs_path,
-                            'result': {'actual': 'FAIL',
-                                       'expected': set(['PASS']),
-                                       'unexpected': True,
-                                       'artifacts': baseline_artifacts}}])
-
-    def test_write_jsons(self):
-        # Ensure that various JSONs are written to the correct location.
-
-        json_dict = {
-            'tests': {
-                'pass': {
-                    'test.html': {
-                        'expected': 'PASS',
-                        'actual': 'PASS',
-                        'artifacts': {
-                            'wpt_actual_status': ['OK'],
-                        },
-                    },
-                },
-                'unexpected_pass.html': {
-                    'expected': 'FAIL',
-                    'actual': 'PASS',
-                    'artifacts': {
-                        'wpt_actual_status': ['OK'],
-                    },
-                    'is_unexpected': True,
-                },
-                'fail.html': {
-                    'expected': 'PASS',
-                    'actual': 'FAIL',
-                    'artifacts': {
-                        'wpt_actual_status': ['ERROR'],
-                    },
-                    'is_unexpected': True,
-                    'is_regression': True,
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        self._create_json_output(json_dict)
-        self.wpt_adapter.do_post_test_run_tasks()
-        # The correctness of the output JSON is verified by other tests.
-        written_files = self.wpt_adapter.fs.written_files
-        self.assertEqual(written_files[OUTPUT_JSON_FILENAME],
-                         written_files[os.path.join(
-                             self.wpt_adapter.layout_test_results_subdir,
-                             'full_results.json')])
-        # Verify JSONP
-        full_results_jsonp = written_files[os.path.join(
-            self.wpt_adapter.layout_test_results_subdir,
-            'full_results_jsonp.js')]
-        match = re.match(r'ADD_FULL_RESULTS\((.*)\);$',
-                         full_results_jsonp.decode('utf-8'))
-        self.assertIsNotNone(match)
-        self.assertEqual(match.group(1),
-            written_files[OUTPUT_JSON_FILENAME].decode(encoding='utf-8'))
-        failing_results_jsonp = written_files[os.path.join(
-            self.wpt_adapter.layout_test_results_subdir,
-            'failing_results.json')]
-        match = re.match(r'ADD_RESULTS\((.*)\);$',
-                         failing_results_jsonp.decode('utf-8'))
-        self.assertIsNotNone(match)
-        failing_results = json.loads(match.group(1))
-        # Verify filtering of failing_results.json
-        self.assertIn('fail.html', failing_results['tests']['external']['wpt'])
-        # We shouldn't have unexpected passes or empty dirs after filtering.
-        self.assertNotIn('unexpected_pass.html',
-                         failing_results['tests']['external']['wpt'])
-        self.assertNotIn('pass', failing_results['tests']['external']['wpt'])
-
-    def test_write_text_outputs(self):
-        # Ensure that text outputs are written to the correct location.
-
-        # We only generate an actual.txt if our actual wasn't PASS, so in this
-        # case we shouldn't write anything.
-        json_dict = {
-            'tests': {
-                'test.html': {
-                    'expected': 'PASS',
-                    'actual': 'PASS',
-                    'artifacts': {
-                        'wpt_actual_status': ['OK'],
-                        'wpt_actual_metadata': ['test.html actual text'],
-                    },
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        self._create_json_output(json_dict)
-        self.wpt_adapter.do_post_test_run_tasks()
-        written_files = self.wpt_adapter.fs.written_files
-        artifact_subdir = os.path.join(
-            self.wpt_adapter.layout_test_results_subdir,
-            "external", "wpt")
-        actual_path = os.path.join(artifact_subdir,
-                                   "test-actual.txt")
-        diff_path = os.path.join(artifact_subdir, "test-diff.txt")
-        pretty_diff_path = os.path.join(artifact_subdir,
-                                        "test-pretty-diff.html")
-        self.assertNotIn(actual_path, written_files)
-        self.assertNotIn(diff_path, written_files)
-        self.assertNotIn(pretty_diff_path, written_files)
-
-        # Now we change the outcome to be a FAIL, which should generate an
-        # actual.txt
-        json_dict['tests']['test.html']['actual'] = 'FAIL'
-        self._create_json_output(json_dict)
-        self.wpt_adapter.do_post_test_run_tasks()
-        written_files = self.wpt_adapter.fs.written_files
-        actual_path = os.path.join(artifact_subdir, "test-actual.txt")
-        self.assertEqual("test.html actual text",
-            written_files[actual_path].decode(encoding='utf-8'))
-        # Ensure the artifact in the json was replaced with the location of
-        # the newly-created file.
-        updated_json = self._load_json_output()
-        self.assertFalse(
-            "wpt_actual_metadata" in updated_json["tests"]["external"]["wpt"]
-                ["test.html"]["artifacts"])
-        self.assertEqual(
-            [actual_path],
-            updated_json["tests"]["external"]["wpt"]["test.html"]["artifacts"]
-                ["actual_text"])
-
-        self.assertIn(actual_path, written_files)
-        self.assertNotIn(diff_path, written_files)
-        self.assertNotIn(pretty_diff_path, written_files)
-
-    def test_write_log_artifact(self):
-        # Ensure that crash log artifacts are written to the correct location.
-        json_dict = {
-            'tests': {
-                'test.html': {
-                    'expected': 'PASS',
-                    'actual': 'FAIL',
-                    'artifacts': {
-                        'wpt_actual_status': ['ERROR'],
-                        'wpt_log': ['test.html exceptions'],
-                    },
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        self._create_json_output(json_dict)
-        self.wpt_adapter.do_post_test_run_tasks()
-        written_files = self.wpt_adapter.fs.written_files
-        artifact_subdir = os.path.join(
-            self.wpt_adapter.layout_test_results_subdir,
-            "external", "wpt")
-        stderr_path = os.path.join(artifact_subdir,
-                                   "test-stderr.txt")
-        self.assertEqual("test.html exceptions",
-            written_files[stderr_path].decode(encoding='utf-8'))
-        # Ensure the artifact in the json was replaced with the location of
-        # the newly-created file.
-        updated_json = self._load_json_output()
-        self.assertFalse(
-            "wpt_log" in updated_json["tests"]["external"]["wpt"]["test.html"]
-                ["artifacts"])
-        self.assertEqual(
-            [stderr_path], updated_json["tests"]["external"]["wpt"]["test.html"]
-                ["artifacts"]["stderr"])
-        self.assertTrue(
-            updated_json["tests"]["external"]["wpt"]["test.html"]["has_stderr"])
-
-    def test_write_crashlog_artifact(self):
-        # Ensure that crash log artifacts are written to the correct location.
-        json_dict = {
-            'tests': {
-                'test.html': {
-                    'expected': 'PASS',
-                    'actual': 'CRASH',
-                    'artifacts': {
-                        'wpt_actual_status': ['CRASH'],
-                        'wpt_crash_log': ['test.html crashed!'],
-                    },
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        self._create_json_output(json_dict)
-        self.wpt_adapter.do_post_test_run_tasks()
-        written_files = self.wpt_adapter.fs.written_files
-        artifact_subdir = os.path.join(
-            self.wpt_adapter.layout_test_results_subdir,
-            "external", "wpt")
-        crash_log_path = os.path.join(artifact_subdir,
-                                      "test-crash-log.txt")
-        self.assertEqual("test.html crashed!",
-            written_files[crash_log_path].decode(encoding='utf-8'))
-        # Ensure the artifact in the json was replaced with the location of
-        # the newly-created file.
-        updated_json = self._load_json_output()
-        self.assertFalse(
-            "wpt_crash_log" in updated_json["tests"]["external"]["wpt"]
-                ["test.html"]["artifacts"])
-        self.assertEqual(
-            [crash_log_path], updated_json["tests"]["external"]["wpt"]
-                ["test.html"]["artifacts"]["crash_log"])
-
-    def test_write_screenshot_artifacts(self):
-        # Ensure that screenshots are written to the correct filenames and
-        # their bytes are base64 decoded. The image diff should also be created.
-        json_dict = {
-            'tests': {
-                'reftest.html': {
-                    'expected': 'PASS',
-                    'actual': 'PASS',
-                    'artifacts': {
-                        'wpt_actual_status': ['PASS'],
-                        'screenshots': [
-                            'reftest.html:abcd',
-                            'reftest-ref.html:bcde',
-                        ],
-                    },
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        self._create_json_output(json_dict)
-        self.wpt_adapter.do_post_test_run_tasks()
-        written_files = self.wpt_adapter.fs.written_files
-        artifact_subdir = os.path.join(
-            self.wpt_adapter.layout_test_results_subdir,
-            "external", "wpt")
-        actual_image_path = os.path.join(artifact_subdir,
-                                         "reftest-actual.png")
-        self.assertEqual(base64.b64decode('abcd'),
-                         written_files[actual_image_path])
-        expected_image_path = os.path.join(artifact_subdir,
-                                           "reftest-expected.png")
-        self.assertEqual(base64.b64decode('bcde'),
-                         written_files[expected_image_path])
-        diff_image_path = os.path.join(artifact_subdir,
-                                       "reftest-diff.png")
-        # Make sure the diff image was written but don't check the contents,
-        # assume that diff_image does the right thing.
-        self.assertIsNotNone(written_files[diff_image_path])
-        # Ensure the artifacts in the json were replaced with the location of
-        # the newly-created files.
-        updated_json = self._load_json_output()
-        self.assertFalse(
-            "screenshots" in updated_json["tests"]["external"]["wpt"]
-                ["reftest.html"]["artifacts"])
-        self.assertEqual(
-            [actual_image_path],
-            updated_json["tests"]["external"]["wpt"]["reftest.html"]
-                ["artifacts"]["actual_image"])
-        self.assertEqual(
-            [expected_image_path],
-            updated_json["tests"]["external"]["wpt"]["reftest.html"]
-                ["artifacts"]["expected_image"])
-        self.assertEqual(
-            [diff_image_path],
-            updated_json["tests"]["external"]["wpt"]["reftest.html"]
-                ["artifacts"]["image_diff"])
-
-    def test_copy_expected_output(self):
-        # Check that an -expected.txt file is created from a checked-in metadata
-        # ini file if it exists for a test
-        json_dict = {
-            'tests': {
-                'test.html': {
-                    'expected': 'PASS',
-                    'actual': 'FAIL',
-                    'artifacts': {
-                        'wpt_actual_status': ['OK'],
-                        'wpt_actual_metadata': ['test.html actual text'],
-                    },
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        self._create_json_output(json_dict)
-        # Also create a checked-in metadata file for this test
-        self.host.filesystem.write_text_file(
-            os.path.join(TESTS_ROOT_DIR, "test.html.ini"),
-            "test.html checked-in metadata")
-        self.wpt_adapter.do_post_test_run_tasks()
-        written_files = self.wpt_adapter.fs.written_files
-        artifact_subdir = os.path.join(
-            self.wpt_adapter.layout_test_results_subdir,
-            "external", "wpt")
-        actual_path = os.path.join(artifact_subdir,
-                                   "test-actual.txt")
-        self.assertEqual("test.html actual text",
-            written_files[actual_path].decode(encoding='utf-8'))
-        # The checked-in metadata file gets renamed from .ini to -expected.txt
-        expected_path = os.path.join(artifact_subdir,
-                                     "test-expected.txt")
-        self.assertEqual("test.html checked-in metadata",
-                         written_files[expected_path].decode(encoding='utf-8'))
-        # Ensure the artifacts in the json were replaced with the locations of
-        # the newly-created files.
-        updated_json = self._load_json_output()
-        self.assertFalse(
-            "wpt_actual_metadata" in updated_json["tests"]["external"]["wpt"]
-                ["test.html"]["artifacts"])
-        self.assertEqual(
-            [actual_path],
-            updated_json["tests"]["external"]["wpt"]["test.html"]["artifacts"]
-                ["actual_text"])
-        self.assertEqual(
-            [expected_path],
-            updated_json["tests"]["external"]["wpt"]["test.html"]["artifacts"]
-                ["expected_text"])
-
-        # Ensure that a diff was also generated. There should be both additions
-        # and deletions for this test since we have expected output. We don't
-        # validate the entire diff files to avoid checking line numbers/markup.
-        diff_path = os.path.join(artifact_subdir, "test-diff.txt")
-        self.assertIn("-test.html checked-in metadata",
-                      written_files[diff_path].decode(encoding='utf-8'))
-        self.assertIn("+test.html actual text",
-            written_files[diff_path].decode(encoding='utf-8'))
-        self.assertEqual(
-            [diff_path],
-            updated_json["tests"]["external"]["wpt"]["test.html"]["artifacts"]
-                ["text_diff"])
-        pretty_diff_path = os.path.join(artifact_subdir,
-                                        "test-pretty-diff.html")
-        self.assertIn("test.html checked-in metadata",
-                      written_files[pretty_diff_path].decode(encoding='utf-8'))
-        self.assertIn("test.html actual text",
-            written_files[pretty_diff_path].decode(encoding='utf-8'))
-        self.assertEqual(
-            [pretty_diff_path],
-            updated_json["tests"]["external"]["wpt"]["test.html"]["artifacts"]
-                ["pretty_text_diff"])
-
-    def test_expected_output_for_variant(self):
-        # Check that an -expected.txt file is created from a checked-in metadata
-        # ini file for a variant test. Variants are a little different because
-        # we have to use the manifest to map a test name to the test file, and
-        # determine the associated metadata from the test file.
-        # Check that an -expected.txt file is created from a checked-in metadata
-        # ini file if it exists for a test
-        json_dict = {
-            'tests': {
-                'variant.html?foo=bar/abc': {
-                    'expected': 'PASS',
-                    'actual': 'FAIL',
-                    'artifacts': {
-                        'wpt_actual_status': ['OK'],
-                        'wpt_actual_metadata': ['variant bar/abc actual text'],
-                    },
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        self._create_json_output(json_dict)
-        # Also create a checked-in metadata file for this test. This filename
-        # matches the test *file* name, not the test name (which includes the
-        # variant).
-        self.host.filesystem.write_text_file(
-            os.path.join(TESTS_ROOT_DIR, "variant.html.ini"),
-            "variant.html checked-in metadata")
-        self.wpt_adapter.do_post_test_run_tasks()
-        written_files = self.wpt_adapter.fs.written_files
-        artifact_subdir = os.path.join(
-            self.wpt_adapter.layout_test_results_subdir,
-            "external", "wpt")
-        actual_path = os.path.join(artifact_subdir,
-                                   "variant_foo=bar_abc-actual.txt")
-        self.assertEqual("variant bar/abc actual text",
-                         written_files[actual_path].decode(encoding='utf-8'))
-        # The checked-in metadata file gets renamed from .ini to -expected.txt
-        expected_path = os.path.join(artifact_subdir,
-                                     "variant_foo=bar_abc-expected.txt")
-        self.assertEqual("variant.html checked-in metadata",
-                         written_files[expected_path].decode(encoding='utf-8'))
-        # Ensure the artifacts in the json were replaced with the locations of
-        # the newly-created files.
-        updated_json = self._load_json_output()
-        self.assertFalse(
-            "wpt_actual_metadata" in updated_json["tests"]["external"]["wpt"]
-                ["variant.html?foo=bar/abc"]["artifacts"])
-        self.assertEqual(
-            [actual_path],
-            updated_json["tests"]["external"]["wpt"]["variant.html?foo=bar/abc"]
-                ["artifacts"]["actual_text"])
-        self.assertEqual(
-            [expected_path],
-            updated_json["tests"]["external"]["wpt"]["variant.html?foo=bar/abc"]
-                ["artifacts"]["expected_text"])
-
-    def test_expected_output_for_multiglob(self):
-        # Check that an -expected.txt file is created from a checked-in metadata
-        # ini file for a multiglobal test. Multi-globals are a little different
-        # because we have to use the manifest to map a test name to the test
-        # file, and determine the associated metadata from the test file.
-        #
-        # Also note that the "dir" is both a directory and a part of the test
-        # name, so the path delimiter remains a / (ie: dir/multiglob) even on
-        # Windows.
-        json_dict = {
-            'tests': {
-                'dir/multiglob.https.any.worker.html': {
-                    'expected': 'PASS',
-                    'actual': 'FAIL',
-                    'artifacts': {
-                        'wpt_actual_status': ['OK'],
-                        'wpt_actual_metadata':
-                        ['dir/multiglob worker actual text'],
-                    },
-                },
-            },
-            'path_delimiter': os.path.sep,
-        }
-        self._create_json_output(json_dict)
-        # Also create a checked-in metadata file for this test. This filename
-        # matches the test *file* name, not the test name (which includes test
-        # scope).
-        self.host.filesystem.write_text_file(
-            os.path.join(TESTS_ROOT_DIR,
-                         "dir/multiglob.https.any.js.ini"),
-            "dir/multiglob checked-in metadata")
-        self.wpt_adapter.do_post_test_run_tasks()
-        written_files = self.wpt_adapter.fs.written_files
-        artifact_subdir = os.path.join(
-            self.wpt_adapter.layout_test_results_subdir,
-            "external", "wpt")
-        actual_path = os.path.join(artifact_subdir,
-                                   "dir/multiglob.https.any.worker-actual.txt")
-        self.assertEqual("dir/multiglob worker actual text",
-                         written_files[actual_path].decode(encoding='utf-8'))
-        # The checked-in metadata file gets renamed from .ini to -expected.txt
-        expected_path = os.path.join(
-            artifact_subdir,
-            "dir/multiglob.https.any.worker-expected.txt")
-        self.assertEqual("dir/multiglob checked-in metadata",
-                         written_files[expected_path].decode(encoding='utf-8'))
-        # Ensure the artifacts in the json were replaced with the locations of
-        # the newly-created files.
-        updated_json = self._load_json_output()
-        self.assertFalse(
-            "wpt_actual_metadata" in updated_json["tests"]["external"]["wpt"]
-                ["dir/multiglob.https.any.worker.html"]["artifacts"])
-        self.assertEqual(
-            [actual_path],
-            updated_json["tests"]["external"]["wpt"]
-                ["dir/multiglob.https.any.worker.html"]["artifacts"]
-                ["actual_text"])
-        self.assertEqual(
-            [expected_path],
-            updated_json["tests"]["external"]["wpt"]
-                ["dir/multiglob.https.any.worker.html"]["artifacts"]
-                ["expected_text"])
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/testing/test.gni b/testing/test.gni
index bd44d2ef..eba1b44 100644
--- a/testing/test.gni
+++ b/testing/test.gni
@@ -45,7 +45,7 @@
   import("//build/config/fuchsia/generate_runner_scripts.gni")
   import("//build/config/fuchsia/package.gni")
   import("//third_party/fuchsia-sdk/sdk/build/cmc.gni")
-} else if ((is_chromeos_ash || is_chromeos_lacros) && is_chromeos_device) {
+} else if (is_chromeos && is_chromeos_device) {
   import("//build/config/chromeos/rules.gni")
   import("//build/config/sanitizers/sanitizers.gni")
   import("//build/util/generate_wrapper.gni")
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index e86ad82..607917a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2394,21 +2394,6 @@
             ]
         }
     ],
-    "CredentialProviderExtensionPromo": [
-        {
-            "platforms": [
-                "ios"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "CredentialProviderExtensionPromo"
-                    ]
-                }
-            ]
-        }
-    ],
     "CriticalPersistedTabDataV2": [
         {
             "platforms": [
@@ -5725,36 +5710,11 @@
             ],
             "experiments": [
                 {
-                    "name": "EnabledExploreAndServerRankingSegmentation2",
-                    "params": {
-                        "base_url": "https://chromeupboarding-pa.googleapis.com",
-                        "experiment_tag": "{maxLevels : 1, rankTiles : true}",
-                        "image_prefetch_mode": "top",
-                        "is_unmetered_network_required": "false",
-                        "max_trending_tile_impressions": "1",
-                        "most_visited_max_rows_normal_screen": "1",
-                        "most_visited_max_rows_small_screen": "1",
-                        "mv_tile_click_threshold": "1",
-                        "small_screen_height_threshold_dp": "700"
-                    },
-                    "enable_features": [
-                        "QueryTiles",
-                        "QueryTilesInNTP",
-                        "QueryTilesLocalOrdering",
-                        "QueryTilesRemoveTrendingAfterInactivity",
-                        "QueryTilesSegmentation"
-                    ],
-                    "disable_features": [
-                        "QueryTilesEnableQueryEditing",
-                        "QueryTilesInOmnibox"
-                    ]
-                },
-                {
-                    "name": "EnabledExploreAndTrendingSegmentation2",
+                    "name": "EnabledExploreAndServerRankingAndRawTrendingSegmentation2",
                     "params": {
                         "base_url": "https://chromeupboarding-pa.googleapis.com",
                         "behavioural_targeting": "model_comparison",
-                        "experiment_tag": "{maxLevels : 1, enableTrending : true, maxTrendingQueries : 8}",
+                        "experiment_tag": "{maxLevels : 1, rankTiles : true, enableTrending : true, maxTrendingQueries : 8, disableEntityTranslation: true}",
                         "image_prefetch_mode": "top",
                         "is_unmetered_network_required": "false",
                         "max_trending_tile_impressions": "1",
@@ -5777,11 +5737,11 @@
                     ]
                 },
                 {
-                    "name": "EnabledExploreAndServerRankingAndRawTrendingSegmentation2",
+                    "name": "EnabledExploreAndTrendingSegmentation2",
                     "params": {
                         "base_url": "https://chromeupboarding-pa.googleapis.com",
                         "behavioural_targeting": "model_comparison",
-                        "experiment_tag": "{maxLevels : 1, rankTiles : true, enableTrending : true, maxTrendingQueries : 8, disableEntityTranslation: true}",
+                        "experiment_tag": "{maxLevels : 1, enableTrending : true, maxTrendingQueries : 8}",
                         "image_prefetch_mode": "top",
                         "is_unmetered_network_required": "false",
                         "max_trending_tile_impressions": "1",
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 2ca39a53..7fbd224 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2549,6 +2549,14 @@
   }
 }
 
+void Element::InvokePopup(Element* invoker) {
+  DCHECK(invoker);
+  DCHECK(RuntimeEnabledFeatures::HTMLPopupAttributeEnabled());
+  DCHECK(HasValidPopupAttribute());
+  GetPopupData()->setInvoker(invoker);
+  showPopup();
+}
+
 bool Element::HasLegalLinkAttribute(const QualifiedName&) const {
   return false;
 }
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 9a586c0..f89b7414 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -542,6 +542,7 @@
   void hidePopup();
   static const Element* NearestOpenAncestralPopup(Node* start_node);
   static void HandlePopupLightDismiss(const Event& event);
+  void InvokePopup(Element* invoker);
 
   virtual bool HasLegalLinkAttribute(const QualifiedName&) const;
   virtual const QualifiedName& SubResourceAttributeName() const;
diff --git a/third_party/blink/renderer/core/html/blocking_attribute.cc b/third_party/blink/renderer/core/html/blocking_attribute.cc
index 8375dc2..dc945d9 100644
--- a/third_party/blink/renderer/core/html/blocking_attribute.cc
+++ b/third_party/blink/renderer/core/html/blocking_attribute.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/space_split_string.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
@@ -26,6 +27,15 @@
   return tokens;
 }
 
+// static
+bool BlockingAttribute::IsRenderBlocking(const String& attribute_value) {
+  if (!RuntimeEnabledFeatures::BlockingAttributeEnabled())
+    return false;
+  if (attribute_value.IsEmpty())
+    return false;
+  return SpaceSplitString(AtomicString(attribute_value)).Contains(kRenderToken);
+}
+
 bool BlockingAttribute::ValidateTokenValue(const AtomicString& token_value,
                                            ExceptionState&) const {
   DCHECK(RuntimeEnabledFeatures::BlockingAttributeEnabled());
diff --git a/third_party/blink/renderer/core/html/blocking_attribute.h b/third_party/blink/renderer/core/html/blocking_attribute.h
index 109b89f58..d30d68d 100644
--- a/third_party/blink/renderer/core/html/blocking_attribute.h
+++ b/third_party/blink/renderer/core/html/blocking_attribute.h
@@ -20,6 +20,7 @@
   explicit BlockingAttribute(Element* element)
       : DOMTokenList(*element, html_names::kBlockingAttr) {}
 
+  static bool IsRenderBlocking(const String& attribute_value);
   bool IsRenderBlocking() const { return contains(kRenderToken); }
 
   void CountTokenUsage();
diff --git a/third_party/blink/renderer/core/html/forms/html_button_element.cc b/third_party/blink/renderer/core/html/forms/html_button_element.cc
index 2098d13..b8d85c4 100644
--- a/third_party/blink/renderer/core/html/forms/html_button_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_button_element.cc
@@ -110,10 +110,8 @@
 
 void HTMLButtonElement::DefaultEventHandler(Event& event) {
   if (event.type() == event_type_names::kDOMActivate) {
-    Element* popupElement =
-        GetDocument().getElementById(getAttribute(html_names::kPopupAttr));
-    if (popupElement && IsA<HTMLPopupElement>(popupElement)) {
-      To<HTMLPopupElement>(popupElement)->Invoke(this);
+    if (Element* popupElement = triggerPopupElement()) {
+      popupElement->InvokePopup(this);
     }
     if (!IsDisabledFormControl()) {
       if (Form() && type_ == kSubmit) {
@@ -133,6 +131,21 @@
   HTMLFormControlElement::DefaultEventHandler(event);
 }
 
+Element* HTMLButtonElement::triggerPopupElement() const {
+  if (!RuntimeEnabledFeatures::HTMLPopupAttributeEnabled())
+    return nullptr;
+  const AtomicString& trigger_id =
+      FastGetAttribute(html_names::kTriggerpopupAttr);
+  if (trigger_id.IsNull())
+    return nullptr;
+  if (!IsInTreeScope())
+    return nullptr;
+  Element* popup_element = GetTreeScope().getElementById(trigger_id);
+  if (!popup_element || !popup_element->HasValidPopupAttribute())
+    return nullptr;
+  return popup_element;
+}
+
 bool HTMLButtonElement::HasActivationBehavior() const {
   return true;
 }
diff --git a/third_party/blink/renderer/core/html/forms/html_button_element.h b/third_party/blink/renderer/core/html/forms/html_button_element.h
index 8d2b0948..847fd6f 100644
--- a/third_party/blink/renderer/core/html/forms/html_button_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_button_element.h
@@ -61,6 +61,10 @@
   void DefaultEventHandler(Event&) override;
   bool HasActivationBehavior() const override;
 
+  // Retrieves the element pointed to by the 'triggerpopup' content attribute,
+  // if that element a) exists, and b) is a valid Popup element.
+  Element* triggerPopupElement() const;
+
   void AppendToFormData(FormData&) override;
 
   bool IsEnumeratable() const override { return true; }
diff --git a/third_party/blink/renderer/core/html/html_attribute_names.json5 b/third_party/blink/renderer/core/html/html_attribute_names.json5
index f87f051..fb9881c 100644
--- a/third_party/blink/renderer/core/html/html_attribute_names.json5
+++ b/third_party/blink/renderer/core/html/html_attribute_names.json5
@@ -334,6 +334,7 @@
     "title",
     "topmargin",
     "translate",
+    "triggerpopup",
     "truespeed",
     "trusttoken",
     "type",
diff --git a/third_party/blink/renderer/core/html/html_link_element.cc b/third_party/blink/renderer/core/html/html_link_element.cc
index 7401af7..35b48d5 100644
--- a/third_party/blink/renderer/core/html/html_link_element.cc
+++ b/third_party/blink/renderer/core/html/html_link_element.cc
@@ -324,10 +324,6 @@
   if (rel_attribute_.IsLinkPrefetch()) {
     UseCounter::Count(GetDocument(), WebFeature::kLinkPrefetchLoadEvent);
   }
-  if (RenderBlockingResourceManager* manager =
-          GetDocument().GetRenderBlockingResourceManager()) {
-    manager->RemovePendingPreload(*this);
-  }
   DispatchEvent(*Event::Create(event_type_names::kLoad));
 }
 
@@ -335,10 +331,6 @@
   if (rel_attribute_.IsLinkPrefetch()) {
     UseCounter::Count(GetDocument(), WebFeature::kLinkPrefetchErrorEvent);
   }
-  if (RenderBlockingResourceManager* manager =
-          GetDocument().GetRenderBlockingResourceManager()) {
-    manager->RemovePendingPreload(*this);
-  }
   DispatchEvent(*Event::Create(event_type_names::kError));
 }
 
@@ -446,17 +438,6 @@
   return scopes_.Get();
 }
 
-bool HTMLLinkElement::IsRenderBlockingPreload() const {
-  if (!RuntimeEnabledFeatures::BlockingAttributeEnabled())
-    return false;
-  return (rel_attribute_.IsLinkPreload() || rel_attribute_.IsModulePreload()) &&
-         blocking_attribute_->IsRenderBlocking();
-}
-
-bool HTMLLinkElement::IsFontPreload() const {
-  return rel_attribute_.IsLinkPreload() && EqualIgnoringASCIICase(as_, "font");
-}
-
 void HTMLLinkElement::Trace(Visitor* visitor) const {
   visitor->Trace(link_);
   visitor->Trace(sizes_);
diff --git a/third_party/blink/renderer/core/html/html_link_element.h b/third_party/blink/renderer/core/html/html_link_element.h
index ab18bf25..905e62f 100644
--- a/third_party/blink/renderer/core/html/html_link_element.h
+++ b/third_party/blink/renderer/core/html/html_link_element.h
@@ -110,8 +110,6 @@
   // From LinkLoaderClient
   bool ShouldLoadLink() override;
   bool IsLinkCreatedByParser() override;
-  bool IsRenderBlockingPreload() const override;
-  bool IsFontPreload() const override;
 
   // For LinkStyle
   bool LoadLink(const LinkLoadParameters&);
diff --git a/third_party/blink/renderer/core/html/link_style.cc b/third_party/blink/renderer/core/html/link_style.cc
index 8d0faf3..4e22b48 100644
--- a/third_party/blink/renderer/core/html/link_style.cc
+++ b/third_party/blink/renderer/core/html/link_style.cc
@@ -331,7 +331,8 @@
       owner_->GetReferrerPolicy(),
       owner_->GetNonEmptyURLAttribute(html_names::kHrefAttr),
       owner_->FastGetAttribute(html_names::kImagesrcsetAttr),
-      owner_->FastGetAttribute(html_names::kImagesizesAttr));
+      owner_->FastGetAttribute(html_names::kImagesizesAttr),
+      owner_->FastGetAttribute(html_names::kBlockingAttr));
 
   WTF::TextEncoding charset = GetCharset();
 
diff --git a/third_party/blink/renderer/core/inspector/thread_debugger.cc b/third_party/blink/renderer/core/inspector/thread_debugger.cc
index 176ad7e6..d010fba 100644
--- a/third_party/blink/renderer/core/inspector/thread_debugger.cc
+++ b/third_party/blink/renderer/core/inspector/thread_debugger.cc
@@ -26,6 +26,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_trusted_script.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_trusted_script_url.h"
 #include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/events/error_event.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.h"
@@ -627,6 +628,25 @@
   return result;
 }
 
+void ThreadDebugger::dispatchError(v8::Local<v8::Context> context,
+                                   v8::Local<v8::Message> message,
+                                   v8::Local<v8::Value> exception) {
+  ScriptState* script_state = ScriptState::From(context);
+  ExecutionContext* execution_context = ExecutionContext::From(script_state);
+
+  // Simulate an ErrorEvent, but prevent default behavior (triggering an
+  // uncaught exception reported in DevTools).
+  ErrorEvent* event = ErrorEvent::Create(
+      ToCoreStringWithNullCheck(message->Get()),
+      SourceLocation::FromMessage(script_state->GetIsolate(), message,
+                                  execution_context),
+      ScriptValue::From(script_state, exception), &script_state->World());
+  event->preventDefault();
+
+  execution_context->DispatchErrorEvent(event,
+                                        SanitizeScriptErrors::kDoNotSanitize);
+}
+
 void ThreadDebugger::OnTimer(TimerBase* timer) {
   for (wtf_size_t index = 0; index < timers_.size(); ++index) {
     if (timers_[index].get() == timer) {
diff --git a/third_party/blink/renderer/core/inspector/thread_debugger.h b/third_party/blink/renderer/core/inspector/thread_debugger.h
index 26b9013..985f834e 100644
--- a/third_party/blink/renderer/core/inspector/thread_debugger.h
+++ b/third_party/blink/renderer/core/inspector/thread_debugger.h
@@ -99,6 +99,9 @@
                            void* data) override;
   void cancelTimer(void* data) override;
   int64_t generateUniqueId() override;
+  void dispatchError(v8::Local<v8::Context>,
+                     v8::Local<v8::Message>,
+                     v8::Local<v8::Value> exception) final;
 
   void OnTimer(TimerBase*);
 
diff --git a/third_party/blink/renderer/core/layout/layout_counter.cc b/third_party/blink/renderer/core/layout/layout_counter.cc
index d8582a02..d45478b3 100644
--- a/third_party/blink/renderer/core/layout/layout_counter.cc
+++ b/third_party/blink/renderer/core/layout/layout_counter.cc
@@ -63,8 +63,8 @@
 }
 
 Element* AncestorStyleContainmentObject(const Element& element) {
-  for (Element* ancestor = FlatTreeTraversal::ParentElement(element); ancestor;
-       ancestor = FlatTreeTraversal::ParentElement(*ancestor)) {
+  for (Element* ancestor = element.GetStyleRecalcParent(); ancestor;
+       ancestor = ancestor->GetStyleRecalcParent()) {
     if (const ComputedStyle* style = ancestor->GetComputedStyle()) {
       if (style->ContainsStyle())
         return ancestor;
diff --git a/third_party/blink/renderer/core/loader/build.gni b/third_party/blink/renderer/core/loader/build.gni
index a0428b0..ade2715a 100644
--- a/third_party/blink/renderer/core/loader/build.gni
+++ b/third_party/blink/renderer/core/loader/build.gni
@@ -59,6 +59,8 @@
   "link_loader.cc",
   "link_loader.h",
   "link_loader_client.h",
+  "pending_link_preload.h",
+  "pending_link_preload.cc",
   "loader_factory_for_frame.cc",
   "loader_factory_for_frame.h",
   "loader_factory_for_worker.cc",
diff --git a/third_party/blink/renderer/core/loader/link_load_parameters.cc b/third_party/blink/renderer/core/loader/link_load_parameters.cc
index 2a57de5f..d7b62bae 100644
--- a/third_party/blink/renderer/core/loader/link_load_parameters.cc
+++ b/third_party/blink/renderer/core/loader/link_load_parameters.cc
@@ -21,7 +21,8 @@
     network::mojom::ReferrerPolicy referrer_policy,
     const KURL& href,
     const String& image_srcset,
-    const String& image_sizes)
+    const String& image_sizes,
+    const String& blocking)
     : rel(rel),
       cross_origin(cross_origin),
       type(type),
@@ -33,7 +34,8 @@
       referrer_policy(referrer_policy),
       href(href),
       image_srcset(image_srcset),
-      image_sizes(image_sizes) {}
+      image_sizes(image_sizes),
+      blocking(blocking) {}
 
 // TODO(domfarolino)
 // Eventually we'll want to support a |fetchpriority| value on
diff --git a/third_party/blink/renderer/core/loader/link_load_parameters.h b/third_party/blink/renderer/core/loader/link_load_parameters.h
index ac5e249..6733c50 100644
--- a/third_party/blink/renderer/core/loader/link_load_parameters.h
+++ b/third_party/blink/renderer/core/loader/link_load_parameters.h
@@ -30,7 +30,10 @@
                      network::mojom::ReferrerPolicy,
                      const KURL& href,
                      const String& image_srcset,
-                     const String& image_sizes);
+                     const String& image_sizes,
+                     // TODO(xiaochengh): The default parameter is temporarily
+                     // introduced to reduce patch diff. Remove it later.
+                     const String& blocking = String());
   LinkLoadParameters(const LinkHeader&, const KURL& base_url);
 
   LinkRelAttribute rel;
@@ -45,6 +48,7 @@
   KURL href;
   String image_srcset;
   String image_sizes;
+  String blocking;
   absl::optional<base::UnguessableToken> recursive_prefetch_token;
 };
 
diff --git a/third_party/blink/renderer/core/loader/link_loader.cc b/third_party/blink/renderer/core/loader/link_loader.cc
index 4562308..2149621e 100644
--- a/third_party/blink/renderer/core/loader/link_loader.cc
+++ b/third_party/blink/renderer/core/loader/link_loader.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/renderer/core/loader/fetch_priority_attribute.h"
 #include "third_party/blink/renderer/core/loader/link_load_parameters.h"
 #include "third_party/blink/renderer/core/loader/link_loader_client.h"
+#include "third_party/blink/renderer/core/loader/pending_link_preload.h"
 #include "third_party/blink/renderer/core/loader/preload_helper.h"
 #include "third_party/blink/renderer/core/loader/prerender_handle.h"
 #include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
@@ -78,55 +79,11 @@
 
 }  // namespace
 
-class LinkLoader::FinishObserver final : public ResourceFinishObserver {
-  USING_PRE_FINALIZER(FinishObserver, ClearResource);
-
- public:
-  FinishObserver(LinkLoader* loader, Resource* resource)
-      : loader_(loader), resource_(resource) {
-    resource_->AddFinishObserver(
-        this, loader_->client_->GetLoadingTaskRunner().get());
-  }
-
-  // ResourceFinishObserver implementation
-  void NotifyFinished() override {
-    if (!resource_)
-      return;
-    loader_->NotifyFinished();
-    ClearResource();
-  }
-  String DebugName() const override {
-    return "LinkLoader::ResourceFinishObserver";
-  }
-
-  Resource* GetResource() { return resource_; }
-  void ClearResource() {
-    if (!resource_)
-      return;
-    resource_->RemoveFinishObserver(this);
-    resource_ = nullptr;
-  }
-
-  void Trace(Visitor* visitor) const override {
-    visitor->Trace(loader_);
-    visitor->Trace(resource_);
-    blink::ResourceFinishObserver::Trace(visitor);
-  }
-
- private:
-  Member<LinkLoader> loader_;
-  Member<Resource> resource_;
-};
-
 LinkLoader::LinkLoader(LinkLoaderClient* client) : client_(client) {
   DCHECK(client_);
 }
 
-LinkLoader::~LinkLoader() = default;
-
-void LinkLoader::NotifyFinished() {
-  DCHECK(finish_observer_);
-  Resource* resource = finish_observer_->GetResource();
+void LinkLoader::NotifyFinished(Resource* resource) {
   if (resource->ErrorOccurred() ||
       (resource->IsLinkPreload() &&
        resource->IntegrityDisposition() ==
@@ -139,9 +96,9 @@
 
 // https://html.spec.whatwg.org/C/#link-type-modulepreload
 void LinkLoader::NotifyModuleLoadFinished(ModuleScript* module) {
-  // Step 11. "If result is null, fire an event named error at the link element,
+  // Step 14. "If result is null, fire an event named error at the link element,
   // and return." [spec text]
-  // Step 12. "Fire an event named load at the link element." [spec text]
+  // Step 15. "Fire an event named load at the link element." [spec text]
   if (!module)
     client_->LinkLoadingErrored();
   else
@@ -149,7 +106,7 @@
 }
 
 Resource* LinkLoader::GetResourceForTesting() {
-  return finish_observer_ ? finish_observer_->GetResource() : nullptr;
+  return pending_preload_ ? pending_preload_->GetResourceForTesting() : nullptr;
 }
 
 bool LinkLoader::LoadLink(const LinkLoadParameters& params,
@@ -160,36 +117,23 @@
   if (!client_->ShouldLoadLink())
     return false;
 
-  if (RenderBlockingResourceManager* manager =
-          document.GetRenderBlockingResourceManager()) {
-    if (client_->IsRenderBlockingPreload()) {
-      manager->AddPendingPreload(
-          *client_, RenderBlockingResourceManager::PreloadType::kRegular);
-    } else if (client_->IsFontPreload()) {
-      manager->AddPendingPreload(
-          *client_,
-          RenderBlockingResourceManager::PreloadType::kShortBlockingFont);
-    }
-  }
-
   PreloadHelper::DnsPrefetchIfNeeded(params, &document, document.GetFrame(),
                                      PreloadHelper::kLinkCalledFromMarkup);
 
   PreloadHelper::PreconnectIfNeeded(params, &document, document.GetFrame(),
                                     PreloadHelper::kLinkCalledFromMarkup);
 
-  Resource* resource = PreloadHelper::PreloadIfNeeded(
+  pending_preload_ = MakeGarbageCollected<PendingLinkPreload>(document, this);
+
+  PreloadHelper::PreloadIfNeeded(
       params, document, NullURL(), PreloadHelper::kLinkCalledFromMarkup,
       nullptr /* viewport_description */,
-      client_->IsLinkCreatedByParser() ? kParserInserted : kNotParserInserted);
-  if (!resource) {
-    resource = PreloadHelper::PrefetchIfNeeded(params, document);
-  }
-  if (resource)
-    finish_observer_ = MakeGarbageCollected<FinishObserver>(this, resource);
-
+      client_->IsLinkCreatedByParser() ? kParserInserted : kNotParserInserted,
+      pending_preload_);
+  if (!pending_preload_->HasResource())
+    PreloadHelper::PrefetchIfNeeded(params, document, pending_preload_);
   PreloadHelper::ModulePreloadIfNeeded(
-      params, document, nullptr /* viewport_description */, this);
+      params, document, nullptr /* viewport_description */, pending_preload_);
 
   absl::optional<mojom::blink::PrerenderTriggerType> trigger_type =
       PrerenderTriggerTypeFromRelAttribute(params.rel, document);
@@ -254,17 +198,16 @@
     prerender_->Cancel();
     prerender_.Clear();
   }
-  if (finish_observer_) {
-    finish_observer_->ClearResource();
-    finish_observer_ = nullptr;
+  if (pending_preload_) {
+    pending_preload_->Dispose();
+    pending_preload_.Clear();
   }
 }
 
 void LinkLoader::Trace(Visitor* visitor) const {
-  visitor->Trace(finish_observer_);
   visitor->Trace(client_);
+  visitor->Trace(pending_preload_);
   visitor->Trace(prerender_);
-  SingleModuleClient::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/link_loader.h b/third_party/blink/renderer/core/loader/link_loader.h
index faa2b9a..45462f2 100644
--- a/third_party/blink/renderer/core/loader/link_loader.h
+++ b/third_party/blink/renderer/core/loader/link_loader.h
@@ -34,23 +34,23 @@
 
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/loader/link_load_parameters.h"
-#include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h"
 
 namespace blink {
 
 class Document;
 class LinkLoaderClient;
+class PendingLinkPreload;
+class ModuleScript;
 class PrerenderHandle;
 class Resource;
 class ResourceClient;
 
 // The LinkLoader can load link rel types icon, dns-prefetch, prefetch, and
 // prerender.
-class CORE_EXPORT LinkLoader final : public SingleModuleClient {
+class CORE_EXPORT LinkLoader final : public GarbageCollected<LinkLoader> {
  public:
   explicit LinkLoader(LinkLoaderClient*);
-  ~LinkLoader() override;
 
   void Abort();
   bool LoadLink(const LinkLoadParameters&, Document&);
@@ -64,17 +64,14 @@
 
   Resource* GetResourceForTesting();
 
-  void Trace(Visitor*) const override;
+  void NotifyModuleLoadFinished(ModuleScript*);
+  void NotifyFinished(Resource*);
+
+  void Trace(Visitor*) const;
 
  private:
-  class FinishObserver;
-
-  void NotifyFinished();
-  // SingleModuleClient implementation
-  void NotifyModuleLoadFinished(ModuleScript*) override;
-
-  Member<FinishObserver> finish_observer_;
   Member<LinkLoaderClient> client_;
+  Member<PendingLinkPreload> pending_preload_;
 
   Member<PrerenderHandle> prerender_;
 };
diff --git a/third_party/blink/renderer/core/loader/link_loader_client.h b/third_party/blink/renderer/core/loader/link_loader_client.h
index 4525441..d5d1716 100644
--- a/third_party/blink/renderer/core/loader/link_loader_client.h
+++ b/third_party/blink/renderer/core/loader/link_loader_client.h
@@ -45,18 +45,13 @@
 
   virtual bool ShouldLoadLink() = 0;
 
-  // Returns true if the link is a render-blocking preload or modulepreload.
-  // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#render-blocking
-  virtual bool IsRenderBlockingPreload() const = 0;
-
-  virtual bool IsFontPreload() const = 0;
-
   virtual void LinkLoaded() = 0;
   virtual void LinkLoadingErrored() = 0;
   // There is no notification for cancellation.
 
   virtual bool IsLinkCreatedByParser() = 0;
 
+  // TODO(xiaochengh): Remove this unused function.
   virtual scoped_refptr<base::SingleThreadTaskRunner>
   GetLoadingTaskRunner() = 0;
 };
diff --git a/third_party/blink/renderer/core/loader/link_loader_test.cc b/third_party/blink/renderer/core/loader/link_loader_test.cc
index bac02cc..b9903b3 100644
--- a/third_party/blink/renderer/core/loader/link_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/link_loader_test.cc
@@ -50,9 +50,6 @@
   bool ShouldLoadLink() override { return should_load_; }
   bool IsLinkCreatedByParser() override { return true; }
 
-  bool IsRenderBlockingPreload() const override { return false; }
-  bool IsFontPreload() const override { return false; }
-
   void LinkLoaded() override {}
   void LinkLoadingErrored() override {}
 
diff --git a/third_party/blink/renderer/core/loader/pending_link_preload.cc b/third_party/blink/renderer/core/loader/pending_link_preload.cc
new file mode 100644
index 0000000..94d3195f
--- /dev/null
+++ b/third_party/blink/renderer/core/loader/pending_link_preload.cc
@@ -0,0 +1,111 @@
+// 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/loader/pending_link_preload.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/loader/link_loader.h"
+#include "third_party/blink/renderer/core/loader/preload_helper.h"
+#include "third_party/blink/renderer/platform/heap/prefinalizer.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_finish_observer.h"
+
+namespace blink {
+
+class PendingLinkPreload::FinishObserver final : public ResourceFinishObserver {
+  USING_PRE_FINALIZER(FinishObserver, Dispose);
+
+ public:
+  FinishObserver(PendingLinkPreload* pending_preload, Resource* resource)
+      : pending_preload_(pending_preload), resource_(resource) {
+    resource_->AddFinishObserver(
+        this, pending_preload_->GetLoadingTaskRunner().get());
+  }
+
+  // ResourceFinishObserver implementation
+  void NotifyFinished() override {
+    if (!resource_)
+      return;
+    pending_preload_->NotifyFinished();
+    Dispose();
+  }
+  String DebugName() const override {
+    return "PendingLinkPreload::FinishObserver";
+  }
+
+  Resource* GetResource() { return resource_; }
+  void Dispose() {
+    if (!resource_)
+      return;
+    resource_->RemoveFinishObserver(this);
+    resource_ = nullptr;
+  }
+
+  void Trace(Visitor* visitor) const override {
+    visitor->Trace(pending_preload_);
+    visitor->Trace(resource_);
+    blink::ResourceFinishObserver::Trace(visitor);
+  }
+
+ private:
+  Member<PendingLinkPreload> pending_preload_;
+  Member<Resource> resource_;
+};
+
+PendingLinkPreload::PendingLinkPreload(Document& document, LinkLoader* loader)
+    : document_(document), loader_(loader) {}
+
+PendingLinkPreload::~PendingLinkPreload() = default;
+
+void PendingLinkPreload::AddResource(Resource* resource) {
+  DCHECK(!finish_observer_);
+  if (resource)
+    finish_observer_ = MakeGarbageCollected<FinishObserver>(this, resource);
+}
+
+// https://html.spec.whatwg.org/C/#link-type-modulepreload
+void PendingLinkPreload::NotifyModuleLoadFinished(ModuleScript* module) {
+  // Step 13. "Unblock rendering on element."
+  UnblockRendering();
+  if (loader_)
+    loader_->NotifyModuleLoadFinished(module);
+}
+
+void PendingLinkPreload::NotifyFinished() {
+  UnblockRendering();
+  DCHECK(finish_observer_);
+  if (loader_)
+    loader_->NotifyFinished(finish_observer_->GetResource());
+}
+
+void PendingLinkPreload::UnblockRendering() {
+  if (RenderBlockingResourceManager* manager =
+          document_->GetRenderBlockingResourceManager()) {
+    manager->RemovePendingPreload(*this);
+  }
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+PendingLinkPreload::GetLoadingTaskRunner() {
+  return document_->GetTaskRunner(TaskType::kNetworking);
+}
+
+void PendingLinkPreload::Dispose() {
+  UnblockRendering();
+  if (finish_observer_)
+    finish_observer_->Dispose();
+  finish_observer_ = nullptr;
+}
+
+Resource* PendingLinkPreload::GetResourceForTesting() {
+  return finish_observer_ ? finish_observer_->GetResource() : nullptr;
+}
+
+void PendingLinkPreload::Trace(Visitor* visitor) const {
+  visitor->Trace(document_);
+  visitor->Trace(loader_);
+  visitor->Trace(finish_observer_);
+  SingleModuleClient::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/pending_link_preload.h b/third_party/blink/renderer/core/loader/pending_link_preload.h
new file mode 100644
index 0000000..82b6606
--- /dev/null
+++ b/third_party/blink/renderer/core/loader/pending_link_preload.h
@@ -0,0 +1,51 @@
+// 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_LOADER_PENDING_LINK_PRELOAD_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PENDING_LINK_PRELOAD_H_
+
+#include "third_party/blink/renderer/core/loader/link_load_parameters.h"
+#include "third_party/blink/renderer/core/script/modulator.h"
+
+namespace blink {
+
+class Document;
+class LinkLoader;
+class Resource;
+
+// Represents a pending preload, prefetch or modulepreload link. Receives
+// callbacks when the loading finishes or errors.
+class PendingLinkPreload final : public SingleModuleClient {
+ public:
+  PendingLinkPreload(Document& document, LinkLoader* loader);
+  ~PendingLinkPreload() override;
+
+  void UnblockRendering();
+  void Dispose();
+
+  void AddResource(Resource*);
+
+  bool HasResource() const { return finish_observer_.Get(); }
+  Resource* GetResourceForTesting();
+
+  void Trace(Visitor*) const override;
+
+ private:
+  class FinishObserver;
+
+  // SingleModuleClient implementation
+  void NotifyModuleLoadFinished(ModuleScript*) override;
+
+  void NotifyFinished();
+
+  scoped_refptr<base::SingleThreadTaskRunner> GetLoadingTaskRunner();
+
+  Member<Document> document_;
+  Member<LinkLoader> loader_;
+  Member<FinishObserver> finish_observer_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_PENDING_LINK_PRELOAD_H_
diff --git a/third_party/blink/renderer/core/loader/preload_helper.cc b/third_party/blink/renderer/core/loader/preload_helper.cc
index 6002e68..aab33a4 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.cc
+++ b/third_party/blink/renderer/core/loader/preload_helper.cc
@@ -21,6 +21,7 @@
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/viewport_data.h"
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/html/blocking_attribute.h"
 #include "third_party/blink/renderer/core/html/parser/html_preload_scanner.h"
 #include "third_party/blink/renderer/core/html/parser/html_srcset_parser.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -30,6 +31,7 @@
 #include "third_party/blink/renderer/core/loader/link_load_parameters.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_script_creation_params.h"
 #include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h"
+#include "third_party/blink/renderer/core/loader/pending_link_preload.h"
 #include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
 #include "third_party/blink/renderer/core/loader/resource/font_resource.h"
 #include "third_party/blink/renderer/core/loader/resource/image_resource.h"
@@ -257,7 +259,8 @@
     const KURL& base_url,
     LinkCaller caller,
     const ViewportDescription* viewport_description,
-    ParserDisposition parser_disposition) {
+    ParserDisposition parser_disposition,
+    PendingLinkPreload* pending_preload) {
   if (!document.Loader() || !params.rel.IsLinkPreload())
     return nullptr;
 
@@ -380,8 +383,27 @@
         String("Preload triggered for " + url.Host() + url.GetPath())));
   }
   link_fetch_params.SetLinkPreload(true);
-  return PreloadHelper::StartPreload(resource_type.value(), link_fetch_params,
-                                     document);
+
+  if (pending_preload) {
+    if (RenderBlockingResourceManager* manager =
+            document.GetRenderBlockingResourceManager()) {
+      if (BlockingAttribute::IsRenderBlocking(params.blocking)) {
+        manager->AddPendingPreload(
+            *pending_preload,
+            RenderBlockingResourceManager::PreloadType::kRegular);
+      } else if (EqualIgnoringASCIICase(params.as, "font")) {
+        manager->AddPendingPreload(
+            *pending_preload,
+            RenderBlockingResourceManager::PreloadType::kShortBlockingFont);
+      }
+    }
+  }
+
+  Resource* resource = PreloadHelper::StartPreload(resource_type.value(),
+                                                   link_fetch_params, document);
+  if (pending_preload)
+    pending_preload->AddResource(resource);
+  return resource;
 }
 
 // https://html.spec.whatwg.org/C/#link-type-modulepreload
@@ -389,7 +411,7 @@
     const LinkLoadParameters& params,
     Document& document,
     const ViewportDescription* viewport_description,
-    SingleModuleClient* client) {
+    PendingLinkPreload* client) {
   if (!document.Loader() || !params.rel.IsModulePreload())
     return;
 
@@ -504,7 +526,15 @@
                          RenderBlockingBehavior::kNonBlocking),
       Referrer::NoReferrer(), TextPosition::MinimumPosition());
 
-  // Step 11. "Fetch a single module script given url, settings object,
+  // Step 11. "If element is render-blocking, then block rendering on element."
+  if (client && BlockingAttribute::IsRenderBlocking(params.blocking)) {
+    if (document.GetRenderBlockingResourceManager()) {
+      document.GetRenderBlockingResourceManager()->AddPendingPreload(
+          *client, RenderBlockingResourceManager::PreloadType::kRegular);
+    }
+  }
+
+  // Step 12. "Fetch a single module script given url, settings object,
   // destination, options, settings object, "client", and with the top-level
   // module fetch flag set. Wait until algorithm asynchronously completes with
   // result." [spec text]
@@ -526,7 +556,8 @@
 }
 
 Resource* PreloadHelper::PrefetchIfNeeded(const LinkLoadParameters& params,
-                                          Document& document) {
+                                          Document& document,
+                                          PendingLinkPreload* pending_preload) {
   if (document.Loader() && document.Loader()->Archive()) {
     return nullptr;
   }
@@ -578,7 +609,11 @@
     link_fetch_params.SetSignedExchangePrefetchCacheEnabled(
         RuntimeEnabledFeatures::SignedExchangeSubresourcePrefetchEnabled(
             document.GetExecutionContext()));
-    return LinkPrefetchResource::Fetch(link_fetch_params, document.Fetcher());
+    Resource* resource =
+        LinkPrefetchResource::Fetch(link_fetch_params, document.Fetcher());
+    if (pending_preload)
+      pending_preload->AddResource(resource);
+    return resource;
   }
   return nullptr;
 }
@@ -679,10 +714,14 @@
     }
     if (can_load_resources != kDoNotLoadResources) {
       DCHECK(document);
+      // TODO(crbug.com/1271296): Pass a PendingLinkPreload to enable
+      // render-blocking on link headers.
       PreloadIfNeeded(params, *document, base_url, kLinkCalledFromHeader,
-                      viewport_description, kNotParserInserted);
-      PrefetchIfNeeded(params, *document);
-      ModulePreloadIfNeeded(params, *document, viewport_description, nullptr);
+                      viewport_description, kNotParserInserted,
+                      nullptr /* PendingLinkPreload */);
+      PrefetchIfNeeded(params, *document, nullptr /* PendingLinkPreload */);
+      ModulePreloadIfNeeded(params, *document, viewport_description,
+                            nullptr /* PendingLinkPreload */);
     }
     if (params.rel.IsServiceWorker()) {
       UseCounter::Count(document, WebFeature::kLinkHeaderServiceWorker);
diff --git a/third_party/blink/renderer/core/loader/preload_helper.h b/third_party/blink/renderer/core/loader/preload_helper.h
index 8621952..6559975 100644
--- a/third_party/blink/renderer/core/loader/preload_helper.h
+++ b/third_party/blink/renderer/core/loader/preload_helper.h
@@ -12,8 +12,8 @@
 
 class AlternateSignedExchangeResourceInfo;
 class Document;
+class PendingLinkPreload;
 class LocalFrame;
-class SingleModuleClient;
 struct LinkLoadParameters;
 struct ViewportDescription;
 
@@ -60,17 +60,20 @@
                                  Document*,
                                  LocalFrame*,
                                  LinkCaller);
-  static Resource* PrefetchIfNeeded(const LinkLoadParameters&, Document&);
+  static Resource* PrefetchIfNeeded(const LinkLoadParameters&,
+                                    Document&,
+                                    PendingLinkPreload*);
   static Resource* PreloadIfNeeded(const LinkLoadParameters&,
                                    Document&,
                                    const KURL& base_url,
                                    LinkCaller,
                                    const ViewportDescription*,
-                                   ParserDisposition);
+                                   ParserDisposition,
+                                   PendingLinkPreload*);
   static void ModulePreloadIfNeeded(const LinkLoadParameters&,
                                     Document&,
                                     const ViewportDescription*,
-                                    SingleModuleClient*);
+                                    PendingLinkPreload*);
 
   static absl::optional<ResourceType> GetResourceTypeFromAsAttribute(
       const String& as);
diff --git a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc
index b6534f4..c704f01 100644
--- a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc
+++ b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.cc
@@ -7,7 +7,7 @@
 #include "third_party/blink/renderer/core/css/font_face.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/html/html_document.h"
-#include "third_party/blink/renderer/core/loader/link_loader_client.h"
+#include "third_party/blink/renderer/core/loader/pending_link_preload.h"
 #include "third_party/blink/renderer/core/script/script_element_base.h"
 
 namespace blink {
@@ -58,7 +58,7 @@
       font_preload_timeout_(kMaxRenderingDelayForFontPreloads) {}
 
 void RenderBlockingResourceManager::AddPendingPreload(
-    const LinkLoaderClient& link,
+    const PendingLinkPreload& link,
     PreloadType type) {
   if (type == PreloadType::kShortBlockingFont && font_preload_timer_has_fired_)
     return;
@@ -87,7 +87,7 @@
 }
 
 void RenderBlockingResourceManager::RemovePendingPreload(
-    const LinkLoaderClient& link) {
+    const PendingLinkPreload& link) {
   auto iter = pending_preloads_.find(&link);
   if (iter == pending_preloads_.end())
     return;
@@ -110,7 +110,7 @@
 
 void RenderBlockingResourceManager::FontPreloadingTimerFired(TimerBase*) {
   font_preload_timer_has_fired_ = true;
-  VectorOf<const LinkLoaderClient> short_blocking_font_preloads;
+  VectorOf<const PendingLinkPreload> short_blocking_font_preloads;
   for (auto preload_and_type : pending_preloads_) {
     if (preload_and_type.value == PreloadType::kShortBlockingFont)
       short_blocking_font_preloads.push_back(preload_and_type.key);
diff --git a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h
index a17a6026..02f71fe5 100644
--- a/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h
+++ b/third_party/blink/renderer/core/loader/render_blocking_resource_manager.h
@@ -15,7 +15,7 @@
 
 class Document;
 class FontFace;
-class LinkLoaderClient;
+class PendingLinkPreload;
 class Node;
 class ScriptElementBase;
 
@@ -53,8 +53,8 @@
   // have a higher chance to be used by the first paint.
   // Design doc: https://bit.ly/36E8UKB
   enum class PreloadType { kRegular, kShortBlockingFont };
-  void AddPendingPreload(const LinkLoaderClient& link, PreloadType type);
-  void RemovePendingPreload(const LinkLoaderClient& link);
+  void AddPendingPreload(const PendingLinkPreload& link, PreloadType type);
+  void RemovePendingPreload(const PendingLinkPreload& link);
 
   void AddImperativeFontLoading(FontFace*);
   void RemoveImperativeFontLoading();
@@ -85,7 +85,7 @@
 
   // Tracks the currently pending render-blocking preload and modulepreload
   // links, including short-blocking font preloads.
-  HeapHashMap<WeakMember<const LinkLoaderClient>, PreloadType>
+  HeapHashMap<WeakMember<const PendingLinkPreload>, PreloadType>
       pending_preloads_;
 
   unsigned imperative_font_loading_count_ = 0;
diff --git a/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc b/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
index 656451c9..7002acf 100644
--- a/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
+++ b/third_party/blink/renderer/core/origin_trials/origin_trial_context.cc
@@ -517,7 +517,7 @@
     const String& trial_name) {
   if (trial_name == "PrivacySandboxAdsAPIs") {
     Vector<OriginTrialFeature> restricted;
-    if (!base::FeatureList::IsEnabled(features::kFledge))
+    if (!base::FeatureList::IsEnabled(features::kInterestGroupStorage))
       restricted.push_back(OriginTrialFeature::kFledge);
     if (!base::FeatureList::IsEnabled(features::kBrowsingTopics))
       restricted.push_back(OriginTrialFeature::kTopicsAPI);
diff --git a/third_party/blink/renderer/core/page/frame_tree.cc b/third_party/blink/renderer/core/page/frame_tree.cc
index b0aace99a..acfada1 100644
--- a/third_party/blink/renderer/core/page/frame_tree.cc
+++ b/third_party/blink/renderer/core/page/frame_tree.cc
@@ -283,8 +283,10 @@
   if (!page)
     return nullptr;
 
-  for (Frame* frame = page->MainFrame(); frame;
-       frame = frame->Tree().TraverseNext()) {
+  for (Frame *top = &this_frame_->Tree().Top(FrameTreeBoundary::kFenced),
+             *frame = top;
+       frame;
+       frame = frame->Tree().TraverseNext(top, FrameTreeBoundary::kFenced)) {
     // Skip descendants of this frame that were searched above to avoid
     // showing duplicate console messages if a frame is found by name
     // but access is blocked.
@@ -295,6 +297,14 @@
     }
   }
 
+  // In fenced frames, only resolve target names using the above lookup methods
+  // (keywords, descendants, and the rest of the frame tree within the fence).
+  // TODO(crbug.com/1262022): Remove this early return when we get rid of
+  // ShadowDOM fenced frames, because it is unnecessary in MPArch.
+  if (this_frame_->IsInFencedFrameTree()) {
+    return nullptr;
+  }
+
   // Search the entire tree of each of the other pages in this namespace.
   for (const Page* other_page : page->RelatedPages()) {
     if (other_page == page || other_page->IsClosing())
diff --git a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
index 68a5a539..514020cd 100644
--- a/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
+++ b/third_party/blink/renderer/modules/mediarecorder/video_track_recorder.cc
@@ -61,6 +61,21 @@
 
 namespace {
 
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+// (kLastHistogram being the only exception, as it does not map to a logged
+// value, and should be renumbered as new values are inserted.)
+enum {
+  kUnknownHistogram = 0,
+  kVp8SwHistogram = 1,
+  kVp8HwHistogram = 2,
+  kVp9SwHistogram = 3,
+  kVp9HwHistogram = 4,
+  kH264SwHistogram = 5,
+  kH264HwHistogram = 6,
+  kLastHistogram = 7,
+};
+
 static const struct {
   CodecId codec_id;
   media::VideoCodecProfile min_profile;
@@ -126,6 +141,45 @@
   return enumerator;
 }
 
+static void UmaHistogramForCodec(bool uses_acceleration, CodecId codec_id) {
+  int histogram_index = kUnknownHistogram;
+  if (uses_acceleration) {
+    switch (codec_id) {
+      case CodecId::kVp8:
+        histogram_index = kVp8HwHistogram;
+        break;
+      case CodecId::kVp9:
+        histogram_index = kVp9HwHistogram;
+        break;
+#if BUILDFLAG(RTC_USE_H264)
+      case CodecId::kH264:
+        histogram_index = kH264HwHistogram;
+        break;
+#endif
+      case CodecId::kLast:
+        break;
+    }
+  } else {
+    switch (codec_id) {
+      case CodecId::kVp8:
+        histogram_index = kVp8SwHistogram;
+        break;
+      case CodecId::kVp9:
+        histogram_index = kVp9SwHistogram;
+        break;
+#if BUILDFLAG(RTC_USE_H264)
+      case CodecId::kH264:
+        histogram_index = kH264SwHistogram;
+        break;
+#endif
+      case CodecId::kLast:
+        break;
+    }
+  }
+  UMA_HISTOGRAM_ENUMERATION("Media.MediaRecorder.Codec", histogram_index,
+                            static_cast<int>(kLastHistogram));
+}
+
 }  // anonymous namespace
 
 VideoTrackRecorder::VideoTrackRecorder(
@@ -660,7 +714,9 @@
   if (allow_vea_encoder &&
       CanUseAcceleratedEncoder(codec_profile.codec_id, input_size.width(),
                                input_size.height())) {
+    // TODO(b/227350897): remove once codec histogram is verified working
     UMA_HISTOGRAM_BOOLEAN("Media.MediaRecorder.VEAUsed", true);
+    UmaHistogramForCodec(true, codec_profile.codec_id);
 
     const auto vea_profile =
         codec_profile.profile
@@ -678,7 +734,9 @@
         bits_per_second, vea_profile, codec_profile.level, input_size,
         use_import_mode, main_task_runner_);
   } else {
+    // TODO(b/227350897): remove once codec histogram is verified working
     UMA_HISTOGRAM_BOOLEAN("Media.MediaRecorder.VEAUsed", false);
+    UmaHistogramForCodec(false, codec_profile.codec_id);
     switch (codec_profile.codec_id) {
 #if BUILDFLAG(RTC_USE_H264)
       case CodecId::kH264:
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 9d85e6f..b96ba48 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -673,11 +673,6 @@
   return helper_.DeprecatedDefaultTaskRunner();
 }
 
-scoped_refptr<base::SingleThreadTaskRunner>
-MainThreadSchedulerImpl::VirtualTimeControlTaskRunner() {
-  return virtual_time_control_task_queue_->GetTaskRunnerWithDefaultTaskType();
-}
-
 scoped_refptr<MainThreadTaskQueue>
 MainThreadSchedulerImpl::CompositorTaskQueue() {
   helper_.CheckOnValidThread();
@@ -697,12 +692,6 @@
   return helper_.DefaultMainThreadTaskQueue();
 }
 
-scoped_refptr<MainThreadTaskQueue>
-MainThreadSchedulerImpl::VirtualTimeControlTaskQueue() {
-  helper_.CheckOnValidThread();
-  return virtual_time_control_task_queue_;
-}
-
 scoped_refptr<MainThreadTaskQueue> MainThreadSchedulerImpl::NewTaskQueue(
     const MainThreadTaskQueue::QueueCreationParams& params) {
   helper_.CheckOnValidThread();
@@ -1884,6 +1873,17 @@
   return !main_thread_only().virtual_time_stopped;
 }
 
+void MainThreadSchedulerImpl::GrantVirtualTimeBudget(
+    base::TimeDelta budget,
+    base::OnceClosure budget_exhausted_callback) {
+  virtual_time_control_task_queue_->GetTaskRunnerWithDefaultTaskType()
+      ->PostDelayedTask(FROM_HERE, std::move(budget_exhausted_callback),
+                        budget);
+  // This can shift time forwards if there's a pending MaybeAdvanceVirtualTime,
+  // so it's important this is called second.
+  virtual_time_domain_->SetVirtualTimeFence(NowTicks() + budget);
+}
+
 base::TimeTicks MainThreadSchedulerImpl::IncrementVirtualTimePauseCount() {
   main_thread_only().virtual_time_pause_count++;
   ApplyVirtualTimePolicy();
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index 42adfad..b69a3e0 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -267,8 +267,6 @@
 
   base::TimeTicks NowTicks() const;
 
-  scoped_refptr<base::SingleThreadTaskRunner> VirtualTimeControlTaskRunner();
-
   TaskAttributionTracker* GetTaskAttributionTracker() override {
     return main_thread_only().task_attribution_tracker.get();
   }
@@ -308,6 +306,8 @@
 
   // Returns true if virtual time is not paused.
   bool VirtualTimeAllowedToAdvance() const;
+  void GrantVirtualTimeBudget(base::TimeDelta budget,
+                              base::OnceClosure budget_exhausted_callback);
   void SetVirtualTimePolicy(VirtualTimePolicy virtual_time_policy);
   void SetMaxVirtualTimeTaskStarvationCount(int max_task_starvation_count);
   base::TimeTicks IncrementVirtualTimePauseCount();
@@ -424,9 +424,6 @@
   scoped_refptr<MainThreadTaskQueue> DefaultTaskQueue();
   scoped_refptr<MainThreadTaskQueue> CompositorTaskQueue();
   scoped_refptr<MainThreadTaskQueue> V8TaskQueue();
-  // A control task queue which also respects virtual time. Only available if
-  // virtual time has been enabled.
-  scoped_refptr<MainThreadTaskQueue> VirtualTimeControlTaskQueue();
 
   // `current_use_case` will be overwritten by the next call to UpdatePolicy.
   // Thus, this function should be only used for testing purposes.
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
index 289409e..0afe2bd 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -340,7 +340,6 @@
   using MainThreadSchedulerImpl::OnPendingTasksChanged;
   using MainThreadSchedulerImpl::SetHaveSeenABlockingGestureForTesting;
   using MainThreadSchedulerImpl::V8TaskQueue;
-  using MainThreadSchedulerImpl::VirtualTimeControlTaskQueue;
 
   explicit MainThreadSchedulerImplForTest(
       std::unique_ptr<base::sequence_manager::SequenceManager> manager)
@@ -3086,7 +3085,6 @@
   scheduler_->EnableVirtualTime(base::Time());
   scheduler_->DisableVirtualTimeForTesting();
   EXPECT_FALSE(scheduler_->IsVirtualTimeEnabled());
-  EXPECT_FALSE(scheduler_->VirtualTimeControlTaskQueue());
 }
 
 TEST_F(MainThreadSchedulerImplTest, VirtualTimePauser) {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
index 915c8269..27863a8 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
@@ -429,12 +429,8 @@
 void PageSchedulerImpl::GrantVirtualTimeBudget(
     base::TimeDelta budget,
     base::OnceClosure budget_exhausted_callback) {
-  main_thread_scheduler_->VirtualTimeControlTaskRunner()->PostDelayedTask(
-      FROM_HERE, std::move(budget_exhausted_callback), budget);
-  // This can shift time forwards if there's a pending MaybeAdvanceVirtualTime,
-  // so it's important this is called second.
-  main_thread_scheduler_->GetVirtualTimeDomain()->SetVirtualTimeFence(
-      main_thread_scheduler_->NowTicks() + budget);
+  main_thread_scheduler_->GrantVirtualTimeBudget(
+      budget, std::move(budget_exhausted_callback));
 }
 
 void PageSchedulerImpl::AudioStateChanged(bool is_audio_playing) {
diff --git a/third_party/blink/tools/blinkpy/common/path_finder.py b/third_party/blink/tools/blinkpy/common/path_finder.py
index 253075d..edaf58f 100644
--- a/third_party/blink/tools/blinkpy/common/path_finder.py
+++ b/third_party/blink/tools/blinkpy/common/path_finder.py
@@ -147,6 +147,9 @@
         return self.path_from_chromium_base('third_party', 'blink',
                                             'perf_tests')
 
+    def wpt_prefix(self):
+        return self._filesystem.join('external', 'wpt', '')
+
     def webdriver_prefix(self):
         return self._filesystem.join('external', 'wpt', 'webdriver', '')
 
@@ -176,17 +179,34 @@
     def path_from_web_tests(self, *comps):
         return self._filesystem.join(self.web_tests_dir(), *comps)
 
-    def strip_web_tests_path(self, wpt_test_abs_path):
+    def strip_web_tests_path(self, web_test_abs_path):
         web_tests_path = self.path_from_web_tests('')
-        if wpt_test_abs_path.startswith(web_tests_path):
-            return wpt_test_abs_path[len(web_tests_path):]
-        return wpt_test_abs_path
+        if web_test_abs_path.startswith(web_tests_path):
+            return web_test_abs_path[len(web_tests_path):]
+        return web_test_abs_path
+
+    def strip_wpt_path(self, wpt_path):
+        """Remove the prefix before all WPT paths.
+
+        ResultDB identifies WPTs as web tests with the prefix "external/wpt",
+        but wptrunner expects paths relative to the WPT root, which is already
+        "<web-tests-dir>/external/wpt". This function removes the redundant
+        path fragment.
+        """
+        if self.is_wpt_path(wpt_path):
+            return wpt_path[len(self.wpt_prefix()):]
+        # Path is absolute or does not start with the prefix.
+        # Assume the path already points to a valid WPT and pass through.
+        return wpt_path
 
     def strip_webdriver_tests_path(self, wpt_webdriver_test_path):
         if self.is_webdriver_test_path(wpt_webdriver_test_path):
             return wpt_webdriver_test_path[len(self.webdriver_prefix()):]
         return wpt_webdriver_test_path
 
+    def is_wpt_path(self, test_path):
+        return test_path.startswith(self.wpt_prefix())
+
     def is_webdriver_test_path(self, test_path):
         return test_path.startswith(self.webdriver_prefix())
 
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py
index ba55e71..a5bec07 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor.py
@@ -4,21 +4,61 @@
 """Process WPT results for upload to ResultDB."""
 
 import argparse
+import base64
 import json
 import logging
-import os
 
+import six
+
+from blinkpy.common.html_diff import html_diff
+from blinkpy.common.path_finder import PathFinder
 from blinkpy.common.system.log_utils import configure_logging
+from blinkpy.common.unified_diff import unified_diff
+from blinkpy.web_tests.models import test_failures
+from blinkpy.web_tests.models.typ_types import (
+    Artifacts,
+    Result,
+    ResultSinkReporter,
+)
 
 _log = logging.getLogger(__name__)
 
 
+def _html_diff(expected_text, actual_text, encoding='utf-8'):
+    """A Unicode-safe wrapper around `html_diff`.
+
+    The `html_diff` library requires `str` arguments and returns a `str` value.
+    This function accepts and returns Unicode instead.
+    """
+    # The coercions will have no effect on Python 3, where `str` is already
+    # Unicode. In Python 2, where `str` is binary, these coercions are
+    # encode/decode calls.
+    diff_content = html_diff(
+        six.ensure_str(expected_text, encoding),
+        six.ensure_str(actual_text, encoding),
+    )
+    return six.ensure_text(diff_content, encoding)
+
+
 class WPTResultsProcessor(object):
-    def __init__(self, host, web_tests_dir='', artifacts_dir=''):
+    def __init__(self,
+                 host,
+                 port=None,
+                 web_tests_dir='',
+                 artifacts_dir='',
+                 results_dir='',
+                 dry_run=False,
+                 sink=None):
         self.host = host
         self.fs = self.host.filesystem
+        self.port = port or self.host.port_factory.get()
         self.web_tests_dir = web_tests_dir
         self.artifacts_dir = artifacts_dir
+        self.results_dir = results_dir
+        self.dry_run = dry_run
+        self.sink = sink
+        self.wpt_manifest = self.port.wpt_manifest('external/wpt')
+        self.path_finder = PathFinder(self.fs)
 
     def main(self, argv=None):
         options = self.parse_args(argv)
@@ -28,7 +68,15 @@
 
         self.web_tests_dir = options.web_tests_dir
         self.artifacts_dir = options.artifacts_dir
+        self.results_dir = self.results_dir or self.fs.dirname(
+            options.wpt_results)
+        self.dry_run = options.dry_run
+        if not self.sink and not self.dry_run:
+            self.sink = ResultSinkReporter()
 
+        self._recreate_artifacts_dir()
+        self.process_wpt_results(options.wpt_results)
+        self._copy_results_viewer()
         if options.wpt_report:
             self.process_wpt_report(options.wpt_report)
         else:
@@ -43,6 +91,12 @@
             help='log extra details helpful for debugging',
         )
         parser.add_argument(
+            '--dry-run',
+            action='store_true',
+            help=('do not upload results to ResultDB via ResultSink '
+                  'or overwrite existing files'),
+        )
+        parser.add_argument(
             '--web-tests-dir',
             required=True,
             help='path to the web tests root',
@@ -53,14 +107,425 @@
             help='path to a directory to write artifacts to',
         )
         parser.add_argument(
+            '--wpt-results',
+            required=True,
+            help=('path to the JSON test results file '
+                  '(created with `wpt run --log-chromium=...`)'),
+        )
+        parser.add_argument(
             '--wpt-report',
             help=('path to the wptreport file '
                   '(created with `wpt run --log-wptreport=...`)'),
         )
         return parser.parse_args(argv)
 
+    def _recreate_artifacts_dir(self):
+        if self.fs.exists(self.artifacts_dir):
+            self.fs.rmtree(self.artifacts_dir)
+        self.fs.maybe_make_directory(self.artifacts_dir)
+        _log.info('Recreated artifacts directory (%s)', self.artifacts_dir)
+
+    def _copy_results_viewer(self):
+        source = self.fs.join(self.web_tests_dir, 'fast', 'harness',
+                              'results.html')
+        destination = self.fs.join(self.artifacts_dir, 'results.html')
+        self.fs.copyfile(source, destination)
+        _log.info('Copied results viewer (%s -> %s)', source, destination)
+
+    def process_wpt_results(self,
+                            raw_results_path,
+                            full_results_json=None,
+                            full_results_jsonp=None,
+                            failing_results_jsonp=None):
+        """Postprocess the results generated by wptrunner.
+
+        Arguments:
+            raw_results_path (str): Path to a JSON results file, which contains
+                raw contents or points to artifacts that will be extracted into
+                their own files. These fields are removed from the test results
+                tree to avoid duplication. This method will overwrite the
+                original JSON file with the processed results if the processor
+                is not in dry run mode.
+            full_results_json (str): Path to write processed JSON results to.
+            full_results_jsonp (str): Path to write processed JSONP results to.
+            failing_results_jsonp (str): Path to write failing JSONP results to.
+
+        See Also:
+            https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/json_test_results_format.md
+        """
+        full_results_json = full_results_json or self.fs.join(
+            self.artifacts_dir, 'full_results.json')
+        full_results_jsonp = full_results_jsonp or self.fs.join(
+            self.artifacts_dir, 'full_results_jsonp.js')
+        # NOTE: Despite the name, this is actually a JSONP file.
+        # https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/tools/blinkpy/web_tests/controllers/manager.py;l=636;drc=3b93609b2498af0e9dc298f64e2b4f6204af68fa
+        failing_results_jsonp = failing_results_jsonp or self.fs.join(
+            self.artifacts_dir, 'failing_results.json')
+
+        # results is modified in place throughout this function.
+        with self.fs.open_text_file_for_reading(
+                raw_results_path) as results_file:
+            results = json.load(results_file)
+
+        # wptrunner test names exclude the "external/wpt" prefix. Here, we
+        # reintroduce the prefix to create valid paths relative to the web test
+        # root directory in the Chromium source tree.
+        tests = results['tests']
+        prefix_components = self.path_finder.wpt_prefix().split(self.fs.sep)
+        for component in reversed(prefix_components):
+            if component:
+                tests = {component: tests}
+        results['tests'] = tests
+        test_names = self._extract_artifacts(results['tests'],
+                                             delim=results['path_delimiter'])
+        _log.info('Extracted artifacts for %d tests', len(test_names))
+
+        results_serialized = json.dumps(results)
+        self.fs.write_text_file(full_results_json, results_serialized)
+        if not self.dry_run:
+            self.fs.copyfile(full_results_json, raw_results_path)
+
+        # JSONP paddings need to be the same as:
+        # https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/tools/blinkpy/web_tests/controllers/manager.py;l=629;drc=3b93609b2498af0e9dc298f64e2b4f6204af68fa
+        with self.fs.open_text_file_for_writing(full_results_jsonp) as dest:
+            dest.write('ADD_FULL_RESULTS(')
+            dest.write(results_serialized)
+            dest.write(');')
+
+        self._trim_to_regressions(results['tests'])
+        with self.fs.open_text_file_for_writing(failing_results_jsonp) as dest:
+            dest.write('ADD_RESULTS(')
+            json.dump(results, dest)
+            dest.write(');')
+
+    def _extract_artifacts(self, current_node, current_path='', delim='/'):
+        """Recursively extract artifacts from the test results trie.
+
+        The JSON results represent tests as the leaves of a trie (nested
+        objects). The trie's structure corresponds to the WPT directory
+        structure on disk. This method will traverse the trie's nodes, writing
+        files to the artifacts directory at leaf nodes and uploading them to
+        ResultSink.
+
+        Arguments:
+            current_node: The node in the trie to be processed.
+            current_path (str): The path constructed so far, which will become
+                a test name at a leaf node. An empty path represents the WPT
+                root directory.
+            delim (str): Delimiter between components in test names. In
+                practice, the value is the POSIX directory separator.
+
+        Returns:
+            list[str]: A list of test names found.
+        """
+        if 'actual' in current_node:
+            # Leaf node detected.
+            if 'artifacts' not in current_node:
+                return
+            artifacts = current_node['artifacts']
+            artifacts.pop('wpt_actual_status', None)
+            artifacts.pop('wpt_subtest_failure', None)
+            test_passed = current_node['actual'] == 'PASS'
+            self._maybe_write_text_results(artifacts, current_path,
+                                           test_passed)
+            self._maybe_write_screenshots(artifacts, current_path)
+            self._maybe_write_logs(artifacts, current_path)
+            # Required by fast/harness/results.html to show stderr.
+            if 'stderr' in artifacts:
+                current_node['has_stderr'] = True
+            self._add_result_to_sink(current_node, current_path)
+            _log.debug('Extracted artifacts for %s: %s', current_path,
+                       ', '.join(artifacts) if artifacts else '(none)')
+            return [current_path]
+        else:
+            test_names = []
+            for component, child_node in current_node.items():
+                if current_path:
+                    child_path = current_path + delim + component
+                else:
+                    # At the web test root, do not include a leading slash.
+                    child_path = component
+                test_names.extend(
+                    self._extract_artifacts(child_node, child_path, delim))
+            return test_names
+
+    def _locate_expected_text(self, test_name, extension='.ini'):
+        """Try to locate the expected output of this test, if it exists.
+
+        The expected output of a test is checked in to the source tree beside
+        the test itself with a ".ini" extension. Not all tests have expected
+        output. This could be print-reftests (which are unsupported by the
+        blinkpy manifest) or ".any.js" tests (which appear in the output even
+        though they do not actually run). Instead, they have corresponding
+        tests like ".any.worker.html" that are covered here.
+        """
+        # When looking into the WPT manifest, we omit "external/wpt" from the
+        # web test name, since that part of the path is only relevant in
+        # Chromium.
+        wpt_name = self.path_finder.strip_wpt_path(test_name)
+        test_file_subpath = self.wpt_manifest.file_path_for_test_url(wpt_name)
+        if test_file_subpath:
+            expected_path = self.fs.join(self.web_tests_dir,
+                                         test_file_subpath + extension)
+            if self.fs.exists(expected_path):
+                return expected_path
+        return ''
+
+    def _maybe_write_text_results(self, artifacts, test_name, test_passed):
+        """Write actual, expected, and diff text outputs to disk, if possible.
+
+        If either the actual or expected output is missing, this method cannot
+        produce diffs.
+
+        Arguments:
+            artifacts (dict[str, Any]): Mapping from artifact names to their
+                contents.
+            test_name (str): Web test name (a path).
+            test_passed (bool): Whether the actual test status is a "PASS". If
+                the test passed, there are no artifacts to output. Note that if
+                a baseline file (*.ini) exists, an "actual" of "PASS" means that
+                the test matched the baseline, not that the test itself passed.
+                As such, we still correctly produce artifacts in the case where
+                someone fixes a baselined test.
+        """
+        actual_metadata = artifacts.pop('wpt_actual_metadata', None)
+        if not actual_metadata or test_passed:
+            return
+        actual_text = '\n'.join(actual_metadata)
+        actual_subpath = self._write_artifact(
+            actual_text,
+            test_name,
+            test_failures.FILENAME_SUFFIX_ACTUAL,
+        )
+        artifacts['actual_text'] = [actual_subpath]
+
+        expected_source_path = self._locate_expected_text(test_name)
+        if not expected_source_path:
+            return
+        expected_text = self.fs.read_text_file(expected_source_path)
+        expected_subpath = self._write_artifact(
+            expected_text,
+            test_name,
+            test_failures.FILENAME_SUFFIX_EXPECTED,
+        )
+        artifacts['expected_text'] = [expected_subpath]
+
+        diff_content = unified_diff(
+            expected_text,
+            actual_text,
+            expected_subpath,
+            actual_subpath,
+        )
+        diff_subpath = self._write_artifact(
+            diff_content,
+            test_name,
+            test_failures.FILENAME_SUFFIX_DIFF,
+        )
+        artifacts['text_diff'] = [diff_subpath]
+
+        html_diff_content = _html_diff(expected_text, actual_text)
+        html_diff_subpath = self._write_artifact(
+            html_diff_content,
+            test_name,
+            test_failures.FILENAME_SUFFIX_HTML_DIFF,
+            extension='.html',
+        )
+        artifacts['pretty_text_diff'] = [html_diff_subpath]
+
+    def _maybe_write_screenshots(self, artifacts, test_name):
+        """Write actual, expected, and diff screenshots to disk, if possible.
+
+        The raw "screenshots" artifact is a list of strings, each of which has
+        the format "<url>:<base64-encoded PNG>". Each URL-PNG pair is a
+        screenshot of either the test result, or one of its refs. We can
+        identify which screenshot is for the test by comparing the URL to the
+        test name.
+        """
+        # Remember the two images so we can diff them later.
+        actual_image_bytes = b''
+        expected_image_bytes = b''
+
+        screenshots = artifacts.pop('screenshots', None)
+        if not screenshots:
+            return
+        for screenshot in screenshots:
+            url, printable_image = screenshot.split(':')[:2]
+            # The URL produced by wptrunner will have a leading "/", which we
+            # trim away for easier comparison to the WPT name below.
+            if url.startswith('/'):
+                url = url[1:]
+            image_bytes = base64.b64decode(printable_image.strip())
+
+            # When comparing the test name to the image URL, we omit
+            # "external/wpt" from the test name, since that part of the path is
+            # only relevant in Chromium.
+            wpt_name = self.path_finder.strip_wpt_path(test_name)
+            screenshot_key = 'expected_image'
+            file_suffix = test_failures.FILENAME_SUFFIX_EXPECTED
+            if wpt_name == url:
+                screenshot_key = 'actual_image'
+                file_suffix = test_failures.FILENAME_SUFFIX_ACTUAL
+                actual_image_bytes = image_bytes
+            else:
+                expected_image_bytes = image_bytes
+
+            screenshot_subpath = self._write_png_artifact(
+                image_bytes,
+                test_name,
+                file_suffix,
+            )
+            artifacts[screenshot_key] = [screenshot_subpath]
+
+        diff_bytes, error = self.port.diff_image(expected_image_bytes,
+                                                 actual_image_bytes)
+        if diff_bytes and not error:
+            diff_subpath = self._write_png_artifact(
+                diff_bytes,
+                test_name,
+                test_failures.FILENAME_SUFFIX_DIFF,
+            )
+            artifacts['image_diff'] = [diff_subpath]
+        else:
+            _log.error(
+                'Error creating diff image for %s '
+                '(error: %s, diff_bytes is None: %s)', test_name, error,
+                diff_bytes is None)
+
+    def _maybe_write_logs(self, artifacts, test_name):
+        """Write WPT logs to disk, if possible."""
+        log = artifacts.pop('wpt_log', None)
+        if log:
+            log_subpath = self._write_artifact(
+                '\n'.join(log),
+                test_name,
+                test_failures.FILENAME_SUFFIX_STDERR,
+            )
+            artifacts['stderr'] = [log_subpath]
+
+        crash_log = artifacts.pop('wpt_crash_log', None)
+        if crash_log:
+            crash_log_subpath = self._write_artifact(
+                '\n'.join(crash_log),
+                test_name,
+                test_failures.FILENAME_SUFFIX_CRASH_LOG,
+            )
+            artifacts['crash_log'] = [crash_log_subpath]
+
+    def _write_artifact(self,
+                        contents,
+                        test_name,
+                        suffix,
+                        extension='.txt',
+                        text=True):
+        """Write an artifact to disk.
+
+        Arguments:
+            contents: The file contents of the artifact to write.
+            test_name (str): The name of the test that generated this artifact.
+            suffix (str): The suffix of the artifact to write. Usually
+                determined from the artifact name.
+            extension (str): Filename extension to use. Defaults to ".txt" for
+                text files.
+            text (bool): Whether to write the contents as text or binary. Make
+                sure to pass a compatible argument to `contents`.
+
+        Returns:
+            str: The path to the artifact file that was written relative to the
+                top-level results directory.
+        """
+        filename = self.port.output_filename(test_name, suffix, extension)
+        full_path = self.fs.join(self.artifacts_dir, filename)
+        parent_dir = self.fs.dirname(full_path)
+        if not self.fs.exists(parent_dir):
+            self.fs.maybe_make_directory(parent_dir)
+        if text:
+            write_file = self.fs.write_text_file
+        else:
+            write_file = self.fs.write_binary_file
+        write_file(full_path, contents)
+        return self.fs.relpath(full_path, self.results_dir)
+
+    def _write_png_artifact(self, artifact, test_name, suffix):
+        return self._write_artifact(
+            artifact,
+            test_name,
+            suffix,
+            extension='.png',
+            text=False,
+        )
+
+    def _remove_query_params(self, test_name):
+        index = test_name.rfind('?')
+        return test_name if index == -1 else test_name[:index]
+
+    def _add_result_to_sink(self, node, test_name):
+        """Add test results to the result sink."""
+        if not self.sink:
+            return
+
+        actual = node['actual']
+        if len(actual.split()) != 1:
+            _log.error(
+                'Test %s should have only one result, '
+                'but has the following: %s', test_name, actual)
+            return
+        # Test timeouts are a special case of aborts. We must report "ABORT" to
+        # result sink for tests that timed out.
+        if actual == 'TIMEOUT':
+            actual = 'ABORT'
+        expected = set(node['expected'].split())
+
+        artifacts = Artifacts(
+            output_dir=self.results_dir,
+            host=self.sink.host,
+            artifacts_base_dir=self.fs.relpath(self.artifacts_dir,
+                                               self.results_dir),
+        )
+
+        for name, paths in (node.get('artifacts') or {}).items():
+            for path in paths:
+                artifacts.AddArtifact(name, path)
+
+        test_duration = node.get('time', 0)
+        result = Result(
+            name=test_name,
+            actual=actual,
+            started=self.host.time() - test_duration,
+            took=test_duration,
+            worker=0,
+            expected=expected,
+            unexpected=actual not in expected,
+            artifacts=artifacts.artifacts,
+        )
+
+        test_path = self.fs.join(self.web_tests_dir,
+                                 self._remove_query_params(test_name))
+        self.sink.report_individual_test_result(test_name, result,
+                                                self.results_dir, None,
+                                                test_path)
+
+    def _trim_to_regressions(self, current_node):
+        """Recursively remove non-regressions from the test results trie.
+
+        Returns:
+            bool: Whether to remove `current_node` from the trie.
+        """
+        if 'actual' in current_node:
+            # Found a leaf. Delete it if it's not a regression (unexpected
+            # failure).
+            return not current_node.get('is_regression')
+
+        # Not a leaf, recurse into the subtree. Note that we make a copy of the
+        # items since we delete from the node during the loop.
+        for component, child_node in list(current_node.items()):
+            if self._trim_to_regressions(child_node):
+                del current_node[component]
+
+        # Delete the current node if empty.
+        return len(current_node) == 0
+
     def _get_wpt_revision(self):
-        version_path = os.path.join(self.web_tests_dir, 'external', 'Version')
+        version_path = self.fs.join(self.web_tests_dir, 'external', 'Version')
         target = 'Version:'
         with self.fs.open_text_file_for_reading(version_path) as version_file:
             for line in version_file:
@@ -70,17 +535,24 @@
         return None
 
     def process_wpt_report(self, report_path):
-        """Process a wpt report for possible eventual upload to wpt.fyi."""
+        """Process and upload a wpt report to result sink."""
         with self.fs.open_text_file_for_reading(report_path) as report_file:
             report = json.load(report_file)
         rev = self._get_wpt_revision()
         # Update with upstream revision
         if rev:
             report['run_info']['revision'] = rev
-        report_filename = os.path.basename(report_path)
-        output_path = os.path.join(self.artifacts_dir, report_filename)
-        with self.fs.open_text_file_for_writing(output_path) as report_file:
+        report_filename = self.fs.basename(report_path)
+        artifact_path = self.fs.join(self.artifacts_dir, report_filename)
+        with self.fs.open_text_file_for_writing(artifact_path) as report_file:
             json.dump(report, report_file)
-        _log.info('Processed wpt report %s and wrote to %s', report_path,
-                  output_path)
-        return output_path
+        _log.info('Processed wpt report (%s -> %s)', report_path,
+                  artifact_path)
+        if self.sink:
+            artifact = {
+                report_filename: {
+                    'filePath': artifact_path,
+                },
+            }
+            self.sink.report_invocation_level_artifacts(artifact)
+        return artifact_path
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py
index 1f74dcda..60d543b 100644
--- a/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py
+++ b/third_party/blink/tools/blinkpy/w3c/wpt_results_processor_unittest.py
@@ -1,53 +1,694 @@
-import json
-import os
+# Copyright (c) 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.
 
-from blinkpy.common.host_mock import MockHost
+import base64
+import json
+import re
+import unittest
+
+from blinkpy.common.host_mock import MockHost as BlinkMockHost
 from blinkpy.common.system.log_testing import LoggingTestCase
+from blinkpy.web_tests.port.factory_mock import MockPortFactory
+from blinkpy.w3c.wpt_manifest import BASE_MANIFEST_NAME
 from blinkpy.w3c.wpt_results_processor import WPTResultsProcessor
+from typ.fakes.host_fake import FakeHost as TypFakeHost
+
+# The path where the output of a wpt run was written. This is the file that
+# gets processed by WPTResultsProcessor.
+OUTPUT_JSON_FILENAME = "out.json"
+
+
+class MockResultSink(object):
+    def __init__(self):
+        self.sink_requests = []
+        self.invocation_level_artifacts = {}
+        self.host = TypFakeHost()
+
+    def report_individual_test_result(self, test_name, result,
+                                      artifacts_sub_dir, expectation,
+                                      test_path):
+        del artifacts_sub_dir
+        assert not expectation, 'expectation parameter should always be None'
+        self.sink_requests.append({
+            'test': test_name,
+            'test_path': test_path,
+            'result': {
+                'actual': result.actual,
+                'expected': result.expected,
+                'unexpected': result.unexpected,
+                'artifacts': result.artifacts
+            },
+        })
+
+    def report_invocation_level_artifacts(self, artifacts):
+        self.invocation_level_artifacts.update(artifacts)
 
 
 class WPTResultsProcessorTest(LoggingTestCase):
     def setUp(self):
         super(WPTResultsProcessorTest, self).setUp()
-        self.host = MockHost()
+
+        self.host = BlinkMockHost()
+        self.host.port_factory = MockPortFactory(self.host)
         self.fs = self.host.filesystem
-        self.processor = WPTResultsProcessor(
-            self.host,
-            web_tests_dir=os.path.join('third_party', 'blink', 'web_tests'),
-            artifacts_dir=os.path.join('out', 'Default',
-                                       'layout-test-results'),
-        )
-        self.wpt_report_path = os.path.join('out', 'Default',
+        port = self.host.port_factory.get()
+        self.wpt_report_path = self.fs.join('out', 'Default',
                                             'wpt_report.json')
 
-        version_path = os.path.join(self.processor.web_tests_dir, 'external',
-                                    'Version')
-        with self.fs.open_text_file_for_writing(version_path) as version_file:
-            version_file.write('Version: ')
-            version_file.write('afd66ac5976672821b2788cd5f6ae57701240308')
-            version_file.write('\n')
+        # Create a testing manifest containing any test files that we
+        # might interact with.
+        self.fs.write_text_file(
+            self.fs.join(port.web_tests_dir(), 'external', BASE_MANIFEST_NAME),
+            json.dumps({
+                'items': {
+                    'reftest': {
+                        'reftest.html': [
+                            'c3f2fb6f436da59d43aeda0a7e8a018084557033',
+                            [None, [['reftest-ref.html', '==']], {}],
+                        ]
+                    },
+                    'testharness': {
+                        'test.html': [
+                            'd933fd981d4a33ba82fb2b000234859bdda1494e',
+                            [None, {}]
+                        ],
+                        'crash.html': [
+                            'd933fd981d4a33ba82fb2b000234859bdda1494e',
+                            [None, {}]
+                        ],
+                        'variant.html': [
+                            'b8db5972284d1ac6bbda0da81621d9bca5d04ee7',
+                            ['variant.html?foo=bar/abc', {}],
+                            ['variant.html?foo=baz', {}],
+                        ],
+                        'dir': {
+                            'multiglob.https.any.js': [
+                                'd6498c3e388e0c637830fa080cca78b0ab0e5305',
+                                ['dir/multiglob.https.any.window.html', {}],
+                                ['dir/multiglob.https.any.worker.html', {}],
+                            ],
+                        },
+                    },
+                },
+            }))
+        self.fs.write_text_file(
+            self.fs.join(port.web_tests_dir(), 'fast', 'harness',
+                         'results.html'), 'results-viewer-body')
+        self.fs.write_text_file(
+            self.fs.join(port.web_tests_dir(), 'external', 'Version'),
+            'Version: afd66ac5976672821b2788cd5f6ae57701240308\n')
+        self.fs.write_text_file(
+            self.wpt_report_path,
+            json.dumps({
+                'run_info': {
+                    'os': 'linux',
+                    'os_version': '18.04',
+                    'product': 'chrome',
+                    'revision': '57a5dfb2d7d6253fbb7dbd7c43e7588f9339f431',
+                },
+                'results': [],
+            }))
 
-        report = {
-            'run_info': {
-                'os': 'linux',
-                'os_version': '18.04',
-                'product': 'chrome',
-                'revision': '57a5dfb2d7d6253fbb7dbd7c43e7588f9339f431',
+        self.processor = WPTResultsProcessor(
+            self.host,
+            port=port,
+            web_tests_dir=port.web_tests_dir(),
+            artifacts_dir=self.fs.join('out', 'Default',
+                                       'layout-test-results'),
+            results_dir=self.fs.join('out', 'Default'),
+            sink=MockResultSink())
+
+    def _create_json_output(self, json_dict):
+        """Writing some json output for processing."""
+        self.fs.write_text_file(OUTPUT_JSON_FILENAME, json.dumps(json_dict))
+
+    def _load_json_output(self, filename=OUTPUT_JSON_FILENAME):
+        """Loads the json output after post-processing."""
+        return json.loads(self.fs.read_text_file(filename))
+
+    def test_result_sink_for_test_expected_result(self):
+        json_dict = {
+            'tests': {
+                'fail': {
+                    'test.html?variant1': {
+                        'expected': 'PASS FAIL',
+                        'actual': 'FAIL',
+                        'artifacts': {
+                            'wpt_actual_status': ['OK'],
+                            'wpt_actual_metadata': ['test.html actual text'],
+                        },
+                    },
+                },
             },
-            'results': [],
+            'path_delimiter': '/',
         }
-        report_file = self.fs.open_text_file_for_writing(self.wpt_report_path)
-        with report_file:
-            json.dump(report, report_file)
+        self._create_json_output(json_dict)
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        test_name = self.fs.join('external', 'wpt', 'fail',
+                                 'test.html?variant1')
+        test_abs_path = self.fs.join(self.processor.web_tests_dir, 'external',
+                                     'wpt', 'fail', 'test.html')
+        path_from_out_dir = self.fs.join('layout-test-results', 'external',
+                                         'wpt', 'fail',
+                                         'test_variant1-actual.txt')
+        self.assertEqual(self.processor.sink.sink_requests, [{
+            'test': test_name,
+            'test_path': test_abs_path,
+            'result': {
+                'actual': 'FAIL',
+                'expected': {'PASS', 'FAIL'},
+                'unexpected': False,
+                'artifacts': {
+                    'actual_text': [path_from_out_dir],
+                },
+            },
+        }])
+
+    def test_result_sink_for_test_variant(self):
+        json_dict = {
+            'tests': {
+                'fail': {
+                    'test.html?variant1': {
+                        'expected': 'PASS',
+                        'actual': 'FAIL',
+                        'artifacts': {
+                            'wpt_actual_status': ['OK'],
+                            'wpt_actual_metadata': ['test.html actual text'],
+                        },
+                    },
+                },
+            },
+            'path_delimiter': '/',
+        }
+        self._create_json_output(json_dict)
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        test_name = self.fs.join('external', 'wpt', 'fail',
+                                 'test.html?variant1')
+        test_abs_path = self.fs.join(self.processor.web_tests_dir, 'external',
+                                     'wpt', 'fail', 'test.html')
+        path_from_out_dir = self.fs.join('layout-test-results', 'external',
+                                         'wpt', 'fail',
+                                         'test_variant1-actual.txt')
+        self.assertEqual(self.processor.sink.sink_requests, [{
+            'test': test_name,
+            'test_path': test_abs_path,
+            'result': {
+                'actual': 'FAIL',
+                'expected': {'PASS'},
+                'unexpected': True,
+                'artifacts': {
+                    'actual_text': [path_from_out_dir],
+                },
+            },
+        }])
+
+    def test_result_sink_artifacts(self):
+        json_dict = {
+            'tests': {
+                'fail': {
+                    'test.html': {
+                        'expected': 'PASS',
+                        'actual': 'FAIL',
+                        'artifacts': {
+                            'wpt_actual_status': ['OK'],
+                            'wpt_actual_metadata': ['test.html actual text'],
+                        },
+                    },
+                },
+            },
+            'path_delimiter': '/',
+        }
+        self._create_json_output(json_dict)
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        test_abs_path = self.fs.join(self.processor.web_tests_dir, 'external',
+                                     'wpt', 'fail', 'test.html')
+        path_from_out_dir = self.fs.join('layout-test-results', 'external',
+                                         'wpt', 'fail', 'test-actual.txt')
+        self.assertEqual(
+            self.processor.sink.sink_requests,
+            [{
+                'test': self.fs.join('external', 'wpt', 'fail', 'test.html'),
+                'test_path': test_abs_path,
+                'result': {
+                    'actual': 'FAIL',
+                    'expected': {'PASS'},
+                    'unexpected': True,
+                    'artifacts': {
+                        'actual_text': [path_from_out_dir],
+                    },
+                },
+            }])
+
+    def test_write_jsons(self):
+        # Ensure that various JSONs are written to the correct location.
+        json_dict = {
+            'tests': {
+                'pass': {
+                    'test.html': {
+                        'expected': 'PASS',
+                        'actual': 'PASS',
+                        'artifacts': {
+                            'wpt_actual_status': ['OK'],
+                        },
+                    },
+                },
+                'unexpected_pass.html': {
+                    'expected': 'FAIL',
+                    'actual': 'PASS',
+                    'artifacts': {
+                        'wpt_actual_status': ['OK'],
+                    },
+                    'is_unexpected': True,
+                },
+                'fail.html': {
+                    'expected': 'PASS',
+                    'actual': 'FAIL',
+                    'artifacts': {
+                        'wpt_actual_status': ['ERROR'],
+                    },
+                    'is_unexpected': True,
+                    'is_regression': True,
+                },
+            },
+            'path_delimiter': '/',
+        }
+        self._create_json_output(json_dict)
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        # The correctness of the output JSON is verified by other tests.
+        written_files = self.fs.written_files
+        artifact_path = self.fs.join(self.processor.artifacts_dir,
+                                     'full_results.json')
+        self.assertEqual(written_files[OUTPUT_JSON_FILENAME],
+                         written_files[artifact_path])
+
+        # Verify JSONP
+        artifact_path = self.fs.join(self.processor.artifacts_dir,
+                                     'full_results_jsonp.js')
+        full_results_jsonp = written_files[artifact_path].decode('utf-8')
+        match = re.match(r'ADD_FULL_RESULTS\((.*)\);$', full_results_jsonp)
+        self.assertIsNotNone(match)
+        self.assertEqual(
+            match.group(1),
+            written_files[OUTPUT_JSON_FILENAME].decode(encoding='utf-8'))
+
+        artifact_path = self.fs.join(self.processor.artifacts_dir,
+                                     'failing_results.json')
+        failing_results_jsonp = written_files[artifact_path].decode('utf-8')
+        match = re.match(r'ADD_RESULTS\((.*)\);$', failing_results_jsonp)
+        self.assertIsNotNone(match)
+        failing_results = json.loads(match.group(1))
+        # Verify filtering of failing_results.json
+        self.assertIn('fail.html', failing_results['tests']['external']['wpt'])
+        # We shouldn't have unexpected passes or empty dirs after filtering.
+        self.assertNotIn('unexpected_pass.html',
+                         failing_results['tests']['external']['wpt'])
+        self.assertNotIn('pass', failing_results['tests']['external']['wpt'])
+
+    def test_write_text_outputs(self):
+        # Ensure that text outputs are written to the correct location.
+
+        # We only generate an actual.txt if our actual wasn't PASS, so in this
+        # case we shouldn't write anything.
+        json_dict = {
+            'tests': {
+                'test.html': {
+                    'expected': 'PASS',
+                    'actual': 'PASS',
+                    'artifacts': {
+                        'wpt_actual_status': ['OK'],
+                        'wpt_actual_metadata': ['test.html actual text'],
+                    },
+                },
+            },
+            'path_delimiter': '/',
+        }
+        self._create_json_output(json_dict)
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        written_files = self.fs.written_files
+        artifacts_subdir = self.fs.join(self.processor.artifacts_dir,
+                                        'external', 'wpt')
+        actual_path = self.fs.join(artifacts_subdir, 'test-actual.txt')
+        diff_path = self.fs.join(artifacts_subdir, 'test-diff.txt')
+        pretty_diff_path = self.fs.join(artifacts_subdir,
+                                        'test-pretty-diff.html')
+        self.assertNotIn(actual_path, written_files)
+        self.assertNotIn(diff_path, written_files)
+        self.assertNotIn(pretty_diff_path, written_files)
+
+        # Now we change the outcome to be a FAIL, which should generate an
+        # actual.txt
+        json_dict['tests']['test.html']['actual'] = 'FAIL'
+        self._create_json_output(json_dict)
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        self.assertEqual("test.html actual text",
+                         written_files[actual_path].decode(encoding='utf-8'))
+        # Ensure the artifact in the json was replaced with the location of
+        # the newly-created file.
+        updated_json = self._load_json_output()
+        test_node = updated_json['tests']['external']['wpt']['test.html']
+        path_from_out_dir = self.fs.join('layout-test-results', 'external',
+                                         'wpt', 'test-actual.txt')
+        self.assertNotIn('wpt_actual_metadata', test_node['artifacts'])
+        self.assertEqual([path_from_out_dir],
+                         test_node['artifacts']['actual_text'])
+        self.assertIn(actual_path, written_files)
+        self.assertNotIn(diff_path, written_files)
+        self.assertNotIn(pretty_diff_path, written_files)
+
+    def test_write_log_artifact(self):
+        # Ensure that crash log artifacts are written to the correct location.
+        json_dict = {
+            'tests': {
+                'test.html': {
+                    'expected': 'PASS',
+                    'actual': 'FAIL',
+                    'artifacts': {
+                        'wpt_actual_status': ['ERROR'],
+                        'wpt_log': ['test.html exceptions'],
+                    },
+                },
+            },
+            'path_delimiter': '/',
+        }
+        self._create_json_output(json_dict)
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        written_files = self.fs.written_files
+        artifacts_subdir = self.fs.join(self.processor.artifacts_dir,
+                                        'external', 'wpt')
+        stderr_path = self.fs.join(artifacts_subdir, 'test-stderr.txt')
+        self.assertEqual(written_files[stderr_path].decode('utf-8'),
+                         'test.html exceptions')
+
+        # Ensure the artifact in the json was replaced with the location of
+        # the newly-created file.
+        updated_json = self._load_json_output()
+        test_node = updated_json['tests']['external']['wpt']['test.html']
+        self.assertNotIn('wpt_log', test_node['artifacts'])
+        path_from_out_dir = self.fs.join('layout-test-results', 'external',
+                                         'wpt', 'test-stderr.txt')
+        self.assertEqual([path_from_out_dir], test_node['artifacts']['stderr'])
+        self.assertTrue(test_node['has_stderr'])
+
+    def test_write_crashlog_artifact(self):
+        # Ensure that crash log artifacts are written to the correct location.
+        json_dict = {
+            'tests': {
+                'test.html': {
+                    'expected': 'PASS',
+                    'actual': 'CRASH',
+                    'artifacts': {
+                        'wpt_actual_status': ['CRASH'],
+                        'wpt_crash_log': ['test.html crashed!'],
+                    },
+                },
+            },
+            'path_delimiter': '/',
+        }
+        self._create_json_output(json_dict)
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        written_files = self.fs.written_files
+        artifacts_subdir = self.fs.join(self.processor.artifacts_dir,
+                                        'external', 'wpt')
+        crash_log_path = self.fs.join(artifacts_subdir, 'test-crash-log.txt')
+        self.assertEqual(
+            "test.html crashed!",
+            written_files[crash_log_path].decode(encoding='utf-8'))
+
+        # Ensure the artifact in the json was replaced with the location of
+        # the newly-created file.
+        updated_json = self._load_json_output()
+        test_node = updated_json['tests']['external']['wpt']['test.html']
+        path_from_out_dir = self.fs.join('layout-test-results', 'external',
+                                         'wpt', 'test-crash-log.txt')
+        self.assertNotIn('wpt_crash_log', test_node['artifacts'])
+        self.assertEqual([path_from_out_dir],
+                         test_node['artifacts']['crash_log'])
+
+    def test_write_screenshot_artifacts(self):
+        # Ensure that screenshots are written to the correct filenames and
+        # their bytes are base64 decoded. The image diff should also be created.
+        json_dict = {
+            'tests': {
+                'reftest.html': {
+                    'expected': 'PASS',
+                    'actual': 'PASS',
+                    'artifacts': {
+                        'wpt_actual_status': ['PASS'],
+                        'screenshots': [
+                            'reftest.html:abcd',
+                            'reftest-ref.html:bcde',
+                        ],
+                    },
+                },
+            },
+            'path_delimiter': '/',
+        }
+        self._create_json_output(json_dict)
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        written_files = self.fs.written_files
+        artifacts_subdir = self.fs.join(self.processor.artifacts_dir,
+                                        'external', 'wpt')
+        actual_path = self.fs.join(artifacts_subdir, 'reftest-actual.png')
+        self.assertEqual(base64.b64decode('abcd'), written_files[actual_path])
+        expected_path = self.fs.join(artifacts_subdir, 'reftest-expected.png')
+        self.assertEqual(base64.b64decode('bcde'),
+                         written_files[expected_path])
+        diff_path = self.fs.join(artifacts_subdir, 'reftest-diff.png')
+        # Make sure the diff image was written but don't check the contents,
+        # assume that diff_image does the right thing.
+        self.assertIsNotNone(written_files[diff_path])
+
+        # Ensure the artifacts in the json were replaced with the location of
+        # the newly-created files.
+        updated_json = self._load_json_output()
+        test_node = updated_json['tests']['external']['wpt']['reftest.html']
+        path_from_out_dir_base = self.fs.join('layout-test-results',
+                                              'external', 'wpt')
+        self.assertNotIn('screenshots', test_node['artifacts'])
+        self.assertEqual(
+            [self.fs.join(path_from_out_dir_base, 'reftest-actual.png')],
+            test_node['artifacts']['actual_image'])
+        self.assertEqual(
+            [self.fs.join(path_from_out_dir_base, 'reftest-expected.png')],
+            test_node['artifacts']['expected_image'])
+        self.assertEqual(
+            [self.fs.join(path_from_out_dir_base, 'reftest-diff.png')],
+            test_node['artifacts']['image_diff'])
+
+    def test_copy_expected_output(self):
+        # Check that an -expected.txt file is created from a checked-in metadata
+        # ini file if it exists for a test
+        json_dict = {
+            'tests': {
+                'test.html': {
+                    'expected': 'PASS',
+                    'actual': 'FAIL',
+                    'artifacts': {
+                        'wpt_actual_status': ['OK'],
+                        'wpt_actual_metadata': ['test.html actual text'],
+                    },
+                },
+            },
+            'path_delimiter': '/',
+        }
+        self._create_json_output(json_dict)
+        # Also create a checked-in metadata file for this test
+        self.fs.write_text_file(
+            self.fs.join(self.processor.web_tests_dir, 'test.html.ini'),
+            'test.html checked-in metadata')
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        written_files = self.fs.written_files
+        artifacts_subdir = self.fs.join(self.processor.artifacts_dir,
+                                        'external', 'wpt')
+        actual_path = self.fs.join(artifacts_subdir, 'test-actual.txt')
+        self.assertEqual("test.html actual text",
+                         written_files[actual_path].decode(encoding='utf-8'))
+        # The checked-in metadata file gets renamed from .ini to -expected.txt
+        expected_path = self.fs.join(artifacts_subdir, 'test-expected.txt')
+        self.assertEqual("test.html checked-in metadata",
+                         written_files[expected_path].decode(encoding='utf-8'))
+
+        # Ensure the artifacts in the json were replaced with the locations of
+        # the newly-created files.
+        path_from_out_dir_base = self.fs.join('layout-test-results',
+                                              'external', 'wpt')
+        updated_json = self._load_json_output()
+        test_node = updated_json['tests']['external']['wpt']['test.html']
+        self.assertNotIn('wpt_actual_metadata', test_node['artifacts'])
+        self.assertEqual(
+            [self.fs.join(path_from_out_dir_base, 'test-actual.txt')],
+            test_node['artifacts']['actual_text'])
+        self.assertEqual(
+            [self.fs.join(path_from_out_dir_base, 'test-expected.txt')],
+            test_node['artifacts']['expected_text'])
+
+        # Ensure that a diff was also generated. There should be both additions
+        # and deletions for this test since we have expected output. We don't
+        # validate the entire diff files to avoid checking line numbers/markup.
+        diff_path = self.fs.join(artifacts_subdir, 'test-diff.txt')
+        self.assertIn('-test.html checked-in metadata',
+                      written_files[diff_path].decode(encoding='utf-8'))
+        self.assertIn('+test.html actual text',
+                      written_files[diff_path].decode(encoding='utf-8'))
+        self.assertEqual(
+            [self.fs.join(path_from_out_dir_base, 'test-diff.txt')],
+            test_node['artifacts']['text_diff'])
+        pretty_diff_path = self.fs.join(artifacts_subdir,
+                                        'test-pretty-diff.html')
+        self.assertIn("test.html checked-in metadata",
+                      written_files[pretty_diff_path].decode(encoding='utf-8'))
+        self.assertIn("test.html actual text",
+                      written_files[pretty_diff_path].decode(encoding='utf-8'))
+        self.assertEqual(
+            [self.fs.join(path_from_out_dir_base, 'test-pretty-diff.html')],
+            test_node['artifacts']['pretty_text_diff'])
+
+    def test_expected_output_for_variant(self):
+        # Check that an -expected.txt file is created from a checked-in metadata
+        # ini file for a variant test. Variants are a little different because
+        # we have to use the manifest to map a test name to the test file, and
+        # determine the associated metadata from the test file.
+        # Check that an -expected.txt file is created from a checked-in metadata
+        # ini file if it exists for a test
+        json_dict = {
+            'tests': {
+                'variant.html?foo=bar/abc': {
+                    'expected': 'PASS',
+                    'actual': 'FAIL',
+                    'artifacts': {
+                        'wpt_actual_status': ['OK'],
+                        'wpt_actual_metadata': ['variant bar/abc actual text'],
+                    },
+                },
+            },
+            'path_delimiter': '/',
+        }
+        self._create_json_output(json_dict)
+        # Also create a checked-in metadata file for this test. This filename
+        # matches the test *file* name, not the test name (which includes the
+        # variant).
+        self.fs.write_text_file(
+            self.fs.join(self.processor.web_tests_dir, "variant.html.ini"),
+            "variant.html checked-in metadata")
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        written_files = self.fs.written_files
+        artifacts_subdir = self.fs.join(self.processor.artifacts_dir,
+                                        'external', 'wpt')
+        actual_path = self.fs.join(artifacts_subdir,
+                                   "variant_foo=bar_abc-actual.txt")
+        self.assertEqual("variant bar/abc actual text",
+                         written_files[actual_path].decode(encoding='utf-8'))
+        # The checked-in metadata file gets renamed from .ini to -expected.txt
+        expected_path = self.fs.join(artifacts_subdir,
+                                     "variant_foo=bar_abc-expected.txt")
+        self.assertEqual("variant.html checked-in metadata",
+                         written_files[expected_path].decode(encoding='utf-8'))
+
+        # Ensure the artifacts in the json were replaced with the locations of
+        # the newly-created files.
+        updated_json = self._load_json_output()
+        test_node_parent = updated_json['tests']['external']['wpt']
+        test_node = test_node_parent['variant.html?foo=bar/abc']
+        path_from_out_dir_base = self.fs.join('layout-test-results',
+                                              'external', 'wpt')
+        actual_path = self.fs.join(path_from_out_dir_base,
+                                   'variant_foo=bar_abc-actual.txt')
+        expected_path = self.fs.join(path_from_out_dir_base,
+                                     'variant_foo=bar_abc-expected.txt')
+        self.assertNotIn('wpt_actual_metadata', test_node['artifacts'])
+        self.assertEqual([actual_path], test_node['artifacts']['actual_text'])
+        self.assertEqual([expected_path],
+                         test_node['artifacts']['expected_text'])
+
+    def test_expected_output_for_multiglob(self):
+        # Check that an -expected.txt file is created from a checked-in metadata
+        # ini file for a multiglobal test. Multi-globals are a little different
+        # because we have to use the manifest to map a test name to the test
+        # file, and determine the associated metadata from the test file.
+        #
+        # Also note that the "dir" is both a directory and a part of the test
+        # name, so the path delimiter remains a / (ie: dir/multiglob) even on
+        # Windows.
+        json_dict = {
+            'tests': {
+                'dir/multiglob.https.any.worker.html': {
+                    'expected': 'PASS',
+                    'actual': 'FAIL',
+                    'artifacts': {
+                        'wpt_actual_status': ['OK'],
+                        'wpt_actual_metadata': [
+                            'dir/multiglob worker actual text',
+                        ],
+                    },
+                },
+            },
+            'path_delimiter': '/',
+        }
+        self._create_json_output(json_dict)
+        # Also create a checked-in metadata file for this test. This filename
+        # matches the test *file* name, not the test name (which includes test
+        # scope).
+        self.fs.write_text_file(
+            self.fs.join(self.processor.web_tests_dir,
+                         "dir/multiglob.https.any.js.ini"),
+            "dir/multiglob checked-in metadata")
+
+        self.processor.process_wpt_results(OUTPUT_JSON_FILENAME)
+        written_files = self.fs.written_files
+        artifacts_subdir = self.fs.join(self.processor.artifacts_dir,
+                                        'external', 'wpt')
+        actual_path = self.fs.join(
+            artifacts_subdir, 'dir/multiglob.https.any.worker-actual.txt')
+        self.assertEqual("dir/multiglob worker actual text",
+                         written_files[actual_path].decode(encoding='utf-8'))
+        # The checked-in metadata file gets renamed from .ini to -expected.txt
+        expected_path = self.fs.join(
+            artifacts_subdir, 'dir/multiglob.https.any.worker-expected.txt')
+        self.assertEqual("dir/multiglob checked-in metadata",
+                         written_files[expected_path].decode(encoding='utf-8'))
+
+        # Ensure the artifacts in the json were replaced with the locations of
+        # the newly-created files.
+        updated_json = self._load_json_output()
+        test_node_parent = updated_json['tests']['external']['wpt']
+        test_node = test_node_parent['dir/multiglob.https.any.worker.html']
+        path_from_out_dir_base = self.fs.join('layout-test-results',
+                                              'external', 'wpt')
+        self.assertNotIn('wpt_actual_metadata', test_node['artifacts'])
+        self.assertEqual([
+            self.fs.join(path_from_out_dir_base,
+                         'dir/multiglob.https.any.worker-actual.txt')
+        ], test_node['artifacts']['actual_text'])
+        self.assertEqual([
+            self.fs.join(path_from_out_dir_base,
+                         'dir/multiglob.https.any.worker-expected.txt')
+        ], test_node['artifacts']['expected_text'])
 
     def test_process_wpt_report(self):
         output_path = self.processor.process_wpt_report(self.wpt_report_path)
-        self.assertEqual(os.path.dirname(output_path),
+        self.assertEqual(self.fs.dirname(output_path),
                          self.processor.artifacts_dir)
-        with self.fs.open_text_file_for_reading(output_path) as output_file:
-            report = json.load(output_file)
-        self.assertEqual(report['run_info']['os'], 'linux')
-        self.assertEqual(report['run_info']['os_version'], '18.04')
-        self.assertEqual(report['run_info']['product'], 'chrome')
-        self.assertEqual(report['run_info']['revision'],
+        report = json.loads(self.fs.read_text_file(output_path))
+        run_info = report['run_info']
+        self.assertEqual(run_info['os'], 'linux')
+        self.assertEqual(run_info['os_version'], '18.04')
+        self.assertEqual(run_info['product'], 'chrome')
+        self.assertEqual(run_info['revision'],
                          'afd66ac5976672821b2788cd5f6ae57701240308')
+        artifacts = self.processor.sink.invocation_level_artifacts
+        artifact_path = self.fs.join(self.processor.artifacts_dir,
+                                     'wpt_report.json')
+        self.assertIn('wpt_report.json', artifacts)
+        self.assertEqual(artifacts['wpt_report.json'],
+                         {'filePath': artifact_path})
diff --git a/third_party/blink/tools/blinkpy/web_tests/models/typ_types.py b/third_party/blink/tools/blinkpy/web_tests/models/typ_types.py
index 1a93bf4..4388b9e 100644
--- a/third_party/blink/tools/blinkpy/web_tests/models/typ_types.py
+++ b/third_party/blink/tools/blinkpy/web_tests/models/typ_types.py
@@ -6,10 +6,12 @@
 
 path_finder.add_typ_dir_to_sys_path()
 
-from typ import json_results, expectations_parser, artifacts
+from typ import json_results, expectations_parser, artifacts, result_sink
 
 # Adds classes from typ that are used in blinkpy
+Result = json_results.Result
 ResultType = json_results.ResultType
 Expectation = expectations_parser.Expectation
 TestExpectations = expectations_parser.TestExpectations
 Artifacts = artifacts.Artifacts
+ResultSinkReporter = result_sink.ResultSinkReporter
diff --git a/third_party/blink/web_tests/SmokeTests b/third_party/blink/web_tests/SmokeTests
index d25593f23..4ddd951 100644
--- a/third_party/blink/web_tests/SmokeTests
+++ b/third_party/blink/web_tests/SmokeTests
@@ -416,7 +416,10 @@
 fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-line.html
 fast/css3-text/css3-text-decoration/text-decoration-skip-ink-css-support.html
 fast/css3-text/css3-text-decoration/text-decoration-style.html
-fast/css3-text/css3-text-decoration/text-decoration-style-inherit.html
+# TODO(crbug.com/1311456): This test fails on SwiftShader FEMU due to a
+# change in log/exp implementation. Re-enable the test after the issue
+# is fixed.
+# fast/css3-text/css3-text-decoration/text-decoration-style-inherit.html
 fast/css3-text/css3-text-decoration/text-decoration-style-inherit-links.html
 fast/css3-text/css3-text-decoration/text-decoration-style-inherit-not-propagated-by-out-of-flow.html
 fast/css3-text/css3-text-decoration/text-decoration-style-inherit-simple-underlines.html
@@ -913,7 +916,10 @@
 tables/mozilla/bugs/bug7342.html
 tables/mozilla/bugs/bug8950.html
 tables/mozilla/collapsing_borders/bug41262-3.html
-tables/mozilla/core/bloomberg.html
+# TODO(crbug.com/1311456): This test fails on SwiftShader FEMU due to a
+# change in log/exp implementation. Re-enable the test after the issue
+# is fixed.
+# tables/mozilla/core/bloomberg.html
 tables/mozilla_expected_failures/bugs/bug1010.html
 tables/mozilla_expected_failures/bugs/bug1055-2.html
 tables/mozilla_expected_failures/bugs/bug2479-5.html
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index d589293..9b1cd976 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1134,7 +1134,7 @@
       "http/tests/inspector-protocol/fenced-frame",
       "external/wpt/html/anonymous-iframe"
     ],
-    "args": ["--enable-features=FencedFrames:implementation_type/mparch,SharedStorageAPI,Prerender2,PartitionedCookies,PartitionedCookiesBypassOriginTrial"]
+    "args": ["--enable-features=FencedFrames:implementation_type/mparch,SharedStorageAPI,Prerender2,NoncedPartitionedCookies"]
   },
   {
     "prefix": "fenced-frame-shadow-dom",
@@ -1144,7 +1144,7 @@
       "wpt_internal/fenced_frame",
       "external/wpt/html/anonymous-iframe"
     ],
-    "args": ["--enable-features=FencedFrames:implementation_type/shadow_dom,SharedStorageAPI,Prerender2,PartitionedCookies,PartitionedCookiesBypassOriginTrial"]
+    "args": ["--enable-features=FencedFrames:implementation_type/shadow_dom,SharedStorageAPI,Prerender2,NoncedPartitionedCookies"]
   },
   {
     "prefix": "disable-custom-element-default-style",
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations
index 779a2ee..563ad31 100644
--- a/third_party/blink/web_tests/WebGPUExpectations
+++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -552,10 +552,6 @@
 crbug.com/1241369 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,canvas,readbackFromWebGPUCanvas:drawTo2DCanvas:format="rgba8unorm";webgpuCanvasType="offscreen";canvas2DType="onscreen" [ Skip ]
 crbug.com/1241369 [ Mac ] wpt_internal/webgpu/cts.https.html?q=webgpu:web_platform,canvas,readbackFromWebGPUCanvas:drawTo2DCanvas:format="rgba8unorm";webgpuCanvasType="offscreen";canvas2DType="offscreen" [ Skip ]
 crbug.com/1241369 [ Mac ] wpt_internal/webgpu/web_platform/reftests/canvas_clear.https.html [ Skip ]
-crbug.com/1241369 [ Mac ] wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_copy.https.html [ Skip ]
-crbug.com/1241369 [ Mac ] wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_draw.https.html [ Skip ]
-crbug.com/1241369 [ Mac ] wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html [ Skip ]
-crbug.com/1241369 [ Mac ] wpt_internal/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html [ Skip ]
 
 # Error from debug layer
 # Failure is for crbug.com/dawn/1112
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/crashtests/chrome-counter-in-multicol-details-crash.html b/third_party/blink/web_tests/external/wpt/css/css-lists/crashtests/chrome-counter-in-multicol-details-crash.html
new file mode 100644
index 0000000..d992f0a1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/crashtests/chrome-counter-in-multicol-details-crash.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>Crash removing element before counter inside multicol details element</title>
+<link rel="help" href="https://crbug.com/1310295">
+<style>
+  #counter { counter-reset:counter; }
+  #counter::after { content: counter(foo); }
+</style>
+<details style="columns:2;" open>
+  <span></span>
+  <div id="removeme"></div>
+  <span id="counter"></span>
+</details>
+<script>
+  document.body.offsetTop;
+  removeme.parentNode.removeChild(removeme);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/invalid-render-blocking-preload-link.html b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/invalid-render-blocking-preload-link.html
new file mode 100644
index 0000000..a640f72
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/dom/render-blocking/invalid-render-blocking-preload-link.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>An invalid preload link should not block rendering</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/preload/resources/preload_helper.js"></script>
+<link rel="preload" as="invalid" blocking="render"
+      href="/fonts/Ahem.ttf?pipe=trickle(d1)">
+<script>
+promise_test(async () => {
+  // requestAnimationFrame() should be eventually run, and the invalid preload
+  // link should not be loaded.
+  await new Promise(resolve => requestAnimationFrame(resolve));
+  verifyNumberOfResourceTimingEntries('/fonts/Ahem.ttf?pipe=trickle(d1)', 0);
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-focus.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-focus.tentative.html
index bb8d679..172414e 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-focus.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-focus.tentative.html
@@ -121,15 +121,11 @@
 
       // Use an activating element:
       const button = document.createElement('button');
-      const popupId = 'popup-id';
-      assert_equals(document.querySelectorAll('#' + popupId).length,0);
       document.body.appendChild(button);
       t.add_cleanup(function() {
-        popup.removeAttribute('id');
         button.remove();
       });
-      popup.id = popupId;
-      button.setAttribute('popup', popupId);
+      button.addEventListener('click',() => {popup.show()},{once: true});
       priorFocus.focus();
       button.click();
       assert_equals(document.activeElement, expectedFocusedElement, `${testName} activated by button.click()`);
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-invoking-attribute.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-invoking-attribute.tentative.html
deleted file mode 100644
index 1ff60fd..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-invoking-attribute.tentative.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8" />
-<title>Popup invoking attribute</title>
-<link rel="author" href="mailto:masonf@chromium.org">
-<link rel=help href="https://open-ui.org/components/popup.research.explainer">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
-<script src="/resources/testdriver-actions.js"></script>
-<script src="/resources/testdriver-vendor.js"></script>
-
-<button id=b1 popup=p1>Open Popup 1</button>
-<popup id=p1 anchor=b1><p>This is popup #1</p></popup>
-
-<style>
-  popup { border: 5px solid red; }
-</style>
-
-<script>
-  function clickOn(element) {
-    const actions = new test_driver.Actions();
-    return actions.pointerMove(0, 0, {origin: element})
-      .pointerDown({button: actions.ButtonType.LEFT})
-      .pointerUp({button: actions.ButtonType.LEFT})
-      .send();
-  }
-
-  const popup1 = document.querySelector('#p1');
-  const button1 = document.querySelector('#b1');
-
-  promise_test(async () => {
-    assert_false(popup1.open);
-    await clickOn(button1);
-    assert_true(popup1.open);
-    popup1.hide();
-    assert_false(popup1.open);
-    button1.click();
-    assert_true(popup1.open);
-  }, "Basic test of the 'popup' attribute on a button");
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-light-dismiss.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-light-dismiss.tentative.html
index 2b37c2d..50dfe369 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-light-dismiss.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/the-popup-element/popup-light-dismiss.tentative.html
@@ -19,11 +19,11 @@
   <span id=inside2>Inside popup 2</span>
 </popup>
 
-<button id=b3 popup=p3>Popup 3 - button 3
+<button id=b3 onclick='p3.show()'>Popup 3 - button 3
   <popup id=p4>Inside popup 4</popup>
 </button>
 <popup id=p3>Inside popup 3</popup>
-<button id=b4 popup=p3>Popup 3 - button 4
+<button id=b4 onclick='p3.show()'>Popup 3 - button 4
   <popup id=p5>Inside popup 5</popup>
 </button>
 
@@ -31,7 +31,7 @@
   <div style="height:2000px;background:lightgreen"></div>
   Bottom of popup6
 </popup>
-<button popup=p6>Popup 6</button>
+<button onclick='p6.show()'>Popup 6</button>
 
 <my-element id="myElement">
   <template shadowroot="open">
@@ -154,24 +154,6 @@
       assert_false(popup1.open);
     },'Clicking on anchor element shouldn\'t close its popup');
 
-    await clickOn(button3);
-    test(t => {
-      assert_true(popup3.open,'invoking element should open popup');
-      popup4.show();
-      assert_true(popup4.open);
-      assert_true(popup3.open);
-    },'An invoking element should be part of the ancestor chain');
-
-    await clickOn(button3);
-    assert_true(popup3.open);
-    assert_false(popup4.open);
-    assert_false(popup5.open);
-    popup5.show();
-    test(t => {
-      assert_true(popup5.open);
-      assert_false(popup3.open);
-    },'An invoking element that was not used to invoke the popup should NOT be part of the ancestor chain');
-
     popup1.show();
     popup2.show(); // Popup1 is an ancestral element for popup2.
     assert_true(popup1.open);
@@ -202,7 +184,7 @@
     },'Scrolling within a popup should not close the popup');
 
     button7.click();
-    assert_true(popup7.open,'invoking element should open popup');
+    assert_true(popup7.open);
     inside7.click();
     test(t => {
       assert_true(popup7.open);
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popups/popup-invoking-attribute.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/popups/popup-invoking-attribute.tentative-expected.txt
deleted file mode 100644
index 7e58f9f..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/popups/popup-invoking-attribute.tentative-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Basic test of the 'popup' attribute on a button assert_true: expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popups/popup-invoking-attribute.tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/popups/popup-invoking-attribute.tentative.html
index e5d1f4b..0eaf2f9f 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/popups/popup-invoking-attribute.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/popups/popup-invoking-attribute.tentative.html
@@ -9,8 +9,8 @@
 <script src="/resources/testdriver-actions.js"></script>
 <script src="/resources/testdriver-vendor.js"></script>
 
-<button id=b1 popup=p1>Open Popup 1</button>
-<div popup=popup id=p1 anchor=b1><p>This is popup #1</p></div>
+<button triggerpopup=p1>Open Popup 1</button>
+<div popup=popup id=p1>This is popup #1</div>
 
 <style>
   [popup] { border: 5px solid red; }
@@ -25,16 +25,16 @@
       .send();
   }
 
-  const popup1 = document.querySelector('#p1');
-  const button1 = document.querySelector('#b1');
+  const popup = document.querySelector('[popup]');
+  const button = document.querySelector('button');
 
   promise_test(async () => {
-    assert_false(popup1.matches(':popup-open'));
-    await clickOn(button1);
-    assert_true(popup1.matches(':popup-open'));
-    popup1.hidePopup();
-    assert_false(popup1.matches(':popup-open'));
-    button1.click();
-    assert_true(popup1.matches(':popup-open'));
+    assert_false(popup.matches(':popup-open'));
+    await clickOn(button);
+    assert_true(popup.matches(':popup-open'));
+    popup.hidePopup();
+    assert_false(popup.matches(':popup-open'));
+    button.click();
+    assert_true(popup.matches(':popup-open'));
   }, "Basic test of the 'popup' attribute on a button");
 </script>
diff --git a/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-evaluate-error-events-expected.txt b/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-evaluate-error-events-expected.txt
new file mode 100644
index 0000000..7f9fd87f
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-evaluate-error-events-expected.txt
@@ -0,0 +1,6 @@
+Tests that Runtime.evaluate triggers error handlers
+
+runtime-evaluate-error-events.js:10 onerror handler: Uncaught Error  1 7 Error
+    at <anonymous>:1:7
+runtime-evaluate-error-events.js:11 error event listener: ErrorEvent {isTrusted: true, message: 'Uncaught Error', filename: '', lineno: 1, colno: 7, …}
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-evaluate-error-events.js b/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-evaluate-error-events.js
new file mode 100644
index 0000000..addbf92
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/runtime/runtime-evaluate-error-events.js
@@ -0,0 +1,17 @@
+// 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.addResult(`Tests that Runtime.evaluate triggers error handlers\n`);
+  await TestRunner.loadLegacyModule('console');
+  await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.evaluateInPagePromise(`
+      window.onerror = (...args) => console.log('onerror handler:', ...args);
+      window.addEventListener('error', event => console.log('error event listener:', event));
+  `);
+
+  await TestRunner.RuntimeAgent.evaluate('throw new Error()');
+  await ConsoleTestRunner.dumpConsoleMessages();
+  TestRunner.completeTest();
+})();
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-by-name.https.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-by-name.https.html
new file mode 100644
index 0000000..a5df1e99
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-ancestor-by-name.https.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<title>Test named frame navigation of ancestors.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="resources/utils.js"></script>
+
+<body>
+<script>
+promise_test(async () => {
+  // This test uses the following layout:
+  // A: Top-level frame
+  //   B: iframe
+  //     C: fencedframe
+  //       D: fencedframe
+  //       E: iframe
+  //
+  // The purpose is to test that name resolution of navigation targets ignores
+  // ancestors beyond fence boundaries.
+
+  // Create an iframe B.
+  const B = attachIFrameContext();
+  await B.execute(async () => {
+    window.name = "B";
+
+    // Create a fenced frame C inside of it.
+    window.C = attachFencedFrameContext();
+    await window.C.execute(async () => {
+      window.name = "C";
+
+      // Navigate the target "B" from inside the fenced frame.
+      // It should open in a new tab due to fenced name lookup.
+      window.open("resources/dummy.html", "B");
+    });
+  });
+
+  // Observe that it created a new window, and the frame B is still here.
+  await B.execute(async () => {
+    // Create a nested iframe and fenced frame.
+    await window.C.execute(async () => {
+      window.D = attachFencedFrameContext();
+      window.E = attachIFrameContext();
+
+      // Navigate the target "C" from inside the nested fenced frame.
+      // It should open in a new tab due to fenced name lookup.
+      await window.D.execute(async () => {
+        window.open("resources/dummy.html", "C");
+      });
+    });
+    // Observe that it created a new window, and the frame C is still here.
+    await window.C.execute(async () => {
+      // Now attempt to navigate the target "C" from inside the iframe.
+      // It should open in a new tab with a console error, because sandboxed
+      // iframes (inherited from the fenced frame) are not allowed to navigate
+      // their ancestors.
+      await window.E.execute(() => {
+        window.open("resources/dummy.html", "C");
+      });
+    });
+
+    // Observe that C is still here.
+    await window.C.execute(() => {});
+  });
+}, 'navigate named ancestors');
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-by-name.https.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-descendant-by-name.https.html
similarity index 98%
rename from third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-by-name.https.html
rename to third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-descendant-by-name.https.html
index 814cbdb..08ce4b9 100644
--- a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-by-name.https.html
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-descendant-by-name.https.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<title>Test named frame navigation</title>
+<title>Test named frame navigation of descendants</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="resources/utils.js"></script>
diff --git a/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-related-page-by-name.https.html b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-related-page-by-name.https.html
new file mode 100644
index 0000000..cd01d1c38
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/fenced_frame/navigate-related-page-by-name.https.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>Test named frame navigation of related pages.</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="resources/utils.js"></script>
+
+<body>
+<script>
+promise_test(async () => {
+  // Create an auxiliary browsing context with a particular name.
+  const second_window = attachWindowContext({target: "target_name"});
+
+  // Create a fenced frame, and use the same target name inside of it.
+  const frame = attachFencedFrameContext();
+  await frame.execute(async () => {
+    window.open("resources/dummy.html", "target_name");
+  });
+
+  // Confirm that the top-level frame's related page (`second_window`)
+  // wasn't navigated by the fenced frame, i.e. that name resolution
+  // for related pages is fenced.
+  await second_window.execute(() => {});
+}, 'navigate related pages');
+</script>
+</body>
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index a3cb9e0b..35f508d 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-11-1-132-ga8e4563c3
-Revision: a8e4563c3418ed74d39019a6c5e2122d12c8f56f
+Version: VER-2-11-1-133-g119e404b8
+Revision: 119e404b892dc8bf7db53e868039aec187042587
 CPEPrefix: cpe:/a:freetype:freetype:2.11.1
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium
index 9b5c37fa8..8a71ebb 100644
--- a/third_party/libaom/README.chromium
+++ b/third_party/libaom/README.chromium
@@ -3,9 +3,9 @@
 URL: https://aomedia.googlesource.com/aom/
 Version: 3.1.2
 CPEPrefix: cpe:/a:aomedia:aomedia:3.1.2
-Date: Monday March 28 2022
+Date: Tuesday March 29 2022
 Branch: main
-Commit: a68079299d655eb98cbc624c0e3059e1a0609a39
+Commit: 46e8b1da9e10663ef1bb9868ee20fd24cb175448
 License: BSD
 License File: source/libaom/LICENSE
 Security Critical: yes
@@ -27,17 +27,16 @@
    Use the generated commit message for the roll.
 
 2. Generate the config files:
-     ./cmake_update.sh
      # See prerequisites in file comments.
+     ./cmake_update.sh
 
    This will also update this file with the new revision.
+   Update 'Branch' in this file if necessary.
 
-   Amend the commit created by the first step:
+3. Amend the commit created by the first step:
 
      git commit -a --amend
 
-3. Update 'Branch' in README.chromium if necessary.
-
 4. Upload the change to Gerrit:
 
      git cl upload
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h
index da459d04..5e27081 100644
--- a/third_party/libaom/source/config/config/aom_version.h
+++ b/third_party/libaom/source/config/config/aom_version.h
@@ -12,8 +12,8 @@
 #define VERSION_MAJOR 3
 #define VERSION_MINOR 3
 #define VERSION_PATCH 0
-#define VERSION_EXTRA "412-ga68079299"
+#define VERSION_EXTRA "414-g46e8b1da9"
 #define VERSION_PACKED \
   ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH))
-#define VERSION_STRING_NOSP "3.3.0-412-ga68079299"
-#define VERSION_STRING " 3.3.0-412-ga68079299"
+#define VERSION_STRING_NOSP "3.3.0-414-g46e8b1da9"
+#define VERSION_STRING " 3.3.0-414-g46e8b1da9"
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index dbd550f..205fedc 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -34,12 +34,12 @@
      cd third_party/libvpx
      ./generate_gni.sh
 
-  Amend the commit created by the first step:
+   Update 'Branch' in this file if necessary.
+
+3. Amend the commit created by the first step:
 
      git commit -a --amend
 
-3. Update 'Branch' in README.chromium if necessary.
-
 4. Upload the change to Gerrit:
 
      git cl upload
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a21570e..da7896a 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -51774,6 +51774,7 @@
       label="EnableLogControllerForDiagnosticsApp:disabled"/>
   <int value="-2114831248" label="disable-new-ntp"/>
   <int value="-2114756847" label="SideSearchClearCacheWhenClosed:disabled"/>
+  <int value="-2114740661" label="FastPairSubsequentPairingUX:disabled"/>
   <int value="-2113783491" label="ArcFilePickerExperiment:enabled"/>
   <int value="-2113705745"
       label="CrossOriginMediaPlaybackRequiresUserGesture:enabled"/>
@@ -52856,6 +52857,7 @@
   <int value="-1408696172" label="CompositeBGColorAnimation:enabled"/>
   <int value="-1408370474" label="AssistantRoutines:enabled"/>
   <int value="-1408288176" label="enable-account-consistency"/>
+  <int value="-1407568904" label="CrOSLabsFloatWindow:enabled"/>
   <int value="-1405349891" label="PictureInPictureAPI:enabled"/>
   <int value="-1405048637" label="OfflinePagesResourceBasedSnapshot:enabled"/>
   <int value="-1404469375" label="RemoteCopyProgressNotification:enabled"/>
@@ -55359,7 +55361,6 @@
   <int value="330439654" label="SyncPseudoUSSExtensions:enabled"/>
   <int value="330627288" label="ArcTouchModeMouse:disabled"/>
   <int value="330653520" label="ChromeShareHighlightsAndroid:enabled"/>
-  <int value="331094131" label="WindowControlMenu:disabled"/>
   <int value="331770879" label="CrostiniAppSearch:disabled"/>
   <int value="331845034" label="enable-webgl-developer-extensions"/>
   <int value="332391072" label="cs-contextual-cards-bar-integration"/>
@@ -55942,6 +55943,7 @@
       label="KeepAliveRendererForKeepaliveRequests:disabled"/>
   <int value="719922283" label="MessagesForAndroidSaveCard:enabled"/>
   <int value="720931007" label="WebAuthenticationBle:enabled"/>
+  <int value="722334179" label="NoncedPartitionedCookies:disabled"/>
   <int value="723318188" label="EnableUniveralLinks:disabled"/>
   <int value="723385329" label="SystemEmojiPickerClipboard:enabled"/>
   <int value="723619383" label="TopSitesFromSiteEngagement:enabled"/>
@@ -56518,6 +56520,7 @@
   <int value="1114794286" label="AutofillTypeSpecificPopupWidth:disabled"/>
   <int value="1115635149" label="EnableUnifiedMultiDeviceSetup:enabled"/>
   <int value="1116593018" label="CaptureThumbnailOnLoadFinished:disabled"/>
+  <int value="1116798400" label="NoncedPartitionedCookies:enabled"/>
   <int value="1117270978" label="ArcDocumentsProviderUnknownSize:disabled"/>
   <int value="1117534750"
       label="ForceSecurePaymentConfirmationDialog:disabled"/>
@@ -56770,6 +56773,7 @@
   <int value="1290904214" label="DiagnosticsAppNavigation:enabled"/>
   <int value="1291257442" label="TabsInCBD:disabled"/>
   <int value="1291761696" label="CCTModuleDexLoading:disabled"/>
+  <int value="1291790140" label="FastPairSubsequentPairingUX:enabled"/>
   <int value="1291966558" label="ScrollAnchoring:disabled"/>
   <int value="1292091029" label="OmniboxOneClickUnelide:disabled"/>
   <int value="1292482533" label="EnableTabMuting:disabled"/>
@@ -57822,6 +57826,7 @@
   <int value="2006413281"
       label="ContextualSuggestionsAlternateCardLayout:enabled"/>
   <int value="2006856618" label="BiometricTouchToFill:enabled"/>
+  <int value="2007638959" label="CrOSLabsFloatWindow:disabled"/>
   <int value="2008599705" label="EnableFeedbackPanel:enabled"/>
   <int value="2008878342" label="TouchToFillAndroid:disabled"/>
   <int value="2009097351" label="memlog-sampling-rate"/>
@@ -57845,7 +57850,6 @@
   <int value="2024298022"
       label="AutofillEnableInfoBarAccountIndicationFooterForSyncUsers:disabled"/>
   <int value="2027492085" label="SuppressToolbarCaptures:disabled"/>
-  <int value="2027729007" label="WindowControlMenu:enabled"/>
   <int value="2027793952" label="EditPasswordsInSettings:disabled"/>
   <int value="2032558514"
       label="RemoveUsageOfDeprecatedGaiaSigninEndpoint:enabled"/>
@@ -60273,6 +60277,16 @@
   <int value="2" label="HLS video"/>
 </enum>
 
+<enum name="MediaRecorderCodec">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="VP8_sw"/>
+  <int value="2" label="VP8_hw"/>
+  <int value="3" label="VP9_sw"/>
+  <int value="4" label="VP9_hw"/>
+  <int value="5" label="H264_sw"/>
+  <int value="6" label="H264_hw"/>
+</enum>
+
 <enum name="MediaRecorderVEAUsed">
   <int value="0" label="Not used"/>
   <int value="1" label="Used"/>
@@ -74249,7 +74263,7 @@
   <int value="6" label="INITIATOR_TAB_CRASHED_UNUSED"/>
   <int value="7" label="INITIATOR_TAB_CLOSED"/>
   <int value="8" label="PRINT_WITH_CLOUD_PRINT"/>
-  <int value="9" label="PRINT_WITH_PRIVET"/>
+  <int value="9" label="PRINT_WITH_PRIVET_UNUSED"/>
   <int value="10" label="PRINT_WITH_EXTENSION"/>
   <int value="11" label="OPEN_IN_MAC_PREVIEW"/>
   <int value="12" label="PRINT_TO_GOOGLE_DRIVE"/>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml
index e972791..f7d3606 100644
--- a/tools/metrics/histograms/metadata/arc/histograms.xml
+++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -56,6 +56,43 @@
   <variant name=".Unmanaged" summary="User with optional Play Store feature"/>
 </variants>
 
+<variants name="SuccessFailure">
+  <variant name=".Failure" summary="Operation failed"/>
+  <variant name=".Success" summary="Operation succeeded"/>
+</variants>
+
+<variants name="TimedCloudDpcOp">
+  <variant name=".DeviceSetup"
+      summary="Step during ManagedProvisioning app to setup the device"/>
+  <variant name=".SetupService.AddAccount"
+      summary="Step during the setup service that adds the account"/>
+  <variant name=".SetupService.CheckForAndroidId"
+      summary="Step during the setup service that checks android ID"/>
+  <variant name=".SetupService.CheckForFirstAccountReady"
+      summary="Step during the setup service that checks for first account
+               ready"/>
+  <variant name=".SetupService.CheckRegistrationToken"
+      summary="Step during the setup service that checks registration token"/>
+  <variant name=".SetupService.InstallApps"
+      summary="Step during the setup service that installs apps"/>
+  <variant name=".SetupService.InstallAppsRetry"
+      summary="Step during the setup service that retries installing apps"/>
+  <variant name=".SetupService.PullAndApplyPolicies"
+      summary="Step during the setup service that pulls and applies policies"/>
+  <variant name=".SetupService.QuarantinedRevised"
+      summary="Step during the setup service for a quarantined device"/>
+  <variant name=".SetupService.Register"
+      summary="Step during the setup service that registers"/>
+  <variant name=".SetupService.ReportPolicyCompliance"
+      summary="Step during the setup service that reports policy compliance"/>
+  <variant name=".SetupService.ThirdPartySignin"
+      summary="Step during the setup service that does third party sign in"/>
+  <variant name=".SetupService.Total"
+      summary="All steps that occur during the setup service"/>
+  <variant name=".SetupService.UpdatePlayServices"
+      summary="Step during the setup service that updates play services"/>
+</variants>
+
 <histogram name="Arc.AbiMigration.BootTime" units="ms"
     expires_after="2022-08-03">
   <owner>vraheja@chromium.org</owner>
@@ -577,6 +614,21 @@
   <summary>The number of clipboard and drag-and-drop events.</summary>
 </histogram>
 
+<histogram
+    name="Arc.CloudDpc{TimedCloudDpcOp}.TimeDelta{SuccessFailure}{ArcUserTypes}"
+    units="ms" expires_after="2022-10-14">
+  <owner>batoon@google.com</owner>
+  <owner>mhasank@google.com</owner>
+  <owner>arc-commercial@google.com</owner>
+  <summary>
+    The amount of time it took to complete the {TimedCloudDpcOp}
+    ({SuccessFailure}) operation in CloudDPC. {ArcUserTypes}
+  </summary>
+  <token key="ArcUserTypes" variants="ArcUserTypes"/>
+  <token key="TimedCloudDpcOp" variants="TimedCloudDpcOp"/>
+  <token key="SuccessFailure" variants="SuccessFailure"/>
+</histogram>
+
 <histogram name="Arc.CodeIntegrityCheckingTotalTime" units="ms"
     expires_after="M81">
   <owner>elijahtaylor@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index a60829ff..f8bc5819 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1946,6 +1946,27 @@
   </token>
 </histogram>
 
+<histogram name="Ash.InteractiveWindowResize.Lacros.TimeToPresent" units="ms"
+    expires_after="2023-03-14">
+  <owner>xiyuan@chromium.org</owner>
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    Similar to Ash.InteractiveWindowResize.TimeToPresent but tracks the resize
+    latency for lacros windows by measuring configure -&gt; ack -&gt; present
+    time.
+  </summary>
+</histogram>
+
+<histogram name="Ash.InteractiveWindowResize.Lacros.TimeToPresent.MaxLatency"
+    units="ms" expires_after="2023-03-14">
+  <owner>xiyuan@chromium.org</owner>
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    Maximum time of Ash.InteractiveWindowResize.Lacros.TimeToPresent during an
+    interactive resize.
+  </summary>
+</histogram>
+
 <histogram name="Ash.InteractiveWindowResize.TimeToPresent" units="ms"
     expires_after="2022-04-17">
   <owner>oshima@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 7fc46ae..ef239bf 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -3861,14 +3861,6 @@
   <summary>Whether the user changed autofilled field.</summary>
 </histogram>
 
-<histogram name="Autofill.{OtpAuthType}.OtpInputDialog.Shown"
-    enum="AutofillOtpAuthEvent" expires_after="2023-04-01">
-  <owner>siyua@chromium.org</owner>
-  <owner>payments-autofill-team@google.com</owner>
-  <summary>Logs when the OTP input dialog was shown.</summary>
-  <token key="OtpAuthType" variants="Autofill.OtpAuth.Type"/>
-</histogram>
-
 </histograms>
 
 </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index 971d052..1fba22b 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -529,7 +529,7 @@
 </histogram>
 
 <histogram name="ChromeOS.CWP.CollectPerf"
-    enum="ChromeOSProfileCollectionStatus" expires_after="2022-05-01">
+    enum="ChromeOSProfileCollectionStatus" expires_after="2023-05-01">
   <owner>aalexand@google.com</owner>
   <owner>gmx@chromium.org</owner>
   <owner>cwp-team@google.com</owner>
@@ -564,7 +564,7 @@
 </histogram>
 
 <histogram name="ChromeOS.CWP.ParseCPUFrequencies"
-    enum="ChromeOSParseCPUFrequencyStatus" expires_after="2022-05-01">
+    enum="ChromeOSParseCPUFrequencyStatus" expires_after="2023-05-01">
   <owner>gmx@chromium.org</owner>
   <owner>cwp-team@google.com</owner>
   <summary>
@@ -575,7 +575,7 @@
 </histogram>
 
 <histogram name="ChromeOS.CWP.ParsePSICPU" enum="ChromeOSParsePSICPUStatus"
-    expires_after="2022-05-01">
+    expires_after="2023-05-01">
   <owner>shantuo@google.com</owner>
   <owner>cwp-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index d3ca5d6..24a58c9 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -3030,6 +3030,16 @@
   </summary>
 </histogram>
 
+<histogram name="Media.MediaRecorder.Codec" enum="MediaRecorderCodec"
+    expires_after="2023-03-30">
+  <owner>clarissagarvey@chromium.org</owner>
+  <owner>mcasas@chromium.org</owner>
+  <summary>
+    The codec and hardware/software variant used by MediaRecorder, recorded once
+    when the VideoTrackRecorder initializes the encoder.
+  </summary>
+</histogram>
+
 <histogram name="Media.MediaRecorder.VEAError"
     enum="VideoDecodeAcceleratorError" expires_after="M95">
   <owner>mcasas@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 086d563..08bf86f 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -12402,16 +12402,6 @@
   </summary>
 </histogram>
 
-<histogram name="StackSamplingProfiler.MetadataSlotsUsed" units="counts"
-    expires_after="2021-01-12">
-  <owner>charliea@chromium.org</owner>
-  <owner>wittman@chromium.org</owner>
-  <summary>
-    The number of sample metadata item slots used after successfully setting a
-    metadata item. This count reflects both active and inactive metadata items.
-  </summary>
-</histogram>
-
 <histogram name="Style.InvalidationTime" units="microseconds"
     expires_after="2022-08-28">
   <owner>futhark@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/platform/histograms.xml b/tools/metrics/histograms/metadata/platform/histograms.xml
index 335a92ee..3c63d9f 100644
--- a/tools/metrics/histograms/metadata/platform/histograms.xml
+++ b/tools/metrics/histograms/metadata/platform/histograms.xml
@@ -167,7 +167,7 @@
 </histogram>
 
 <histogram name="Platform.Cr50.BoardIdOfRlzMismatch" enum="Cr50CrosRlzCodes"
-    expires_after="2022-05-01">
+    expires_after="2022-09-30">
   <owner>vbendeb@chromium.org</owner>
   <owner>apronin@chromium.org</owner>
   <owner>cros-hwsec+uma@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index db08c5e..ef59e3f 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "14a6dbac8eb062b2392348f19609ebcac6276afb",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/03d5ae5e403b60c94ba420e6a7cc50443142aa14/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/4e2255781b131bf3be20ca0084ea3f929afc406a/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/base/ime/text_input_client.cc b/ui/base/ime/text_input_client.cc
index bbdd0dce..212a598d 100644
--- a/ui/base/ime/text_input_client.cc
+++ b/ui/base/ime/text_input_client.cc
@@ -25,4 +25,10 @@
 }
 #endif
 
+#if BUILDFLAG(IS_WIN)
+ui::TextInputClient::EditingContext TextInputClient::GetTextEditingContext() {
+  return {};
+}
+#endif
+
 }  // namespace ui
diff --git a/ui/base/ime/text_input_client.h b/ui/base/ime/text_input_client.h
index fc8a8d8d..1155e485 100644
--- a/ui/base/ime/text_input_client.h
+++ b/ui/base/ime/text_input_client.h
@@ -24,6 +24,7 @@
 #include "ui/base/ime/text_input_type.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/range/range.h"
+#include "url/gurl.h"
 
 namespace gfx {
 class Rect;
@@ -304,6 +305,13 @@
       const gfx::Range& range,
       const std::u16string& active_composition_text,
       bool is_composition_committed) = 0;
+
+  struct EditingContext {
+    // Contains the active web content's URL.
+    GURL page_url;
+  };
+
+  virtual ui::TextInputClient::EditingContext GetTextEditingContext();
 #endif
 
   // Called before ui::InputMethod dispatches a not-consumed event to PostIME
diff --git a/ui/base/ime/win/tsf_text_store.cc b/ui/base/ime/win/tsf_text_store.cc
index bf1e522d..65194300 100644
--- a/ui/base/ime/win/tsf_text_store.cc
+++ b/ui/base/ime/win/tsf_text_store.cc
@@ -748,12 +748,16 @@
     return E_INVALIDARG;
   if (!text_input_client_)
     return E_FAIL;
-  // We support only input scope attribute.
+
+  supported_attrs_.clear();
   for (size_t i = 0; i < attribute_buffer_size; ++i) {
-    if (IsEqualGUID(GUID_PROP_INPUTSCOPE, attribute_buffer[i]))
-      return S_OK;
+    const auto& attribute = attribute_buffer[i];
+    if (IsEqualGUID(GUID_PROP_INPUTSCOPE, attribute) ||
+        IsEqualGUID(GUID_PROP_URL, attribute)) {
+      supported_attrs_.push_back(attribute);
+    }
   }
-  return E_FAIL;
+  return S_OK;
 }
 
 HRESULT TSFTextStore::RetrieveRequestedAttrs(ULONG attribute_buffer_size,
@@ -765,20 +769,43 @@
     return E_INVALIDARG;
   if (!text_input_client_)
     return E_UNEXPECTED;
-  // We support only input scope attribute.
+
   *attribute_buffer_copied = 0;
   if (attribute_buffer_size == 0)
     return S_OK;
 
-  attribute_buffer[0].dwOverlapId = 0;
-  attribute_buffer[0].idAttr = GUID_PROP_INPUTSCOPE;
-  attribute_buffer[0].varValue.vt = VT_UNKNOWN;
-  attribute_buffer[0].varValue.punkVal =
-      tsf_inputscope::CreateInputScope(text_input_client_->GetTextInputType(),
-                                       text_input_client_->GetTextInputMode(),
-                                       text_input_client_->ShouldDoLearning());
-  attribute_buffer[0].varValue.punkVal->AddRef();
-  *attribute_buffer_copied = 1;
+  *attribute_buffer_copied = std::min(
+      attribute_buffer_size, static_cast<ULONG>(supported_attrs_.size()));
+
+  for (size_t i = 0; i < *attribute_buffer_copied; ++i) {
+    attribute_buffer[i].idAttr = supported_attrs_[i];
+    // In TSF, this parameter value is zero.
+    // https://docs.microsoft.com/en-us/windows/win32/api/textstor/ns-textstor-ts_attrval
+    attribute_buffer[i].dwOverlapId = 0;
+    // If the caller is asking for the input scope, then create one based on
+    // the input client and return the COM object for it.
+    if (IsEqualGUID(GUID_PROP_INPUTSCOPE, supported_attrs_[i])) {
+      attribute_buffer[i].varValue.vt = VT_UNKNOWN;
+      attribute_buffer[i].varValue.punkVal = tsf_inputscope::CreateInputScope(
+          text_input_client_->GetTextInputType(),
+          text_input_client_->GetTextInputMode(),
+          text_input_client_->ShouldDoLearning());
+      attribute_buffer[i].varValue.punkVal->AddRef();
+    } else if (IsEqualGUID(GUID_PROP_URL, supported_attrs_[i])) {
+      const ui::TextInputClient::EditingContext editing_context =
+          text_input_client_->GetTextEditingContext();
+      attribute_buffer[i].varValue.vt = VT_BSTR;
+      std::wstring wide_url;
+      // If the caller is asking for the URL, get the URL from the
+      // the text input client (if there is one).
+      if (!editing_context.page_url.is_empty()) {
+        const std::string& url_string = editing_context.page_url.spec();
+        wide_url = base::UTF8ToWide(url_string);
+      }
+      attribute_buffer[i].varValue.bstrVal =
+          SysAllocStringLen(wide_url.c_str(), wide_url.length());
+    }
+  }
   return S_OK;
 }
 
diff --git a/ui/base/ime/win/tsf_text_store.h b/ui/base/ime/win/tsf_text_store.h
index 968b72d..8f1f822 100644
--- a/ui/base/ime/win/tsf_text_store.h
+++ b/ui/base/ime/win/tsf_text_store.h
@@ -20,6 +20,15 @@
 namespace ui {
 class TextInputClient;
 
+// d5138268-a1bf-4308-bcbf-2e739398e234
+// Bootstrap the definition of the GUID for the URL property which
+// will be defined in the windows SDK.
+// https://docs.microsoft.com/en-us/windows/win32/tsf/predefined-properties
+const GUID GUID_PROP_URL = {0xd5138268,
+                            0xa1bf,
+                            0x4308,
+                            {0xbc, 0xbf, 0x2e, 0x73, 0x93, 0x98, 0xe2, 0x34}};
+
 // TSFTextStore is used to interact with the input method via TSF manager.
 // TSFTextStore have a string buffer which is manipulated by TSF manager through
 // ITextStoreACP interface methods such as SetText().
@@ -312,6 +321,9 @@
   // composed text.
   void GetStyle(const TF_DISPLAYATTRIBUTE& attribute, ImeTextSpan* span);
 
+  // Clear all of the pending supported attributes values and count.
+  void ClearSupportedAttributes();
+
   // The reference count of this instance.
   volatile LONG ref_count_ = 0;
 
@@ -447,6 +459,10 @@
   Microsoft::WRL::ComPtr<ITfCategoryMgr> category_manager_;
   Microsoft::WRL::ComPtr<ITfDisplayAttributeMgr> display_attribute_manager_;
   Microsoft::WRL::ComPtr<ITfContext> context_;
+
+  // Current list of requested supported attribute values.
+  // Currently the supported attributes are URL and InputScope.
+  std::vector<TS_ATTRID> supported_attrs_;
 };
 
 }  // namespace ui
diff --git a/ui/base/ime/win/tsf_text_store_unittest.cc b/ui/base/ime/win/tsf_text_store_unittest.cc
index 54fcad9..80d12ae 100644
--- a/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -13,6 +13,7 @@
 #include <vector>
 
 #include "base/memory/ref_counted.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/win/scoped_com_initializer.h"
 #include "base/win/scoped_variant.h"
 #include "build/build_config.h"
@@ -74,6 +75,7 @@
   MOCK_METHOD2(GetActiveTextInputControlLayoutBounds,
                void(absl::optional<gfx::Rect>* control_bounds,
                     absl::optional<gfx::Rect>* selection_bounds));
+  MOCK_METHOD0(GetTextEditingContext, ui::TextInputClient::EditingContext());
 };
 
 class MockInputMethodDelegate : public internal::InputMethodDelegate {
@@ -1456,22 +1458,42 @@
 }
 
 TEST_F(TSFTextStoreTest, RequestSupportedAttrs) {
+  ui::TextInputClient::EditingContext expected_editing_context;
+  expected_editing_context.page_url = GURL("http://example.com");
   EXPECT_CALL(text_input_client_, GetTextInputType())
       .WillRepeatedly(Return(TEXT_INPUT_TYPE_TEXT));
   EXPECT_CALL(text_input_client_, GetTextInputMode())
       .WillRepeatedly(Return(TEXT_INPUT_MODE_DEFAULT));
+  EXPECT_CALL(text_input_client_, GetTextEditingContext())
+      .WillOnce(Return(ui::TextInputClient::EditingContext()))
+      .WillOnce(Return(expected_editing_context));
 
   EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(0, 1, nullptr));
 
   const TS_ATTRID kUnknownAttributes[] = {GUID_NULL};
-  EXPECT_HRESULT_FAILED(text_store_->RequestSupportedAttrs(
+  EXPECT_HRESULT_SUCCEEDED(text_store_->RequestSupportedAttrs(
       0, std::size(kUnknownAttributes), kUnknownAttributes))
-      << "Must fail for unknown attributes";
+      << "Mustn't fail for unknown attributes";
 
   const TS_ATTRID kAttributes[] = {GUID_NULL, GUID_PROP_INPUTSCOPE, GUID_NULL};
   EXPECT_EQ(S_OK, text_store_->RequestSupportedAttrs(0, std::size(kAttributes),
                                                      kAttributes))
       << "InputScope must be supported";
+  const TS_ATTRID urlAttributes[] = {GUID_PROP_URL};
+  ui::TextInputClient::EditingContext actual_editing_context =
+      text_input_client_.GetTextEditingContext();
+  EXPECT_TRUE(actual_editing_context.page_url.is_empty());
+  EXPECT_EQ(S_OK, text_store_->RequestSupportedAttrs(
+                      0, std::size(urlAttributes), urlAttributes))
+      << "Should return S_OK even if URL not supported";
+
+  actual_editing_context = text_input_client_.GetTextEditingContext();
+  EXPECT_TRUE(!actual_editing_context.page_url.is_empty());
+  EXPECT_TRUE(actual_editing_context.page_url.spec().compare(
+                  expected_editing_context.page_url.spec()) == 0);
+  EXPECT_EQ(S_OK, text_store_->RequestSupportedAttrs(
+                      0, std::size(urlAttributes), urlAttributes))
+      << "Expect URL to be supported";
 
   {
     SCOPED_TRACE("Check if RequestSupportedAttrs fails while focus is lost");
@@ -1484,19 +1506,26 @@
 }
 
 TEST_F(TSFTextStoreTest, RetrieveRequestedAttrs) {
+  ui::TextInputClient::EditingContext expected_editing_context;
+  expected_editing_context.page_url = GURL("http://example.com");
   EXPECT_CALL(text_input_client_, GetTextInputType())
       .WillRepeatedly(Return(TEXT_INPUT_TYPE_TEXT));
   EXPECT_CALL(text_input_client_, GetTextInputMode())
       .WillRepeatedly(Return(TEXT_INPUT_MODE_DEFAULT));
+  EXPECT_CALL(text_input_client_, GetTextEditingContext())
+      .WillRepeatedly(Return(expected_editing_context));
 
   ULONG num_copied = 0xfffffff;
   EXPECT_HRESULT_FAILED(
       text_store_->RetrieveRequestedAttrs(1, nullptr, &num_copied));
 
   {
-    SCOPED_TRACE("Make sure if InputScope is supported");
+    SCOPED_TRACE("Make sure that InputScope is supported");
     TS_ATTRVAL buffer[2] = {};
     num_copied = 0xfffffff;
+    const TS_ATTRID kAttributes[] = {GUID_PROP_INPUTSCOPE};
+    ASSERT_EQ(S_OK, text_store_->RequestSupportedAttrs(
+                        0, std::size(kAttributes), kAttributes));
     ASSERT_EQ(S_OK, text_store_->RetrieveRequestedAttrs(std::size(buffer),
                                                         buffer, &num_copied));
     bool input_scope_found = false;
@@ -1516,6 +1545,65 @@
     EXPECT_TRUE(input_scope_found);
   }
   {
+    SCOPED_TRACE("Verify URL support");
+    TS_ATTRVAL buffer[2] = {};
+    num_copied = 0xfffffff;
+    base::win::ScopedVariant variant;
+    const TS_ATTRID urlAttributes[] = {GUID_PROP_URL};
+
+    // This call should have a valid URL so the URL property should be returned
+    // and is expected to match the test_url value set above.
+    ASSERT_EQ(S_OK, text_store_->RequestSupportedAttrs(
+                        0, std::size(urlAttributes), urlAttributes));
+    ASSERT_EQ(S_OK, text_store_->RetrieveRequestedAttrs(std::size(buffer),
+                                                        buffer, &num_copied));
+    EXPECT_EQ(num_copied, 1U) << "Expect only URL property to be supported";
+    EXPECT_TRUE(IsEqualGUID(buffer[0].idAttr, GUID_PROP_URL));
+    std::swap(*variant.Receive(), buffer[0].varValue);
+    EXPECT_EQ(VT_BSTR, variant.type());
+    std::string url_string = base::WideToUTF8(std::wstring(
+        variant.ptr()->bstrVal, SysStringLen(variant.ptr()->bstrVal)));
+    EXPECT_EQ(expected_editing_context.page_url.spec(), url_string)
+        << "Expected url strings to match";
+  }
+  {
+    SCOPED_TRACE("Verify URL and InputScope support");
+    TS_ATTRVAL buffer[2] = {};
+    num_copied = 0xfffffff;
+    base::win::ScopedVariant variant;
+    const TS_ATTRID inputScopeAndUrlAttributes[] = {GUID_PROP_INPUTSCOPE,
+                                                    GUID_PROP_URL};
+
+    // This call should have a valid URL so the URL property should be returned
+    // and is expected to match the test_url value set above.
+    ASSERT_EQ(S_OK, text_store_->RequestSupportedAttrs(
+                        0, std::size(inputScopeAndUrlAttributes),
+                        inputScopeAndUrlAttributes));
+    ASSERT_EQ(S_OK, text_store_->RetrieveRequestedAttrs(std::size(buffer),
+                                                        buffer, &num_copied));
+    EXPECT_EQ(num_copied, 2U)
+        << "Expect both URL & InputScope properties to be supported";
+    for (size_t i = 0; i < num_copied; ++i) {
+      base::win::ScopedVariant variant;
+      // Move ownership from |buffer[i].varValue| to |variant|.
+      std::swap(*variant.Receive(), buffer[i].varValue);
+      if (IsEqualGUID(buffer[i].idAttr, GUID_PROP_INPUTSCOPE)) {
+        EXPECT_EQ(VT_UNKNOWN, variant.type());
+        Microsoft::WRL::ComPtr<ITfInputScope> input_scope;
+        EXPECT_HRESULT_SUCCEEDED(variant.AsInput()->punkVal->QueryInterface(
+            IID_PPV_ARGS(&input_scope)));
+      }
+      if (IsEqualGUID(buffer[i].idAttr, GUID_PROP_URL)) {
+        EXPECT_EQ(VT_BSTR, variant.type());
+        std::string url_string = base::WideToUTF8(std::wstring(
+            variant.ptr()->bstrVal, SysStringLen(variant.ptr()->bstrVal)));
+        EXPECT_EQ(expected_editing_context.page_url.spec(), url_string)
+            << "Expected url strings to match";
+      }
+      // we do not break here to clean up all the retrieved VARIANTs.
+    }
+  }
+  {
     SCOPED_TRACE("Check if RetrieveRequestedAttrs fails while focus is lost");
     // Emulate focus lost
     text_store_->SetFocusedTextInputClient(nullptr, nullptr);
diff --git a/ui/color/color_id_macros.inc b/ui/color/color_id_macros.inc
index 112e49b..55dc589 100644
--- a/ui/color/color_id_macros.inc
+++ b/ui/color/color_id_macros.inc
@@ -14,7 +14,7 @@
 // Convert first token to string, throw away the rest.
 #define D1(enum_name) #enum_name
 #define D2(enum_name, enum_value) #enum_name
-#else
+#else  // defined(STRINGIZE_COLOR_IDS)
 // Declare enum with optional assigned value.
 #define D1(enum_name) enum_name
 #define D2(enum_name, enum_value) enum_name = enum_value
@@ -27,7 +27,7 @@
 #define E_CPONLY(...) E(__VA_ARGS__)
 #define GET_E(_1, _2, _3, macro_name, ...) macro_name
 #define E(...) GET_E(__VA_ARGS__, E3, E2, E1)(__VA_ARGS__),
-#else
+#else  // !defined(COLOR_ID_MACROS_DEFINED)
 #undef D1
 #undef D2
 #undef E1
@@ -37,4 +37,4 @@
 #undef GET_E
 #undef E
 #undef COLOR_ID_MACROS_DEFINED
-#endif
+#endif  // !defined(COLOR_ID_MACROS_DEFINED)
diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn
index 27d6cc3..b1180a8 100644
--- a/ui/ozone/platform/x11/BUILD.gn
+++ b/ui/ozone/platform/x11/BUILD.gn
@@ -163,7 +163,7 @@
     "//ui/ozone/common",
   ]
 
-  if (!is_chromeos && !is_chromeos_ash && !is_chromeos_lacros) {
+  if (!is_chromeos && !is_chromeos) {
     sources += [ "test/os_exchange_data_provider_x11_unittest.cc" ]
     deps += [ "//ui/base/clipboard:clipboard_types" ]
 
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 426eb9d0..5e068e9a 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -588,7 +588,7 @@
     }
   }
 
-  if (is_chromeos_ash || is_chromeos_lacros) {
+  if (is_chromeos) {
     sources += [ "controls/menu/menu_config_chromeos.cc" ]
     if (!is_chromeos_lacros) {
       public += [ "controls/views_text_services_context_menu_chromeos.h" ]
diff --git a/ui/views/widget/any_widget_observer.h b/ui/views/widget/any_widget_observer.h
index 558f5d4b..e2f2e72 100644
--- a/ui/views/widget/any_widget_observer.h
+++ b/ui/views/widget/any_widget_observer.h
@@ -60,7 +60,7 @@
 // like this:
 //
 //    NamedWidgetShownWaiter waiter(
-//        "MyWidget", views::test::AnyWidgetTestPasskey{});
+//        views::test::AnyWidgetTestPasskey{}, "MyWidget");
 //    ThingThatCreatesAndShowsWidget();
 //    Widget* widget = waiter.WaitIfNeededAndGet();
 //