Desktop PWA: Adding prototype for Run PWA on user OS login

This is part 1 of 3 of the prototype to configure PWAS to run on
OS login.

Updates for the prototype include:
- Added feature flag "Desktop PWAs run on OS login", disabled by default.
- Added Startup folder to Windows base paths and shell util.
- Added "in_startup" entry to Web App Shortcut locations.
- If feature flag is enabled, show a checkbox in the PWA install dialog.
- If checked, PWA install task creates an additional shortcut in
  Windows Startup folder by setting "in_startup" location to true.

Additional parts for the feature to come in next CLs.

Explainer: https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/RunOnLogin/Explainer.md
I2P: https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/T6d2zqF_jpw/76TP7Bc2DwAJ
Bug: 897302
Change-Id: I0870e5a26e94e8e60001b78c95e53da134388f0a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2026256
Commit-Queue: Carlos Frias <carlos.frias@microsoft.com>
Reviewed-by: Alexey Baskakov <loyso@chromium.org>
Reviewed-by: Greg Thompson <grt@chromium.org>
Reviewed-by: Alan Cutter <alancutter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#772460}
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc
index 453b249c..1fe49b61 100644
--- a/base/base_paths_win.cc
+++ b/base/base_paths_win.cc
@@ -107,6 +107,18 @@
         return false;
       cur = FilePath(system_buffer);
       break;
+    case base::DIR_COMMON_STARTUP:
+      if (FAILED(SHGetFolderPath(nullptr, CSIDL_COMMON_STARTUP, nullptr,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_USER_STARTUP:
+      if (FAILED(SHGetFolderPath(nullptr, CSIDL_STARTUP, nullptr,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
     case base::DIR_APP_DATA:
       if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
                                  system_buffer)))
diff --git a/base/base_paths_win.h b/base/base_paths_win.h
index 2db16a6..df1991c 100644
--- a/base/base_paths_win.h
+++ b/base/base_paths_win.h
@@ -30,6 +30,10 @@
                                // Start Menu\Programs"
   DIR_START_MENU,              // Usually "C:\Users\<user>\AppData\Roaming\
                                // Microsoft\Windows\Start Menu\Programs"
+  DIR_COMMON_STARTUP,          // Usually "C:\ProgramData\Microsoft\Windows\
+                               // Start Menu\Programs\Startup"
+  DIR_USER_STARTUP,            // Usually "C:\Users\<user>\AppData\Roaming\
+                               // Microsoft\Windows\Start Menu\Programs\Startup"
   DIR_APP_DATA,                // Application Data directory under the user
                                // profile.
   DIR_LOCAL_APP_DATA,          // "Local Settings\Application Data" directory
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 84f1ae1..c07ec50d 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2297,6 +2297,12 @@
       <message name="IDS_INSTALL_PWA_BUTTON_LABEL" desc="Text for button that installs a web app to the operating system.">
         Install
       </message>
+      <message name="IDS_INSTALL_PWA_RUN_ON_OS_LOGIN_LABEL" desc="Text for checkbox label for auto starting the web app with user login to the operating system session.">
+        {0, select,
+        tablet {Start app when you sign in to your tablet}
+        computer {Start app when you sign in to your computer}
+        other {Start app when you sign in to your device}}
+      </message>
 
       <message name="IDS_BOOKMARK_APP_AX_BUBBLE_NAME_LABEL" desc="Text preceding the name of a bookmark app, read by spoken feedback.">
         Shortcut name
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d0e0107..02196125 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2734,6 +2734,10 @@
      flag_descriptions::kDesktopPWAsWithoutExtensionsName,
      flag_descriptions::kDesktopPWAsWithoutExtensionsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kDesktopPWAsWithoutExtensions)},
+    {"enable-desktop-pwas-run-on-os-login",
+     flag_descriptions::kDesktopPWAsRunOnOsLoginName,
+     flag_descriptions::kDesktopPWAsRunOnOsLoginDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(features::kDesktopPWAsRunOnOsLogin)},
     {"enable-system-webapps", flag_descriptions::kEnableSystemWebAppsName,
      flag_descriptions::kEnableSystemWebAppsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kSystemWebApps)},
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 58af1ca..281969d8 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1453,6 +1453,11 @@
     "expiry_milestone": 88
   },
   {
+    "name": "enable-desktop-pwas-run-on-os-login",
+    "owners": [ "cafrias@microsoft.com", "desktop-pwas-team@google.com" ],
+    "expiry_milestone": 85
+  },
+  {
     "name": "enable-desktop-pwas-tab-strip",
     "owners": [ "desktop-pwas-team@google.com" ],
     "expiry_milestone": 88
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 054822a2..bff329c 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -634,6 +634,11 @@
     "is incomplete and may corrupt your synced Chrome profile. Test accounts "
     "only are advised.";
 
+const char kDesktopPWAsRunOnOsLoginName[] = "Desktop PWAs run on OS login";
+const char kDesktopPWAsRunOnOsLoginDescription[] =
+    "Enable installed PWAs to be configured to automatically start when the OS "
+    "user logs in.";
+
 const char kEnableSystemWebAppsName[] = "System Web Apps";
 const char kEnableSystemWebAppsDescription[] =
     "Experimental system for using the Desktop PWA framework for running System"
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index e024d558..352316d 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -385,6 +385,9 @@
 extern const char kDesktopPWAsWithoutExtensionsName[];
 extern const char kDesktopPWAsWithoutExtensionsDescription[];
 
+extern const char kDesktopPWAsRunOnOsLoginName[];
+extern const char kDesktopPWAsRunOnOsLoginDescription[];
+
 extern const char kEnableSystemWebAppsName[];
 extern const char kEnableSystemWebAppsDescription[];
 
diff --git a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc
index abf2070..717fbbb 100644
--- a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc
+++ b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.cc
@@ -4,8 +4,12 @@
 
 #include "chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h"
 
+#include <utility>
+
+#include "base/i18n/message_formatter.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
+#include "build/build_config.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
@@ -29,6 +33,12 @@
 
 namespace {
 
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+constexpr char kDeviceTypeForCheckbox[] = "computer";
+#else
+constexpr char kDeviceTypeForCheckbox[] = "other";
+#endif
+
 PWAConfirmationBubbleView* g_bubble_ = nullptr;
 
 bool g_auto_accept_pwa_for_testing = false;
@@ -79,6 +89,11 @@
   return g_bubble_;
 }
 
+// static
+PWAConfirmationBubbleView* PWAConfirmationBubbleView::GetBubbleForTesting() {
+  return g_bubble_;
+}
+
 PWAConfirmationBubbleView::PWAConfirmationBubbleView(
     views::View* anchor_view,
     views::Button* highlight_button,
@@ -86,7 +101,8 @@
     chrome::AppInstallationAcceptanceCallback callback)
     : LocationBarBubbleDelegateView(anchor_view, nullptr),
       web_app_info_(std::move(web_app_info)),
-      callback_(std::move(callback)) {
+      callback_(std::move(callback)),
+      run_on_os_login_(nullptr) {
   DCHECK(web_app_info_);
 
   WidgetDelegate::SetShowCloseButton(true);
@@ -136,6 +152,17 @@
         web_app_info_->enable_experimental_tabbed_window);
   }
 
+  // TODO(crbug.com/897302): This is an experimental UI added to prototype
+  // The PWA Run on OS Login feature, final design is yet to be decided.
+  if (base::FeatureList::IsEnabled(features::kDesktopPWAsRunOnOsLogin)) {
+    // TODO(crbug.com/897302): Detect the type of device and supply the proper
+    // constant for the string.
+    run_on_os_login_ = labels->AddChildView(std::make_unique<views::Checkbox>(
+        base::i18n::MessageFormatter::FormatWithNumberedArgs(
+            l10n_util::GetStringUTF16(IDS_INSTALL_PWA_RUN_ON_OS_LOGIN_LABEL),
+            kDeviceTypeForCheckbox)));
+  }
+
   chrome::RecordDialogCreation(chrome::DialogIdentifier::PWA_CONFIRMATION);
 
   SetHighlightedButton(highlight_button);
@@ -162,10 +189,23 @@
     web_app_info_->enable_experimental_tabbed_window =
         tabbed_window_checkbox_->GetChecked();
   }
+
+  // User opt-in in checkbox is passed via the web_app_info structure to the
+  // underlying PWA install code.
+  // The definition of run_on_os_login_ is dependent on
+  // features::kDesktopPWAsRunOnOsLogin being enabled.
+  if (run_on_os_login_)
+    web_app_info_->run_on_os_login = run_on_os_login_->GetChecked();
+
   std::move(callback_).Run(true, std::move(web_app_info_));
   return true;
 }
 
+views::Checkbox*
+PWAConfirmationBubbleView::GetRunOnOsLoginCheckboxForTesting() {
+  return run_on_os_login_;
+}
+
 namespace chrome {
 
 void ShowPWAInstallBubble(content::WebContents* web_contents,
diff --git a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h
index f63db32a..d32b360 100644
--- a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h
+++ b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_WEB_APPS_PWA_CONFIRMATION_BUBBLE_VIEW_H_
 #define CHROME_BROWSER_UI_VIEWS_WEB_APPS_PWA_CONFIRMATION_BUBBLE_VIEW_H_
 
+#include <memory>
+
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
 #include "chrome/common/web_application_info.h"
@@ -20,6 +22,7 @@
 class PWAConfirmationBubbleView : public LocationBarBubbleDelegateView {
  public:
   static bool IsShowing();
+  static PWAConfirmationBubbleView* GetBubbleForTesting();
 
   PWAConfirmationBubbleView(views::View* anchor_view,
                             views::Button* highlight_button,
@@ -31,10 +34,12 @@
   views::View* GetInitiallyFocusedView() override;
   void WindowClosing() override;
   bool Accept() override;
+  views::Checkbox* GetRunOnOsLoginCheckboxForTesting();
 
  private:
   std::unique_ptr<WebApplicationInfo> web_app_info_;
   chrome::AppInstallationAcceptanceCallback callback_;
+  views::Checkbox* run_on_os_login_ = nullptr;
 
   // Checkbox to launch window with tab strip.
   views::Checkbox* tabbed_window_checkbox_ = nullptr;
diff --git a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view_browsertest.cc b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view_browsertest.cc
index cd6912c..09a8204c 100644
--- a/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view_browsertest.cc
@@ -2,18 +2,78 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+#include <utility>
+
 #include "base/bind_helpers.h"
 #include "base/macros.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/views/web_apps/pwa_confirmation_bubble_view.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/web_applications/components/web_app_id.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/browser_test.h"
+#include "ui/views/controls/button/checkbox.h"
 
-using PWAConfirmationBubbleViewBrowserTest = InProcessBrowserTest;
+class PWAConfirmationBubbleViewBrowserTest : public InProcessBrowserTest {
+ public:
+  PWAConfirmationBubbleViewBrowserTest() {
+    // Tests will crash if kDesktopPWAsRunOnOsLogin feature flag is not enabled.
+    // AcceptBubbleInPWAWindowRunOnOsLoginChecked and
+    // AcceptBubbleInPWAWindowRunOnOsLoginUnchecked tests interact with the
+    // checkbox which is only added if feature flag is enabled.
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kDesktopPWAsRunOnOsLogin);
+  }
+  ~PWAConfirmationBubbleViewBrowserTest() override = default;
+
+  std::unique_ptr<WebApplicationInfo> GetAppInfo() {
+    auto app_info = std::make_unique<WebApplicationInfo>();
+    app_info->title = base::UTF8ToUTF16("Test app 2");
+    app_info->app_url = GURL("https://example2.com");
+    app_info->open_as_window = true;
+    return app_info;
+  }
+
+  std::unique_ptr<WebApplicationInfo> GetCallbackAppInfoFromDialog(
+      bool run_on_os_login_checked) {
+    std::unique_ptr<WebApplicationInfo> resulting_app_info = nullptr;
+    auto app_info = GetAppInfo();
+
+    base::RunLoop loop;
+    // Show the PWA install dialog.
+    chrome::ShowPWAInstallBubble(
+        browser()->tab_strip_model()->GetActiveWebContents(),
+        std::move(app_info),
+        base::BindLambdaForTesting(
+            [&](bool accepted,
+                std::unique_ptr<WebApplicationInfo> app_info_callback) {
+              resulting_app_info = std::move(app_info_callback);
+              loop.Quit();
+            }));
+
+    // Get bubble dialog, set checkbox and accept.
+    PWAConfirmationBubbleView* bubble_dialog =
+        PWAConfirmationBubbleView::GetBubbleForTesting();
+    bubble_dialog->GetRunOnOsLoginCheckboxForTesting()->SetChecked(
+        run_on_os_login_checked);
+    bubble_dialog->Accept();
+
+    loop.Run();
+
+    return resulting_app_info;
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
 
 IN_PROC_BROWSER_TEST_F(PWAConfirmationBubbleViewBrowserTest,
                        ShowBubbleInPWAWindow) {
@@ -24,10 +84,7 @@
   web_app::AppId app_id = web_app::InstallWebApp(profile, std::move(app_info));
   Browser* browser = web_app::LaunchWebAppBrowser(profile, app_id);
 
-  app_info = std::make_unique<WebApplicationInfo>();
-  app_info->title = base::UTF8ToUTF16("Test app 2");
-  app_info->app_url = GURL("https://example2.com");
-  app_info->open_as_window = true;
+  app_info = GetAppInfo();
   // Tests that we don't crash when showing the install prompt in a PWA window.
   chrome::ShowPWAInstallBubble(
       browser->tab_strip_model()->GetActiveWebContents(), std::move(app_info),
@@ -43,3 +100,17 @@
       browser->tab_strip_model()->GetActiveWebContents(), std::move(app_info),
       base::DoNothing());
 }
+
+IN_PROC_BROWSER_TEST_F(PWAConfirmationBubbleViewBrowserTest,
+                       AcceptBubbleInPWAWindowRunOnOsLoginChecked) {
+  auto resulting_app_info =
+      GetCallbackAppInfoFromDialog(/*run_on_os_login_checked=*/true);
+  EXPECT_TRUE(resulting_app_info->run_on_os_login);
+}
+
+IN_PROC_BROWSER_TEST_F(PWAConfirmationBubbleViewBrowserTest,
+                       AcceptBubbleInPWAWindowRunOnOsLoginUnchecked) {
+  auto resulting_app_info =
+      GetCallbackAppInfoFromDialog(/*run_on_os_login_checked=*/false);
+  EXPECT_FALSE(resulting_app_info->run_on_os_login);
+}
diff --git a/chrome/browser/ui/web_applications/web_app_menu_model.cc b/chrome/browser/ui/web_applications/web_app_menu_model.cc
index c6c3195..9dcf974e 100644
--- a/chrome/browser/ui/web_applications/web_app_menu_model.cc
+++ b/chrome/browser/ui/web_applications/web_app_menu_model.cc
@@ -42,6 +42,9 @@
 }
 
 void WebAppMenuModel::Build() {
+  // TODO(crbug.com/897302): Expose UI for user opt out and reenable for the Run
+  // on OS Login feature.
+
   if (CreateActionToolbarOverflowMenu())
     AddSeparator(ui::UPPER_SEPARATOR);
   AddItemWithStringId(IDC_WEB_APP_MENU_APP_INFO,
diff --git a/chrome/browser/web_applications/components/app_shortcut_manager.cc b/chrome/browser/web_applications/components/app_shortcut_manager.cc
index 93975b5..8c00475 100644
--- a/chrome/browser/web_applications/components/app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/components/app_shortcut_manager.cc
@@ -79,6 +79,13 @@
   base::FilePath shortcut_data_dir =
       internals::GetShortcutDataDir(*shortcut_info);
 
+  if (base::FeatureList::IsEnabled(features::kDesktopPWAsRunOnOsLogin)) {
+    internals::GetShortcutIOTaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&internals::UnregisterRunOnOsLogin,
+                       shortcut_info->profile_path, shortcut_info->title));
+  }
+
   internals::PostShortcutIOTask(
       base::BindOnce(&internals::DeletePlatformShortcuts, shortcut_data_dir),
       std::move(shortcut_info));
@@ -183,4 +190,22 @@
       std::move(info), std::move(callback));
 }
 
+void AppShortcutManager::RegisterRunOnOsLogin(
+    const AppId& app_id,
+    RegisterRunOnOsLoginCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  GetShortcutInfoForApp(
+      app_id,
+      base::BindOnce(
+          &AppShortcutManager::OnShortcutInfoRetrievedRegisterRunOnOsLogin,
+          weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void AppShortcutManager::OnShortcutInfoRetrievedRegisterRunOnOsLogin(
+    RegisterRunOnOsLoginCallback callback,
+    std::unique_ptr<ShortcutInfo> info) {
+  internals::ScheduleRegisterRunOnOsLogin(std::move(info), std::move(callback));
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/components/app_shortcut_manager.h b/chrome/browser/web_applications/components/app_shortcut_manager.h
index 36cc07d..2c50355 100644
--- a/chrome/browser/web_applications/components/app_shortcut_manager.h
+++ b/chrome/browser/web_applications/components/app_shortcut_manager.h
@@ -58,6 +58,8 @@
   virtual void CreateShortcuts(const AppId& app_id,
                                bool add_to_desktop,
                                CreateShortcutsCallback callback);
+  virtual void RegisterRunOnOsLogin(const AppId& app_id,
+                                    RegisterRunOnOsLoginCallback callback);
 
   // Registers a shortcuts menu for the web app's icon with the OS.
   void RegisterShortcutsMenuWithOs(
@@ -95,6 +97,10 @@
       CreateShortcutsCallback callback,
       std::unique_ptr<ShortcutInfo> info);
 
+  void OnShortcutInfoRetrievedRegisterRunOnOsLogin(
+      RegisterRunOnOsLoginCallback callback,
+      std::unique_ptr<ShortcutInfo> info);
+
   ScopedObserver<AppRegistrar, AppRegistrarObserver> app_registrar_observer_{
       this};
 
diff --git a/chrome/browser/web_applications/components/external_install_options.cc b/chrome/browser/web_applications/components/external_install_options.cc
index 38907264..2d5b6b4 100644
--- a/chrome/browser/web_applications/components/external_install_options.cc
+++ b/chrome/browser/web_applications/components/external_install_options.cc
@@ -97,6 +97,7 @@
   params.add_to_applications_menu = install_options.add_to_applications_menu;
   params.add_to_desktop = install_options.add_to_desktop;
   params.add_to_quick_launch_bar = install_options.add_to_quick_launch_bar;
+  params.run_on_os_login = install_options.run_on_os_login;
   params.add_to_search = install_options.add_to_search;
   params.add_to_management = install_options.add_to_management;
   params.is_disabled = install_options.is_disabled;
diff --git a/chrome/browser/web_applications/components/external_install_options.h b/chrome/browser/web_applications/components/external_install_options.h
index 11983df..82627a37 100644
--- a/chrome/browser/web_applications/components/external_install_options.h
+++ b/chrome/browser/web_applications/components/external_install_options.h
@@ -58,6 +58,12 @@
   // other platforms.
   bool add_to_management = true;
 
+  // Whether the app should be registered to run on OS login.
+  // Currently this only works on Windows by adding a shortcut to the
+  // Startup Folder.
+  // TODO(crbug.com/897302): Enable for other platforms.
+  bool run_on_os_login = false;
+
   // If true, the app icon is displayed on Chrome OS with a blocked logo on
   // top, and the user cannot launch the app. Has no effect on other platforms.
   bool is_disabled = false;
diff --git a/chrome/browser/web_applications/components/install_manager.h b/chrome/browser/web_applications/components/install_manager.h
index ddcddec7..2613285 100644
--- a/chrome/browser/web_applications/components/install_manager.h
+++ b/chrome/browser/web_applications/components/install_manager.h
@@ -121,6 +121,7 @@
     bool add_to_applications_menu = true;
     bool add_to_desktop = true;
     bool add_to_quick_launch_bar = true;
+    bool run_on_os_login = false;
 
     // These have no effect outside of Chrome OS.
     bool add_to_search = true;
diff --git a/chrome/browser/web_applications/components/web_app_shortcut.cc b/chrome/browser/web_applications/components/web_app_shortcut.cc
index 099c69d8..9cd64a1b 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut.cc
@@ -71,6 +71,15 @@
       FROM_HERE, base::BindOnce(std::move(callback), shortcut_created));
 }
 
+void RegisterRunOnOsLoginAndPostCallback(RegisterRunOnOsLoginCallback callback,
+                                         const ShortcutInfo& shortcut_info) {
+  bool run_on_os_login_registered =
+      internals::RegisterRunOnOsLogin(shortcut_info);
+  content::GetUIThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), run_on_os_login_registered));
+}
+
 }  // namespace
 
 ShortcutInfo::ShortcutInfo() = default;
@@ -82,7 +91,8 @@
 ShortcutLocations::ShortcutLocations()
     : on_desktop(false),
       applications_menu_location(APP_MENU_LOCATION_NONE),
-      in_quick_launch_bar(false) {}
+      in_quick_launch_bar(false),
+      in_startup(false) {}
 
 std::string GenerateApplicationNameFromInfo(const ShortcutInfo& shortcut_info) {
   // TODO(loyso): Remove this empty()/non-empty difference.
@@ -165,6 +175,28 @@
                      std::move(shortcut_info));
 }
 
+void ScheduleRegisterRunOnOsLogin(std::unique_ptr<ShortcutInfo> shortcut_info,
+                                  RegisterRunOnOsLoginCallback callback) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  PostShortcutIOTask(
+      base::BindOnce(&RegisterRunOnOsLoginAndPostCallback, std::move(callback)),
+      std::move(shortcut_info));
+}
+
+#if !defined(OS_WIN)
+// TODO(crbug.com/897302): This boilerplate function is used for platforms
+// other than Windows, currently the feature is only supported in Windows.
+bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info) {
+  return false;
+}
+
+// TODO(crbug.com/897302): This boilerplate function is used for platforms
+// other than Windows, currently the feature is only supported in Windows.
+void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
+                            const base::string16& shortcut_title) {}
+#endif
+
 void PostShortcutIOTaskAndReply(
     base::OnceCallback<void(const ShortcutInfo&)> task,
     std::unique_ptr<ShortcutInfo> shortcut_info,
diff --git a/chrome/browser/web_applications/components/web_app_shortcut.h b/chrome/browser/web_applications/components/web_app_shortcut.h
index ff6cb284..7ec765638 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut.h
+++ b/chrome/browser/web_applications/components/web_app_shortcut.h
@@ -87,6 +87,10 @@
   // Mac dock or the gnome/kde application launcher. However, those are not
   // implemented yet.
   bool in_quick_launch_bar;
+
+  // For Windows, this refers to the Startup folder.
+  // TODO(crbug.com/897302): where to create shortcuts in other OS.
+  bool in_startup;
 };
 
 // This encodes the cause of shortcut creation as the correct behavior in each
@@ -115,6 +119,12 @@
 // created.
 using CreateShortcutsCallback = base::OnceCallback<void(bool shortcut_created)>;
 
+// Callback made when RegisterRunOnOsLogin has finished trying to register the
+// app to the OS Startup indicating whether or not it was successfully
+// registered.
+using RegisterRunOnOsLoginCallback =
+    base::OnceCallback<void(bool registered_successfully)>;
+
 // Returns an array of desired icon sizes (in px) to be contained in an app OS
 // shortcut, sorted in ascending order (biggest desired icon size is last).
 base::span<const int> GetDesiredIconSizesForShortcut();
@@ -146,6 +156,23 @@
     std::unique_ptr<ShortcutInfo> shortcut_info,
     CreateShortcutsCallback callback);
 
+// Schedules a call to |RegisterRunOnOsLogin| on the Shortcut IO thread and
+// invokes |callback| when complete. This function must be called from the UI
+// thread.
+void ScheduleRegisterRunOnOsLogin(std::unique_ptr<ShortcutInfo> shortcut_info,
+                                  RegisterRunOnOsLoginCallback callback);
+
+// Registers the app with the OS to run on OS login. Platform specific
+// implementations are required for this.
+// See web_app_shortcut_win.cc for Windows.
+bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info);
+
+// Unregisters the app with the OS from running on startup. Platform specific
+// implementations are required for this.
+// See web_app_shortcut_win.cc for Windows.
+void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
+                            const base::string16& shortcut_title);
+
 // Delete all the shortcuts we have added for this extension. This is the
 // platform specific implementation of the DeleteAllShortcuts function, and
 // is executed on the FILE thread.
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_win.cc b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
index 6a8a1c49..f2d68d3b 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_win.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
@@ -393,6 +393,35 @@
   return true;
 }
 
+bool RegisterRunOnOsLogin(const ShortcutInfo& shortcut_info) {
+  base::FilePath shortcut_data_dir =
+      internals::GetShortcutDataDir(shortcut_info);
+
+  ShortcutLocations locations;
+  locations.in_startup = true;
+
+  return CreatePlatformShortcuts(shortcut_data_dir, locations,
+                                 SHORTCUT_CREATION_BY_USER, shortcut_info);
+}
+
+void UnregisterRunOnOsLogin(const base::FilePath& profile_path,
+                            const base::string16& shortcut_title) {
+  web_app::ShortcutLocations all_shortcut_locations;
+  all_shortcut_locations.in_startup = true;
+  std::vector<base::FilePath> all_paths =
+      web_app::internals::GetShortcutPaths(all_shortcut_locations);
+
+  // Only Startup folder is the expected path to be returned in all_paths.
+  for (const auto& path : all_paths) {
+    // Find all app's shortcuts in Startup folder to delete.
+    std::vector<base::FilePath> shortcut_files =
+        FindAppShortcutsByProfileAndTitle(path, profile_path, shortcut_title);
+    for (const auto& shortcut_file : shortcut_files) {
+      base::DeleteFile(shortcut_file, /*recursive=*/false);
+    }
+  }
+}
+
 bool CreatePlatformShortcuts(const base::FilePath& web_app_path,
                              const ShortcutLocations& creation_locations,
                              ShortcutCreationReason creation_reason,
@@ -526,7 +555,8 @@
        // taskbar. This needs to be handled by callers.
        creation_locations.in_quick_launch_bar &&
            base::win::CanPinShortcutToTaskbar(),
-       ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH}};
+       ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH},
+      {creation_locations.in_startup, ShellUtil::SHORTCUT_LOCATION_STARTUP}};
 
   // Populate shortcut_paths.
   for (size_t i = 0; i < base::size(locations); ++i) {
diff --git a/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc b/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc
index a4b420b..0312d90 100644
--- a/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/extensions/pending_app_install_task_unittest.cc
@@ -388,6 +388,19 @@
   DISALLOW_COPY_AND_ASSIGN(PendingAppInstallTaskTest);
 };
 
+class PendingAppInstallTaskWithRunOnOsLoginTest
+    : public PendingAppInstallTaskTest {
+ public:
+  void SetUp() override {
+    scoped_feature_list_.InitWithFeatures({features::kDesktopPWAsRunOnOsLogin},
+                                          {});
+    PendingAppInstallTaskTest::SetUp();
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
 TEST_F(PendingAppInstallTaskTest,
        WebAppOrShortcutFromContents_InstallationSucceeds) {
   auto task = GetInstallationTaskWithTestMocks(
@@ -916,4 +929,65 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(PendingAppInstallTaskWithRunOnOsLoginTest,
+       WebAppOrShortcutFromContents_RunOnOsLogin) {
+  ExternalInstallOptions install_options(
+      WebAppUrl(), DisplayMode::kStandalone,
+      ExternalInstallSource::kInternalDefault);
+  install_options.run_on_os_login = true;
+
+  auto task = GetInstallationTaskWithTestMocks(std::move(install_options));
+
+  base::RunLoop run_loop;
+
+  task->Install(
+      web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
+      base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
+        EXPECT_TRUE(result.app_id.has_value());
+
+        EXPECT_EQ(1u, shortcut_manager()->num_create_shortcuts_calls());
+        EXPECT_TRUE(shortcut_manager()->did_add_to_desktop().value());
+
+        EXPECT_EQ(1u, shortcut_manager()->num_register_run_on_os_login_calls());
+
+        EXPECT_EQ(1u, finalizer()->num_add_app_to_quick_launch_bar_calls());
+        EXPECT_EQ(0u, finalizer()->num_reparent_tab_calls());
+
+        run_loop.Quit();
+      }));
+
+  run_loop.Run();
+}
+
+TEST_F(PendingAppInstallTaskWithRunOnOsLoginTest,
+       WebAppOrShortcutFromContents_NoRunOnOsLogin) {
+  ExternalInstallOptions install_options(
+      WebAppUrl(), DisplayMode::kStandalone,
+      ExternalInstallSource::kInternalDefault);
+  install_options.run_on_os_login = false;
+  auto task = GetInstallationTaskWithTestMocks(std::move(install_options));
+
+  base::RunLoop run_loop;
+
+  task->Install(
+      web_contents(), WebAppUrlLoader::Result::kUrlLoaded,
+      base::BindLambdaForTesting([&](PendingAppInstallTask::Result result) {
+        EXPECT_EQ(InstallResultCode::kSuccessNewInstall, result.code);
+        EXPECT_TRUE(result.app_id.has_value());
+
+        EXPECT_EQ(1u, shortcut_manager()->num_create_shortcuts_calls());
+        EXPECT_TRUE(shortcut_manager()->did_add_to_desktop().value());
+
+        EXPECT_EQ(0u, shortcut_manager()->num_register_run_on_os_login_calls());
+
+        EXPECT_EQ(1u, finalizer()->num_add_app_to_quick_launch_bar_calls());
+        EXPECT_EQ(0u, finalizer()->num_reparent_tab_calls());
+
+        run_loop.Quit();
+      }));
+
+  run_loop.Run();
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/test/test_app_shortcut_manager.cc b/chrome/browser/web_applications/test/test_app_shortcut_manager.cc
index 7b64e91..5a5686c 100644
--- a/chrome/browser/web_applications/test/test_app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/test/test_app_shortcut_manager.cc
@@ -56,4 +56,11 @@
   NOTIMPLEMENTED();
 }
 
+void TestAppShortcutManager::RegisterRunOnOsLogin(
+    const AppId& app_id,
+    RegisterRunOnOsLoginCallback callback) {
+  ++num_register_run_on_os_login_calls_;
+  std::move(callback).Run(true);
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/test/test_app_shortcut_manager.h b/chrome/browser/web_applications/test/test_app_shortcut_manager.h
index e9132e5..517fd0c 100644
--- a/chrome/browser/web_applications/test/test_app_shortcut_manager.h
+++ b/chrome/browser/web_applications/test/test_app_shortcut_manager.h
@@ -25,6 +25,10 @@
     return num_create_shortcuts_calls_;
   }
 
+  size_t num_register_run_on_os_login_calls() const {
+    return num_register_run_on_os_login_calls_;
+  }
+
   void set_can_create_shortcuts(bool can_create_shortcuts) {
     can_create_shortcuts_ = can_create_shortcuts;
   }
@@ -34,7 +38,7 @@
   }
 
   void SetNextCreateShortcutsResult(const AppId& app_id, bool success);
-
+  void SetNextRegisterRunOnOsLoginResult(const AppId& app_id, bool success);
   // AppShortcutManager:
   bool CanCreateShortcuts() const override;
   void CreateShortcuts(const AppId& app_id,
@@ -43,9 +47,12 @@
   std::unique_ptr<ShortcutInfo> BuildShortcutInfo(const AppId& app_id) override;
   void GetShortcutInfoForApp(const AppId& app_id,
                              GetShortcutInfoCallback callback) override;
+  void RegisterRunOnOsLogin(const AppId& app_id,
+                            RegisterRunOnOsLoginCallback callback) override;
 
  private:
   size_t num_create_shortcuts_calls_ = 0;
+  size_t num_register_run_on_os_login_calls_ = 0;
   base::Optional<bool> did_add_to_desktop_;
 
   bool can_create_shortcuts_ = true;
diff --git a/chrome/browser/web_applications/web_app_install_task.cc b/chrome/browser/web_applications/web_app_install_task.cc
index 0415c54..1886daa 100644
--- a/chrome/browser/web_applications/web_app_install_task.cc
+++ b/chrome/browser/web_applications/web_app_install_task.cc
@@ -810,6 +810,30 @@
     shortcut_manager_->RegisterShortcutsMenuWithOs(web_app_info->shortcut_infos,
                                                    app_id);
   }
+
+  if (base::FeatureList::IsEnabled(features::kDesktopPWAsRunOnOsLogin)) {
+    // TODO(crbug.com/897302): Add run on OS login dev activation from
+    // manifest, for now it is on by default if feature flag is enabled
+    bool run_on_os_login = web_app_info->run_on_os_login;
+
+    if (install_params_)
+      run_on_os_login = install_params_->run_on_os_login;
+
+    if (run_on_os_login) {
+      shortcut_manager_->RegisterRunOnOsLogin(
+          app_id, base::BindOnce(&WebAppInstallTask::OnRegisteredRunOnOsLogin,
+                                 weak_ptr_factory_.GetWeakPtr(), app_id));
+    } else {
+      CallInstallCallback(app_id, InstallResultCode::kSuccessNewInstall);
+    }
+  } else {
+    CallInstallCallback(app_id, InstallResultCode::kSuccessNewInstall);
+  }
+}
+
+void WebAppInstallTask::OnRegisteredRunOnOsLogin(
+    const AppId& app_id,
+    bool registered_run_on_os_login) {
   CallInstallCallback(app_id, InstallResultCode::kSuccessNewInstall);
 }
 
diff --git a/chrome/browser/web_applications/web_app_install_task.h b/chrome/browser/web_applications/web_app_install_task.h
index 8d866db..bfee580b 100644
--- a/chrome/browser/web_applications/web_app_install_task.h
+++ b/chrome/browser/web_applications/web_app_install_task.h
@@ -217,6 +217,8 @@
   void OnShortcutsCreated(std::unique_ptr<WebApplicationInfo> web_app_info,
                           const AppId& app_id,
                           bool shortcut_created);
+  void OnRegisteredRunOnOsLogin(const AppId& app_id,
+                                bool registered_run_on_os_login);
 
   // Whether we should just obtain WebApplicationInfo instead of the actual
   // installation.
diff --git a/chrome/browser/web_applications/web_app_install_task_unittest.cc b/chrome/browser/web_applications/web_app_install_task_unittest.cc
index 162f8cc..7546de13 100644
--- a/chrome/browser/web_applications/web_app_install_task_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_task_unittest.cc
@@ -345,6 +345,39 @@
   TestInstallFinalizer* test_install_finalizer_ = nullptr;
 };
 
+class WebAppInstallTaskWithRunOnOsLoginTest : public WebAppInstallTaskTest {
+ public:
+  WebAppInstallTaskWithRunOnOsLoginTest() {
+    scoped_feature_list_.InitWithFeatures({features::kDesktopPWAsRunOnOsLogin},
+                                          {});
+  }
+
+  ~WebAppInstallTaskWithRunOnOsLoginTest() override = default;
+
+  void CreateRendererAppInfo(const GURL& url,
+                             const std::string name,
+                             const std::string description,
+                             const GURL& scope,
+                             base::Optional<SkColor> theme_color,
+                             bool open_as_window,
+                             bool run_on_os_login) {
+    auto web_app_info = std::make_unique<WebApplicationInfo>();
+
+    web_app_info->app_url = url;
+    web_app_info->title = base::UTF8ToUTF16(name);
+    web_app_info->description = base::UTF8ToUTF16(description);
+    web_app_info->scope = scope;
+    web_app_info->theme_color = theme_color;
+    web_app_info->open_as_window = open_as_window;
+    web_app_info->run_on_os_login = run_on_os_login;
+
+    data_retriever_->SetRendererWebApplicationInfo(std::move(web_app_info));
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
 TEST_F(WebAppInstallTaskTest, InstallFromWebContents) {
   EXPECT_TRUE(AreWebAppsUserInstallable(profile()));
 
@@ -1173,4 +1206,98 @@
   }
 }
 
+TEST_F(WebAppInstallTaskWithRunOnOsLoginTest,
+       InstallFromWebContentsRunOnOsLogin) {
+  EXPECT_TRUE(AreWebAppsUserInstallable(profile()));
+
+  const GURL url = GURL("https://example.com/scope/path");
+  const std::string name = "Name";
+  const std::string description = "Description";
+  const GURL scope = GURL("https://example.com/scope");
+  const base::Optional<SkColor> theme_color = 0xAABBCCDD;
+  const base::Optional<SkColor> expected_theme_color = 0xFFBBCCDD;  // Opaque.
+
+  const AppId app_id = GenerateAppIdFromURL(url);
+
+  CreateDefaultDataToRetrieve(url, scope);
+  CreateRendererAppInfo(url, name, description, /*scope=*/GURL{}, theme_color,
+                        /*open_as_window=*/true, /*run_on_os_login=*/true);
+
+  base::RunLoop run_loop;
+  bool callback_called = false;
+  const bool force_shortcut_app = false;
+
+  install_task_->InstallWebAppFromManifestWithFallback(
+      web_contents(), force_shortcut_app, WebappInstallSource::MENU_BROWSER_TAB,
+      base::BindOnce(TestAcceptDialogCallback),
+      base::BindLambdaForTesting(
+          [&](const AppId& installed_app_id, InstallResultCode code) {
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
+            EXPECT_EQ(app_id, installed_app_id);
+            callback_called = true;
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+
+  EXPECT_TRUE(callback_called);
+
+  const WebApp* web_app = registrar().GetAppById(app_id);
+  EXPECT_NE(nullptr, web_app);
+
+  EXPECT_EQ(app_id, web_app->app_id());
+  EXPECT_EQ(name, web_app->name());
+  EXPECT_EQ(description, web_app->description());
+  EXPECT_EQ(url, web_app->launch_url());
+  EXPECT_EQ(scope, web_app->scope());
+  EXPECT_EQ(expected_theme_color, web_app->theme_color());
+  EXPECT_EQ(1u, test_shortcut_manager().num_register_run_on_os_login_calls());
+}
+
+TEST_F(WebAppInstallTaskWithRunOnOsLoginTest,
+       InstallFromWebContentsNoRunOnOsLogin) {
+  EXPECT_TRUE(AreWebAppsUserInstallable(profile()));
+
+  const GURL url = GURL("https://example.com/scope/path");
+  const std::string name = "Name";
+  const std::string description = "Description";
+  const GURL scope = GURL("https://example.com/scope");
+  const base::Optional<SkColor> theme_color = 0xAABBCCDD;
+  const base::Optional<SkColor> expected_theme_color = 0xFFBBCCDD;  // Opaque.
+
+  const AppId app_id = GenerateAppIdFromURL(url);
+
+  CreateDefaultDataToRetrieve(url, scope);
+  CreateRendererAppInfo(url, name, description, /*scope=*/GURL{}, theme_color,
+                        /*open_as_window=*/true, /*run_on_os_login=*/false);
+
+  base::RunLoop run_loop;
+  bool callback_called = false;
+  const bool force_shortcut_app = false;
+
+  install_task_->InstallWebAppFromManifestWithFallback(
+      web_contents(), force_shortcut_app, WebappInstallSource::MENU_BROWSER_TAB,
+      base::BindOnce(TestAcceptDialogCallback),
+      base::BindLambdaForTesting(
+          [&](const AppId& installed_app_id, InstallResultCode code) {
+            EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
+            EXPECT_EQ(app_id, installed_app_id);
+            callback_called = true;
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+
+  EXPECT_TRUE(callback_called);
+
+  const WebApp* web_app = registrar().GetAppById(app_id);
+  EXPECT_NE(nullptr, web_app);
+
+  EXPECT_EQ(app_id, web_app->app_id());
+  EXPECT_EQ(name, web_app->name());
+  EXPECT_EQ(description, web_app->description());
+  EXPECT_EQ(url, web_app->launch_url());
+  EXPECT_EQ(scope, web_app->scope());
+  EXPECT_EQ(expected_theme_color, web_app->theme_color());
+  EXPECT_EQ(0u, test_shortcut_manager().num_register_run_on_os_login_calls());
+}
+
 }  // namespace web_app
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 95e07c46..e723eb05 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -261,6 +261,10 @@
     "DefaultWebAppInstallation", base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
+// Enables or disables Desktop PWAs to be auto-started on OS login.
+const base::Feature kDesktopPWAsRunOnOsLogin{"DesktopPWAsRunOnOsLogin",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enable DNS over HTTPS (DoH).
 const base::Feature kDnsOverHttps{"DnsOverHttps",
                                   base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 2ca6f2d..700c807c 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -155,6 +155,9 @@
 #endif
 
 COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsRunOnOsLogin;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kDnsOverHttps;
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::FeatureParam<bool> kDnsOverHttpsFallbackParam;
diff --git a/chrome/common/web_application_info.h b/chrome/common/web_application_info.h
index 6cfde5a..78f6dd6 100644
--- a/chrome/common/web_application_info.h
+++ b/chrome/common/web_application_info.h
@@ -121,6 +121,10 @@
 
   // Set of shortcut infos populated using shortcuts specified in the manifest.
   std::vector<WebApplicationShortcutInfo> shortcut_infos;
+
+  // User preference as to whether to auto run the app on OS login.
+  // Currently only supported in Windows platform.
+  bool run_on_os_login = false;
 };
 
 std::ostream& operator<<(std::ostream& out,
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 502fc4f..7152775 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -1560,7 +1560,8 @@
     case SHORTCUT_LOCATION_QUICK_LAUNCH:  // Falls through.
     case SHORTCUT_LOCATION_START_MENU_ROOT:  // Falls through.
     case SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED:  // Falls through.
-    case SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR:
+    case SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR:        // Falls through.
+    case SHORTCUT_LOCATION_STARTUP:
       return true;
     case SHORTCUT_LOCATION_TASKBAR_PINS:
       return base::win::GetVersion() >= base::win::Version::WIN7;
@@ -1608,6 +1609,10 @@
     case SHORTCUT_LOCATION_APP_SHORTCUTS:
       // TODO(huangs): Move GetAppShortcutsFolder() logic into base_paths_win.
       return GetAppShortcutsFolder(level, path);
+    case SHORTCUT_LOCATION_STARTUP:
+      dir_key = (level == CURRENT_USER) ? base::DIR_USER_STARTUP
+                                        : base::DIR_COMMON_STARTUP;
+      break;
 
     default:
       NOTREACHED();
diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h
index 9cc69fa..0676683 100644
--- a/chrome/installer/util/shell_util.h
+++ b/chrome/installer/util/shell_util.h
@@ -72,6 +72,7 @@
     SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
     SHORTCUT_LOCATION_TASKBAR_PINS,   // base::win::Version::WIN7 +
     SHORTCUT_LOCATION_APP_SHORTCUTS,  // base::win::Version::WIN8 +
+    SHORTCUT_LOCATION_STARTUP,
     NUM_SHORTCUT_LOCATIONS
   };
 
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index d6a5b5d..e384dcb 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -76,6 +76,8 @@
     ASSERT_TRUE(fake_default_user_quick_launch_.CreateUniqueTempDir());
     ASSERT_TRUE(fake_start_menu_.CreateUniqueTempDir());
     ASSERT_TRUE(fake_common_start_menu_.CreateUniqueTempDir());
+    ASSERT_TRUE(fake_user_startup_.CreateUniqueTempDir());
+    ASSERT_TRUE(fake_common_startup_.CreateUniqueTempDir());
     user_desktop_override_.reset(new base::ScopedPathOverride(
         base::DIR_USER_DESKTOP, fake_user_desktop_.GetPath()));
     common_desktop_override_.reset(new base::ScopedPathOverride(
@@ -86,6 +88,10 @@
         base::DIR_START_MENU, fake_start_menu_.GetPath()));
     common_start_menu_override_.reset(new base::ScopedPathOverride(
         base::DIR_COMMON_START_MENU, fake_common_start_menu_.GetPath()));
+    common_startup_override_.reset(new base::ScopedPathOverride(
+        base::DIR_COMMON_STARTUP, fake_common_startup_.GetPath()));
+    user_startup_override_.reset(new base::ScopedPathOverride(
+        base::DIR_USER_STARTUP, fake_user_startup_.GetPath()));
 
     base::FilePath icon_path;
     base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &icon_path);
@@ -205,11 +211,15 @@
   base::ScopedTempDir fake_default_user_quick_launch_;
   base::ScopedTempDir fake_start_menu_;
   base::ScopedTempDir fake_common_start_menu_;
+  base::ScopedTempDir fake_user_startup_;
+  base::ScopedTempDir fake_common_startup_;
   std::unique_ptr<base::ScopedPathOverride> user_desktop_override_;
   std::unique_ptr<base::ScopedPathOverride> common_desktop_override_;
   std::unique_ptr<base::ScopedPathOverride> user_quick_launch_override_;
   std::unique_ptr<base::ScopedPathOverride> start_menu_override_;
   std::unique_ptr<base::ScopedPathOverride> common_start_menu_override_;
+  std::unique_ptr<base::ScopedPathOverride> user_startup_override_;
+  std::unique_ptr<base::ScopedPathOverride> common_startup_override_;
 
   base::FilePath chrome_exe_;
   base::FilePath manganese_exe_;
@@ -246,6 +256,14 @@
       ShellUtil::SYSTEM_LEVEL, &path);
   EXPECT_EQ(fake_common_start_menu_.GetPath().Append(start_menu_subfolder),
             path);
+
+  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_STARTUP,
+                             ShellUtil::SYSTEM_LEVEL, &path);
+  EXPECT_EQ(fake_common_startup_.GetPath(), path);
+
+  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_STARTUP,
+                             ShellUtil::CURRENT_USER, &path);
+  EXPECT_EQ(fake_user_startup_.GetPath(), path);
 }
 
 TEST_F(ShellUtilShortcutTest, MoveExistingShortcut) {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 12e5a46..44586fde 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -40990,6 +40990,7 @@
   <int value="746765012" label="AutofillEnableToolbarStatusChip:disabled"/>
   <int value="746944193" label="enable-automatic-password-saving:disabled"/>
   <int value="747076955" label="MobileIdentityConsistency:enabled"/>
+  <int value="747391377" label="DesktopPWAsRunOnOsLogin:disabled"/>
   <int value="747847237" label="PhysicalWeb:enabled"/>
   <int value="749312701" label="ChromeOSAccountManager:disabled"/>
   <int value="749516419" label="DragToSnapInClamshellMode:disabled"/>
@@ -41955,6 +41956,7 @@
       label="enable-message-center-always-scroll-up-upon-notification-removal"/>
   <int value="1861521561" label="OmniboxLocalEntitySuggestions:enabled"/>
   <int value="1861954820" label="HighResolutionMouseScrolling:enabled"/>
+  <int value="1862126613" label="DesktopPWAsRunOnOsLogin:enabled"/>
   <int value="1862207743" label="enable-android-spellchecker"/>
   <int value="1863622457" label="WebAuthentication:enabled"/>
   <int value="1865068568" label="disable-audio-support-for-desktop-share"/>