blob: 3cc4f54a0a332718c914b3b388e202a7f8937955 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_STARTUP_STARTUP_BROWSER_CREATOR_H_
#define CHROME_BROWSER_UI_STARTUP_STARTUP_BROWSER_CREATOR_H_
#include <memory>
#include <vector>
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/ui/startup/startup_types.h"
class Browser;
class GURL;
class PrefRegistrySimple;
class Profile;
namespace base {
class CommandLine;
}
namespace web_app {
namespace integration_tests {
class WebAppIntegrationTestDriver;
}
FORWARD_DECLARE_TEST(WebAppEngagementBrowserTest, CommandLineTab);
FORWARD_DECLARE_TEST(WebAppEngagementBrowserTest, CommandLineWindowByUrl);
FORWARD_DECLARE_TEST(WebAppEngagementBrowserTest, CommandLineWindowByAppId);
} // namespace web_app
// Indicates how Chrome should start up the first profile.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class StartupProfileMode {
// Regular startup with a browser window.
kBrowserWindow = 0,
// Profile picker window should be shown on startup.
kProfilePicker = 1,
// Chrome cannot start because no profiles are available.
kError = 2,
kMaxValue = kError,
};
// Indicates the reason why the StartupProfileMode was chosen.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class StartupProfileModeReason {
kError = 0,
// Cases when the profile picker is shown:
kMultipleProfiles = 1,
kPickerForcedByPolicy = 2,
// Cases when the profile picker is not shown:
kGuestModeRequested = 10,
// Deleted kGuestSessionLacros = 11,
kProfileDirSwitch = 12,
kProfileEmailSwitch = 13,
kIgnoreProfilePicker = 14,
kCommandLineTabs = 15,
kPickerNotSupported = 16,
kWasRestarted = 17,
kIncognitoModeRequested = 18,
kAppRequested = 19,
kUninstallApp = 20,
kGcpwSignin = 21,
kLaunchWithoutWindow = 22,
// The check for Win notifications seems to be done twice. Record these
// separately, just in case.
kNotificationLaunchIdWin1 = 23,
kNotificationLaunchIdWin2 = 24,
kPickerDisabledByPolicy = 25,
// Deleted kProfilesDisabledLacros = 26
kSingleProfile = 27,
kInactiveProfiles = 28,
kUserOptedOut = 29,
kProfileEmailSwitchCreateProfile = 30,
kMaxValue = kProfileEmailSwitchCreateProfile,
};
// Bundles the startup profile path together with a `StartupProfileMode`.
// Depending on `StartupProfileModeFromReason(reason)`, `path` is either:
// - regular profile path for `kBrowserWindow`; if the guest mode is requested,
// may contain either the default profile path or the guest profile path
// - empty profile path for `kProfilePicker` and `kError`
// TODO(crbug.com/40157821): return a guest profile path for the Guest
// mode.
struct StartupProfilePathInfo {
base::FilePath path;
StartupProfileModeReason reason = StartupProfileModeReason::kError;
};
// Bundles the startup profile together with a StartupProfileMode.
// Depending on the `mode` value, `profile` is either:
// - regular profile for `kBrowserWindow`; if the Guest mode is requested,
// may contain either the default profile path or the guest profile path
// - nullptr for `kProfilePicker` and `kError`
// TODO(crbug.com/40157821): return a guest profile for the Guest mode.
struct StartupProfileInfo {
raw_ptr<Profile, LeakedDanglingUntriaged> profile;
StartupProfileMode mode;
};
// Whether the profile picker should be shown based on `reason`.
StartupProfileMode StartupProfileModeFromReason(
StartupProfileModeReason reason);
// class containing helpers for BrowserMain to spin up a new instance and
// initialize the profile.
class StartupBrowserCreator {
public:
typedef std::vector<Profile*> Profiles;
StartupBrowserCreator();
StartupBrowserCreator(const StartupBrowserCreator&) = delete;
StartupBrowserCreator& operator=(const StartupBrowserCreator&) = delete;
~StartupBrowserCreator();
// Adds urls to be opened during first run. This overrides the standard
// tabs shown at first run.
// Invalid URLs (per `GURL::is_valid()`) are skipped.
void AddFirstRunTabs(const std::vector<GURL>& urls);
// This function is equivalent to ProcessCommandLine but should only be
// called during actual process startup.
bool Start(const base::CommandLine& cmd_line,
const base::FilePath& cur_dir,
StartupProfileInfo profile_info,
const Profiles& last_opened_profiles);
// This function performs command-line handling and is invoked only after
// start up (for example when we get a start request for another process).
// |command_line| holds the command line we need to process.
// |cur_dir| is the current working directory that the original process was
// invoked from.
// |profile_path_info| contains the directory that contains the profile that
// the command line arguments will be executed under.
static void ProcessCommandLineAlreadyRunning(
const base::CommandLine& command_line,
const base::FilePath& cur_dir,
const StartupProfilePathInfo& profile_path_info);
// Opens the set of startup pages from the current session startup prefs.
static void OpenStartupPages(
Browser* browser,
chrome::startup::IsProcessStartup process_startup);
// Returns true if we're launching a profile synchronously. In that case, the
// opened window should not cause a session restore.
static bool InSynchronousProfileLaunch();
// Launches a browser window associated with |profile|. |command_line| should
// be the command line passed to this process. |cur_dir| can be empty, which
// implies that the directory of the executable should be used.
// `process_startup` indicates whether this is the first browser.
// `is_first_run` indicates that this is a new profile.
// `restore_tabbed_browser` should only be flipped false by Ash full restore
// code path, suppressing restoring a normal browser when there were only PWAs
// open in previous session. See crbug.com/1463906.
void LaunchBrowser(const base::CommandLine& command_line,
Profile* profile,
const base::FilePath& cur_dir,
chrome::startup::IsProcessStartup process_startup,
chrome::startup::IsFirstRun is_first_run,
bool restore_tabbed_browser);
// Launches browser for `last_opened_profiles` if it's not empty. Otherwise,
// launches browser for `profile_info`. `restore_tabbed_browser` should
// only be flipped false by Ash full restore code path, suppressing restoring
// a normal browser when there were only PWAs open in previous session. See
// crbug.com/1463906.
void LaunchBrowserForLastProfiles(
const base::CommandLine& command_line,
const base::FilePath& cur_dir,
chrome::startup::IsProcessStartup process_startup,
chrome::startup::IsFirstRun is_first_run,
StartupProfileInfo profile_info,
const Profiles& last_opened_profiles,
bool restore_tabbed_browser);
// Returns true during browser process startup if the previous browser was
// restarted. This only returns true before the first StartupBrowserCreator
// destructs. WasRestarted() will update prefs::kWasRestarted to false, but
// caches the value of kWasRestarted until StartupBrowserCreator's
// dtor is called. After the dtor is called, this function returns the value
// of the preference which is expected to be false as per above.
static bool WasRestarted();
static SessionStartupPref GetSessionStartupPref(
const base::CommandLine& command_line,
const Profile* profile);
// For faking that no profiles have been launched yet.
static void ClearLaunchedProfilesForTesting();
static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
// Returns true if Chrome is intended to load a profile and launch without any
// window.
static bool ShouldLoadProfileWithoutWindow(
const base::CommandLine& command_line);
private:
friend class StartupBrowserCreatorImpl;
friend class StartupBrowserCreatorInfobarsTest;
friend class StartupBrowserCreatorInfobarsWithoutStartupWindowTest;
// TODO(crbug.com/40482804): Remove this when first_run_tabs gets refactored.
friend class StartupTabProviderImpl;
friend class web_app::integration_tests::WebAppIntegrationTestDriver;
FRIEND_TEST_ALL_PREFIXES(BrowserTest, AppIdSwitch);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest,
ReadingWasRestartedAfterNormalStart);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest,
ReadingWasRestartedAfterRestart);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest, UpdateWithTwoProfiles);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest, LastUsedProfileActivated);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest,
ValidNotificationLaunchId);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest,
InvalidNotificationLaunchId);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserWithListAppsFeature,
ListAppsForAllProfiles);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserWithListAppsFeature,
ListAppsForGivenProfile);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorChromeAppShortcutTest,
OpenAppShortcutNoPref);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorChromeAppShortcutTest,
OpenAppShortcutTabPref);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorChromeAppShortcutTest,
OpenAppShortcutWindowPref);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorChromeAppShortcutTest,
OpenPolicyForcedAppShortcut);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorChromeAppShortcutTestWithLaunch,
OpenAppShortcutNoPref);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorChromeAppShortcutTestWithLaunch,
OpenAppShortcutTabPref);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorChromeAppShortcutTestWithLaunch,
OpenAppShortcutWindowPref);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorChromeAppShortcutTestWithLaunch,
OpenPolicyForcedAppShortcut);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest, OpenAppUrlShortcut);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest,
OpenAppUrlIncognitoShortcut);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserWithRealWebAppTest,
LastUsedProfilesWithRealWebApp);
FRIEND_TEST_ALL_PREFIXES(web_app::WebAppEngagementBrowserTest,
CommandLineTab);
FRIEND_TEST_ALL_PREFIXES(web_app::WebAppEngagementBrowserTest,
CommandLineWindowByUrl);
FRIEND_TEST_ALL_PREFIXES(web_app::WebAppEngagementBrowserTest,
CommandLineWindowByAppId);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest,
LastUsedProfilesWithWebApp);
FRIEND_TEST_ALL_PREFIXES(StartupBrowserCreatorTest,
KSameTabSwitchReplacesActiveTab);
bool ProcessCmdLineImpl(const base::CommandLine& command_line,
const base::FilePath& cur_dir,
chrome::startup::IsProcessStartup process_startup,
StartupProfileInfo profile_info,
const Profiles& last_opened_profiles);
// Launches the |last_used_profile| with the full command line, and the other
// |last_opened_profiles| without the URLs to launch.
void ProcessLastOpenedProfiles(
const base::CommandLine& command_line,
const base::FilePath& cur_dir,
chrome::startup::IsProcessStartup process_startup,
chrome::startup::IsFirstRun is_first_run,
Profile* last_used_profile,
const Profiles& last_opened_profiles);
// This function performs command-line handling and is invoked only after
// start up (for example when we get a start request for another process).
// |command_line| holds the command line being processed.
// |cur_dir| is the current working directory that the original process was
// invoked from.
// |profile| is the profile the apps will be launched in.
static bool ProcessLoadApps(const base::CommandLine& command_line,
const base::FilePath& cur_dir,
Profile* profile);
// Callback after a profile has been initialized. `profile` should be nullptr
// if `mode` is `StartupProfileMode::kProfilePicker`.
static void ProcessCommandLineWithProfile(
const base::CommandLine& command_line,
const base::FilePath& cur_dir,
StartupProfileMode mode,
Profile* profile);
// Returns true once a profile was activated. Used by the
// StartupBrowserCreatorTest.LastUsedProfileActivated test.
static bool ActivatedProfile();
// Additional tabs to open during first run.
std::vector<GURL> first_run_tabs_;
// True if we have already read and reset the preference kWasRestarted. (A
// member variable instead of a static variable inside WasRestarted because
// of testing.)
static bool was_restarted_read_;
static bool in_synchronous_profile_launch_;
static bool is_launching_browser_for_last_profiles_;
};
// Returns true if |profile| has exited uncleanly and has not been launched
// after the unclean exit.
bool HasPendingUncleanExit(Profile* profile);
// Adds launched |profile| to ProfileLaunchObserver.
void AddLaunchedProfile(Profile* profile);
// Returns the path that contains the profile that should be loaded on process
// startup. This can do blocking operations to check if the profile exists in
// the case of using --profile-directory and
// --ignore-profile-directory-if-not-exists together.
// When the profile picker is shown on startup, this returns the Guest profile
// path. On Mac, the startup profile path is also used to open URLs at startup,
// bypassing the profile picker, because the profile picker does not support it.
// TODO(crbug.com/40159795): Remove this parameter once the picker
// supports opening URLs.
StartupProfilePathInfo GetStartupProfilePath(
const base::FilePath& cur_dir,
const base::CommandLine& command_line,
bool ignore_profile_picker);
#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
// Returns the profile that should be loaded on process startup. This is either
// the profile returned by GetStartupProfilePath, or the guest profile along
// with StartupProfileMode::kProfilePicker mode if the profile picker should be
// opened. Returns nullptr with kError if neither the regular profile nor the
// profile picker can be opened.
StartupProfileInfo GetStartupProfile(const base::FilePath& cur_dir,
const base::CommandLine& command_line);
// Returns the profile that should be loaded on process startup when
// GetStartupProfile() returns kError. This may return kError if neither any
// profile nor the profile picker can be opened.
StartupProfileInfo GetFallbackStartupProfile();
#endif // !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
#endif // CHROME_BROWSER_UI_STARTUP_STARTUP_BROWSER_CREATOR_H_