#include "chrome/browser/ui/startup/startup_browser_creator.h"
#include <stddef.h>
#include <optional>
#include <set>
#include <string>
#include <utility>
#include "apps/switches.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/debug/dump_without_crashing.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/statistics_recorder.h"
#include "base/scoped_multi_source_observation.h"
#include "base/strings/string_tokenizer.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/trace_event/trace_event.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "chrome/browser/app_mode/app_mode_utils.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/apps/platform_apps/app_load_service.h"
#include "chrome/browser/apps/platform_apps/platform_app_launch.h"
#include "chrome/browser/browser_features.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/startup_helper.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/lifetime/browser_shutdown.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/nuke_profile_directory_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_observer.h"
#include "chrome/browser/profiles/profile_window.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/sessions/exit_type_service.h"
#include "chrome/browser/signin/signin_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/browser/ui/startup/launch_mode_recorder.h"
#include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
#include "chrome/browser/ui/startup/startup_tab_provider.h"
#include "chrome/browser/ui/startup/startup_types.h"
#include "chrome/browser/ui/startup/web_app_startup_utils.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/web_applications/web_app_ui_manager_impl.h"
#include "chrome/browser/web_applications/web_app_ui_manager.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/search_engines/util.h"
#include "components/services/app_service/public/cpp/app_launch_util.h"
#include "components/startup_metric_utils/browser/startup_metric_utils.h"
#include "components/url_formatter/url_fixer.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/common/content_switches.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/switches.h"
#include "printing/buildflags/buildflags.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "ash/constants/ash_switches.h"
#include "chrome/browser/ash/app_mode/app_launch_utils.h"
#include "chrome/browser/ash/app_mode/kiosk_app_types.h"
#include "chrome/browser/ash/app_mode/kiosk_controller.h"
#include "chrome/browser/ash/app_restore/full_restore_service.h"
#include "chrome/browser/ash/app_restore/full_restore_service_factory.h"
#include "chrome/browser/ash/floating_workspace/floating_workspace_service.h"
#include "chrome/browser/ash/floating_workspace/floating_workspace_service_factory.h"
#include "chrome/browser/ash/floating_workspace/floating_workspace_util.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
#include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
#include "components/user_manager/user_manager.h"
#else
#include "chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h"
#include "chrome/browser/ui/profiles/profile_picker.h"
#endif
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
#include "chrome/browser/ui/startup/first_run_service.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "chrome/browser/web_applications/os_integration/mac/app_shim_registry.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/notifications/notification_platform_bridge_win.h"
#include "chrome/browser/notifications/win/notification_launch_id.h"
#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win.h"
#include "chrome/browser/ui/webui/settings/reset_settings_handler.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/credential_provider/common/gcp_strings.h"
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#include "chrome/browser/headless/headless_mode_util.h"
#include "chrome/browser/ui/startup/web_app_info_recorder_utils.h"
#include "components/headless/policy/headless_mode_policy.h"
#endif
#if !BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/web_applications/isolated_web_apps/install/isolated_web_app_installation_manager.h"
#endif
#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/startup/focus/focus_handler.h"
#endif
using content::BrowserThread;
using content::ChildProcessSecurityPolicy;
namespace {
class ProfileLaunchObserver : public ProfileObserver,
public BrowserListObserver {
public:
ProfileLaunchObserver() { BrowserList::AddObserver(this); }
ProfileLaunchObserver(const ProfileLaunchObserver&) = delete;
ProfileLaunchObserver& operator=(const ProfileLaunchObserver&) = delete;
~ProfileLaunchObserver() override { BrowserList::RemoveObserver(this); }
void OnBrowserAdded(Browser* browser) override {
opened_profiles_.insert(browser->profile());
MaybeActivateProfile();
}
void OnProfileWillBeDestroyed(Profile* profile) override {
observed_profiles_.RemoveObservation(profile);
launched_profiles_.erase(profile);
opened_profiles_.erase(profile);
if (profile == profile_to_activate_) {
profile_to_activate_ = nullptr;
}
MaybeActivateProfile();
}
bool HasBeenLaunchedAndBrowserOpen(const Profile* profile) const {
return base::Contains(opened_profiles_, profile) &&
base::Contains(launched_profiles_, profile);
}
void AddLaunched(Profile* profile) {
if (!observed_profiles_.IsObservingSource(profile)) {
observed_profiles_.AddObservation(profile);
}
launched_profiles_.insert(profile);
if (chrome::FindBrowserWithProfile(profile)) {
opened_profiles_.insert(profile);
}
}
void Clear() {
launched_profiles_.clear();
opened_profiles_.clear();
}
bool activated_profile() { return activated_profile_; }
void set_profile_to_activate(Profile* profile) {
if (!observed_profiles_.IsObservingSource(profile)) {
observed_profiles_.AddObservation(profile);
}
profile_to_activate_ = profile;
MaybeActivateProfile();
}
private:
void MaybeActivateProfile() {
if (!profile_to_activate_) {
return;
}
auto i = launched_profiles_.begin();
for (; i != launched_profiles_.end(); ++i) {
if (opened_profiles_.find(*i) == opened_profiles_.end()) {
return;
}
}
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&ProfileLaunchObserver::ActivateProfile,
base::Unretained(this)));
observed_profiles_.RemoveAllObservations();
BrowserList::RemoveObserver(this);
}
void ActivateProfile() {
if (profile_to_activate_) {
Browser* browser = chrome::FindBrowserWithProfile(profile_to_activate_);
if (browser) {
browser->window()->Activate();
}
profile_to_activate_ = nullptr;
}
activated_profile_ = true;
}
std::set<raw_ptr<const Profile, SetExperimental>> launched_profiles_;
std::set<raw_ptr<const Profile, SetExperimental>> opened_profiles_;
raw_ptr<Profile, DanglingUntriaged> profile_to_activate_ = nullptr;
bool activated_profile_ = false;
base::ScopedMultiSourceObservation<Profile, ProfileObserver>
observed_profiles_{this};
};
base::LazyInstance<ProfileLaunchObserver>::DestructorAtExit
profile_launch_observer = LAZY_INSTANCE_INITIALIZER;
void DumpBrowserHistograms(const base::FilePath& output_file) {
std::string output_string(
base::StatisticsRecorder::ToJSON(base::JSON_VERBOSITY_LEVEL_FULL));
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
base::WriteFile(output_file, output_string);
}
bool CanOpenProfileOnStartup(StartupProfileInfo profile_info) {
#if BUILDFLAG(IS_CHROMEOS)
DCHECK_NE(profile_info.mode, StartupProfileMode::kProfilePicker);
return true;
#else
if (profile_info.mode == StartupProfileMode::kProfilePicker) {
return false;
}
Profile* profile = profile_info.profile;
DCHECK(!profile->IsSystemProfile());
ProfileAttributesEntry* entry =
g_browser_process->profile_manager()
->GetProfileAttributesStorage()
.GetProfileAttributesWithPath(profile->GetPath());
if (entry && entry->IsSigninRequired()) {
return false;
}
if (profile->IsGuestSession()) {
return chrome::GetBrowserCount(
profile->GetPrimaryOTRProfile(false)) > 0;
}
return true;
#endif
}
#if !BUILDFLAG(IS_CHROMEOS)
StartupProfileMode GetStartupProfileMode(
ProfileManager* profile_manager,
bool has_command_line_specified_profile_directory,
const base::CommandLine& command_line) {
if (StartupBrowserCreator::WasRestarted()) {
return StartupProfileMode::kBrowserWindow;
}
if (profiles::IsGuestModeRequested(command_line,
g_browser_process->local_state(),
false) ||
command_line.HasSwitch(switches::kIncognito) ||
has_command_line_specified_profile_directory) {
return StartupProfileMode::kBrowserWindow;
}
if (command_line.HasSwitch(switches::kApp) ||
command_line.HasSwitch(switches::kAppId)) {
return StartupProfileMode::kBrowserWindow;
}
#if BUILDFLAG(IS_WIN)
if (command_line.HasSwitch(switches::kUninstallAppId)) {
return StartupProfileMode::kBrowserWindow;
}
if (command_line.HasSwitch(credential_provider::kGcpwSigninSwitch)) {
return StartupProfileMode::kBrowserWindow;
}
base::FilePath profile_basename =
NotificationLaunchId::GetNotificationLaunchProfileBaseName(command_line);
if (!profile_basename.empty()) {
return StartupProfileMode::kBrowserWindow;
}
#endif
if (StartupBrowserCreator::ShouldLoadProfileWithoutWindow(command_line)) {
return StartupProfileMode::kBrowserWindow;
}
return ProfilePicker::GetStartupMode();
}
#endif
Profile* GetPrivateProfileIfRequested(const base::CommandLine& command_line,
StartupProfileInfo profile_info) {
bool open_guest_profile = profiles::IsGuestModeRequested(
command_line, g_browser_process->local_state(),
true);
if (open_guest_profile) {
Profile* profile = g_browser_process->profile_manager()->GetProfile(
ProfileManager::GetGuestProfilePath());
profile = profile->GetPrimaryOTRProfile(true);
return profile;
}
if (profile_info.mode == StartupProfileMode::kProfilePicker) {
return profile_info.profile;
}
Profile* profile = profile_info.profile;
if (IncognitoModePrefs::ShouldLaunchIncognito(command_line,
profile->GetPrefs())) {
return profile->GetPrimaryOTRProfile(true);
} else {
bool expect_incognito = command_line.HasSwitch(switches::kIncognito);
LOG_IF(WARNING, expect_incognito)
<< "Incognito mode disabled by policy, launching a normal "
<< "browser session.";
}
return profile;
}
#if !BUILDFLAG(IS_CHROMEOS)
StartupProfileInfo GetProfilePickerStartupProfileInfo() {
ProfileManager* profile_manager = g_browser_process->profile_manager();
if (!profile_manager->GetProfile(ProfileManager::GetSystemProfilePath())) {
return {.profile = nullptr, .mode = StartupProfileMode::kError};
}
return {.profile = nullptr, .mode = StartupProfileMode::kProfilePicker};
}
#endif
bool IsSilentLaunchEnabled(const base::CommandLine& command_line,
const Profile* profile) {
if (command_line.HasSwitch(switches::kNoStartupWindow)) {
return true;
}
if (command_line.HasSwitch(switches::kSilentLaunch)) {
return true;
}
if (StartupBrowserCreator::ShouldLoadProfileWithoutWindow(command_line)) {
return true;
}
#if BUILDFLAG(IS_CHROMEOS)
return profile->GetPrefs()->GetBoolean(
prefs::kStartupBrowserWindowLaunchSuppressed);
#else
return false;
#endif
}
bool CanOpenWebApp(Profile* profile) {
return web_app::AreWebAppsEnabled(profile) &&
apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile);
}
bool MaybeLaunchAppShortcutWindow(const base::CommandLine& command_line,
const base::FilePath& cur_dir,
chrome::startup::IsFirstRun is_first_run,
Profile* profile) {
if (!profile) {
return false;
}
if (!command_line.HasSwitch(switches::kApp)) {
return false;
}
std::string url_string = command_line.GetSwitchValueASCII(switches::kApp);
if (url_string.empty()) {
return false;
}
#if BUILDFLAG(IS_WIN)
base::ReplaceSubstringsAfterOffset(&url_string, 0, "\\x", "%");
#endif
GURL url(url_string);
if (!url.is_empty() && url.is_valid()) {
content::ChildProcessSecurityPolicy* policy =
content::ChildProcessSecurityPolicy::GetInstance();
if (policy->IsWebSafeScheme(url.GetScheme()) ||
url.SchemeIs(url::kFileScheme)) {
const content::WebContents* web_contents =
apps::OpenExtensionAppShortcutWindow(profile, url);
if (web_contents) {
web_app::startup::FinalizeWebAppLaunch(
web_app::startup::OpenMode::kInWindowByUrl, command_line,
is_first_run, chrome::FindBrowserWithTab(web_contents),
apps::LaunchContainer::kLaunchContainerWindow);
return true;
}
}
}
return false;
}
bool MaybeLaunchExtensionApp(const base::CommandLine& command_line,
const base::FilePath& cur_dir,
chrome::startup::IsFirstRun is_first_run,
Profile* profile) {
if (!command_line.HasSwitch(switches::kAppId)) {
return false;
}
std::string app_id = command_line.GetSwitchValueASCII(switches::kAppId);
const extensions::Extension* extension =
extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension(
app_id);
if (!extension) {
return false;
}
LaunchAppWithCallback(
profile, app_id, command_line, cur_dir,
base::BindOnce(&web_app::startup::FinalizeWebAppLaunch,
web_app::startup::OpenMode::kInWindowByAppId, command_line,
is_first_run));
return true;
}
enum class IncognitoForcedStart {
kNoSwitchAndNotForced = 0,
kSwitchButNotForced = 1,
kNoSwitchButForced = 2,
kSwitchAndForced = 3,
kMaxValue = kSwitchAndForced,
};
void RecordIncognitoForcedStart(bool should_launch_incognito,
bool has_incognito_switch) {
if (has_incognito_switch) {
base::UmaHistogramEnumeration(
"Startup.IncognitoForcedStart",
should_launch_incognito ? IncognitoForcedStart::kSwitchAndForced
: IncognitoForcedStart::kSwitchButNotForced);
} else {
base::UmaHistogramEnumeration(
"Startup.IncognitoForcedStart",
should_launch_incognito ? IncognitoForcedStart::kNoSwitchButForced
: IncognitoForcedStart::kNoSwitchAndNotForced);
}
}
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
void OpenNewWindowForFirstRun(const base::CommandLine& command_line,
Profile* profile,
const base::FilePath& cur_dir,
const std::vector<GURL>& first_run_urls,
chrome::startup::IsProcessStartup process_startup,
chrome::startup::IsFirstRun is_first_run,
bool proceed) {
if (!proceed) {
return;
}
StartupBrowserCreator browser_creator;
browser_creator.AddFirstRunTabs(first_run_urls);
browser_creator.LaunchBrowser(command_line, profile, cur_dir, process_startup,
is_first_run, true);
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
std::optional<ash::KioskAppId> GetAppId(const base::CommandLine& command_line,
Profile* profile) {
const user_manager::User* user =
ash::ProfileHelper::Get()->GetUserByProfile(profile);
if (!user) {
return std::nullopt;
}
switch (user->GetType()) {
case user_manager::UserType::kKioskChromeApp:
return ash::KioskAppId::ForChromeApp(
command_line.GetSwitchValueASCII(::switches::kAppId),
user->GetAccountId());
case user_manager::UserType::kKioskWebApp:
return ash::KioskAppId::ForWebApp(user->GetAccountId());
case user_manager::UserType::kKioskIWA:
return ash::KioskAppId::ForIsolatedWebApp(user->GetAccountId());
case user_manager::UserType::kRegular:
case user_manager::UserType::kChild:
case user_manager::UserType::kGuest:
case user_manager::UserType::kPublicAccount:
case user_manager::UserType::kKioskArcvmApp:
return std::nullopt;
}
}
#endif
#if !BUILDFLAG(IS_CHROMEOS)
bool ShouldForceLaunchIntoNewProfileWithEmail(
const base::CommandLine& command_line,
const Profile* profile) {
if (base::FeatureList::IsEnabled(features::kCreateProfileIfNoneExists) &&
command_line.HasSwitch(switches::kCreateProfileEmailIfNotExists)) {
std::string switch_email =
command_line.GetSwitchValueASCII(switches::kProfileEmail);
if (switch_email.empty()) {
return false;
}
if (profile == nullptr) {
return true;
}
if (profile != nullptr && profile->GetProfileUserName() != switch_email) {
return true;
}
}
return false;
}
#endif
#if !BUILDFLAG(IS_ANDROID)
std::optional<bool> MaybeHandleFocusRequest(
const base::CommandLine& command_line,
chrome::startup::IsProcessStartup process_startup,
const StartupProfileInfo& profile_info) {
if (process_startup != chrome::startup::IsProcessStartup::kNo ||
!command_line.HasSwitch(switches::kFocus) ||
profile_info.mode != StartupProfileMode::kBrowserWindow ||
!profile_info.profile) {
return std::nullopt;
}
focus::FocusResult focus_result = focus::ProcessFocusRequestWithResultFile(
command_line, *profile_info.profile);
if (focus_result.status == focus::FocusStatus::kFocused ||
focus_result.status == focus::FocusStatus::kParseError ||
(focus_result.status == focus::FocusStatus::kNoMatch &&
command_line.GetArgs().empty())) {
return true;
}
return std::nullopt;
}
#endif
struct ProfileSetupResult {
bool silent_launch;
bool should_launch_incognito;
bool can_use_profile;
raw_ptr<Profile> privacy_safe_profile;
};
ProfileSetupResult SetupProfileAndIncognito(
const base::CommandLine& command_line,
const StartupProfileInfo& profile_info) {
ProfileSetupResult result;
result.silent_launch = false;
result.should_launch_incognito =
profile_info.mode != StartupProfileMode::kProfilePicker &&
IncognitoModePrefs::ShouldLaunchIncognito(
command_line, profile_info.profile->GetPrefs());
result.can_use_profile =
CanOpenProfileOnStartup(profile_info) && !result.should_launch_incognito;
RecordIncognitoForcedStart(result.should_launch_incognito,
command_line.HasSwitch(switches::kIncognito));
result.privacy_safe_profile =
GetPrivateProfileIfRequested(command_line, profile_info);
return result;
}
std::optional<bool> MaybeHandleValidateCrx(
const base::CommandLine& command_line,
chrome::startup::IsProcessStartup process_startup) {
if (!command_line.HasSwitch(switches::kValidateCrx)) {
return std::nullopt;
}
if (process_startup == chrome::startup::IsProcessStartup::kNo) {
LOG(ERROR) << "chrome is already running; you must close all running "
<< "instances before running with the --"
<< switches::kValidateCrx << " flag";
return false;
}
extensions::StartupHelper helper;
std::string message;
std::string error;
if (helper.ValidateCrx(command_line, &error)) {
message = std::string("ValidateCrx Success");
} else {
message = std::string("ValidateCrx Failure: ") + error;
}
printf("%s\n", message.c_str());
return false;
}
StartupBrowserCreator::ProcessCommandLineCallback*
GetProcessCommandLineCallback() {
static base::NoDestructor<StartupBrowserCreator::ProcessCommandLineCallback>
callback;
return callback.get();
}
}
StartupBrowserCreator::StartupBrowserCreator() = default;
StartupBrowserCreator::~StartupBrowserCreator() {
was_restarted_read_ = false;
}
bool StartupBrowserCreator::was_restarted_read_ = false;
bool StartupBrowserCreator::in_synchronous_profile_launch_ = false;
void StartupBrowserCreator::AddFirstRunTabs(const std::vector<GURL>& urls) {
for (const auto& url : urls) {
if (url.is_valid()) {
first_run_tabs_.push_back(url);
}
}
}
bool StartupBrowserCreator::Start(const base::CommandLine& cmd_line,
const base::FilePath& cur_dir,
StartupProfileInfo profile_info,
const Profiles& last_opened_profiles) {
TRACE_EVENT0("startup", "StartupBrowserCreator::Start");
return ProcessCmdLineImpl(cmd_line, cur_dir,
chrome::startup::IsProcessStartup::kYes,
profile_info, last_opened_profiles);
}
bool StartupBrowserCreator::InSynchronousProfileLaunch() {
return in_synchronous_profile_launch_;
}
void StartupBrowserCreator::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) {
TRACE_EVENT0("ui", "StartupBrowserCreator::LaunchBrowser");
SCOPED_UMA_HISTOGRAM_TIMER("Startup.StartupBrowserCreator.LaunchBrowser");
DCHECK(profile);
#if BUILDFLAG(IS_WIN)
DCHECK(!command_line.HasSwitch(credential_provider::kGcpwSigninSwitch));
DCHECK(!command_line.HasSwitch(switches::kNotificationLaunchId));
#endif
in_synchronous_profile_launch_ =
process_startup == chrome::startup::IsProcessStartup::kYes;
profile = GetPrivateProfileIfRequested(
command_line, {profile, StartupProfileMode::kBrowserWindow});
if (!IsSilentLaunchEnabled(command_line, profile)) {
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
auto* fre_service = FirstRunServiceFactory::GetForBrowserContext(profile);
if (fre_service && fre_service->ShouldOpenFirstRun()) {
fre_service->OpenFirstRunIfNeeded(base::BindOnce(
&OpenNewWindowForFirstRun, command_line, profile, cur_dir,
first_run_tabs_, process_startup, is_first_run));
return;
}
#endif
StartupBrowserCreatorImpl lwp(cur_dir, command_line, this, is_first_run);
lwp.Launch(profile,
in_synchronous_profile_launch_
? chrome::startup::IsProcessStartup::kYes
: chrome::startup::IsProcessStartup::kNo,
restore_tabbed_browser);
}
in_synchronous_profile_launch_ = false;
profile_launch_observer.Get().AddLaunched(profile);
}
void StartupBrowserCreator::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) {
TRACE_EVENT0("ui", "StartupBrowserCreator::LaunchBrowserForLastProfiles");
DCHECK_NE(profile_info.mode, StartupProfileMode::kError);
Profile* profile = profile_info.profile;
bool was_windows_notification_launch = false;
#if BUILDFLAG(IS_WIN)
was_windows_notification_launch =
command_line.HasSwitch(switches::kNotificationLaunchId);
#endif
if (profile_info.mode == StartupProfileMode::kProfilePicker) {
#if BUILDFLAG(IS_CHROMEOS)
NOTREACHED();
#else
if (ShouldForceLaunchIntoNewProfileWithEmail(command_line, profile)) {
std::string email =
command_line.GetSwitchValueASCII(switches::kProfileEmail);
ProfilePicker::Show(ProfilePicker::Params::FromStartupWithEmail(email));
return;
}
ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint(
process_startup == chrome::startup::IsProcessStartup::kYes
? ProfilePicker::EntryPoint::kOnStartup
: ProfilePicker::EntryPoint::kNewSessionOnExistingProcess));
return;
#endif
}
if (last_opened_profiles.empty() || was_windows_notification_launch) {
if (CanOpenProfileOnStartup(profile_info)) {
Profile* profile_to_open = profile->IsGuestSession()
? profile->GetPrimaryOTRProfile(
true)
: profile;
#if BUILDFLAG(IS_CHROMEOS)
if (process_startup == chrome::startup::IsProcessStartup::kYes) {
if (ash::floating_workspace_util::IsFloatingWorkspaceV2Enabled() ||
ash::floating_workspace_util::IsFloatingSsoEnabled(
profile_to_open)) {
ash::FloatingWorkspaceServiceFactory::GetForProfile(profile_to_open);
}
if (ash::floating_workspace_util::ShouldHandleRestartRestore()) {
return;
}
auto* full_restore_service =
ash::full_restore::FullRestoreServiceFactory::GetForProfile(
profile_to_open);
if (full_restore_service) {
full_restore_service->LaunchBrowserWhenReady();
return;
}
}
#endif
LaunchBrowser(command_line, profile_to_open, cur_dir, process_startup,
is_first_run, restore_tabbed_browser);
return;
}
#if BUILDFLAG(IS_CHROMEOS)
NOTREACHED();
#else
ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint(
process_startup == chrome::startup::IsProcessStartup::kYes
? ProfilePicker::EntryPoint::kOnStartupNoProfile
: ProfilePicker::EntryPoint::
kNewSessionOnExistingProcessNoProfile));
return;
#endif
}
ProcessLastOpenedProfiles(command_line, cur_dir, process_startup,
is_first_run, profile, last_opened_profiles);
}
bool StartupBrowserCreator::WasRestarted() {
static bool was_restarted = false;
if (!was_restarted_read_) {
PrefService* pref_service = g_browser_process->local_state();
was_restarted = pref_service->GetBoolean(prefs::kWasRestarted);
pref_service->SetBoolean(prefs::kWasRestarted, false);
was_restarted_read_ = true;
}
return was_restarted;
}
SessionStartupPref StartupBrowserCreator::GetSessionStartupPref(
const base::CommandLine& command_line,
const Profile* profile) {
DCHECK(profile);
const PrefService* prefs = profile->GetPrefs();
SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
#if BUILDFLAG(IS_CHROMEOS)
const bool is_first_run =
user_manager::UserManager::Get()->IsCurrentUserNew();
const bool did_restart = false;
StartupBrowserCreator::WasRestarted();
#else
const bool is_first_run = first_run::IsChromeFirstRun();
const bool did_restart = StartupBrowserCreator::WasRestarted();
#endif
if (is_first_run && SessionStartupPref::TypeIsDefault(prefs)) {
pref.type = SessionStartupPref::DEFAULT;
}
bool restore_last_session =
command_line.HasSwitch(switches::kRestoreLastSession);
if ((restore_last_session || did_restart) && !profile->IsNewProfile()) {
pref.type = SessionStartupPref::LAST;
}
if (!profile->IsGuestSession()) {
ProfileAttributesEntry* entry =
g_browser_process->profile_manager()
->GetProfileAttributesStorage()
.GetProfileAttributesWithPath(profile->GetPath());
if (entry && entry->IsSigninRequired()) {
pref.type = SessionStartupPref::LAST;
}
}
if ((pref.ShouldRestoreLastSession() && !pref.ShouldOpenUrls()) &&
(profile->IsGuestSession() || profile->IsOffTheRecord())) {
pref.type = SessionStartupPref::DEFAULT;
}
return pref;
}
void StartupBrowserCreator::ClearLaunchedProfilesForTesting() {
profile_launch_observer.Get().Clear();
}
void StartupBrowserCreator::RegisterLocalStatePrefs(
PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(prefs::kPromotionsEnabled, true);
#if !BUILDFLAG(IS_CHROMEOS)
registry->RegisterBooleanPref(prefs::kCommandLineFlagSecurityWarningsEnabled,
true);
#endif
registry->RegisterBooleanPref(prefs::kSuppressUnsupportedOSWarning, false);
registry->RegisterBooleanPref(prefs::kWasRestarted, false);
#if BUILDFLAG(IS_WIN)
registry->RegisterStringPref(prefs::kShortcutMigrationVersion, std::string());
#endif
}
void StartupBrowserCreator::RegisterProfilePrefs(PrefRegistrySimple* registry) {
#if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
registry->RegisterStringPref(prefs::kNaviOnboardGroup, "");
#endif
}
bool StartupBrowserCreator::ShouldLoadProfileWithoutWindow(
const base::CommandLine& command_line) {
if (command_line.HasSwitch(switches::kNoStartupWindow)) {
return true;
}
return false;
}
bool StartupBrowserCreator::ProcessCmdLineImpl(
const base::CommandLine& command_line,
const base::FilePath& cur_dir,
chrome::startup::IsProcessStartup process_startup,
StartupProfileInfo profile_info,
const Profiles& last_opened_profiles) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_NE(profile_info.mode, StartupProfileMode::kError);
TRACE_EVENT0("startup", "StartupBrowserCreator::ProcessCmdLineImpl");
ComputeAndRecordLaunchMode(command_line);
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
if (headless::IsHeadlessMode() &&
headless::HeadlessModePolicy::IsHeadlessModeDisabled(
g_browser_process->local_state())) {
LOG(ERROR) << "Headless mode is disallowed by the system admin.";
return false;
}
#endif
if (process_startup == chrome::startup::IsProcessStartup::kYes &&
command_line.HasSwitch(switches::kDisablePromptOnRepost)) {
content::NavigationController::DisablePromptOnRepost();
}
chrome::startup::IsFirstRun is_first_run =
first_run::IsChromeFirstRun() ? chrome::startup::IsFirstRun::kYes
: chrome::startup::IsFirstRun::kNo;
ProfileSetupResult profile_setup =
SetupProfileAndIncognito(command_line, profile_info);
bool silent_launch = profile_setup.silent_launch;
bool can_use_profile = profile_setup.can_use_profile;
Profile* privacy_safe_profile = profile_setup.privacy_safe_profile;
#if !BUILDFLAG(IS_ANDROID)
if (std::optional<bool> focus_result = MaybeHandleFocusRequest(
command_line, process_startup, profile_info)) {
return *focus_result;
}
#endif
if (std::optional<bool> crx_result =
MaybeHandleValidateCrx(command_line, process_startup)) {
return *crx_result;
}
#if BUILDFLAG(IS_CHROMEOS)
if (command_line.HasSwitch(ash::switches::kLoginManager)) {
silent_launch = true;
}
if (IsRunningInForcedAppMode()) {
Profile* profile = profile_info.profile;
silent_launch = true;
if (auto app_id = GetAppId(command_line, profile); app_id.has_value()) {
ash::KioskController::Get().StartSessionAfterCrash(app_id.value(),
profile);
} else {
chrome::AttemptUserExit();
return false;
}
}
#endif
if (process_startup == chrome::startup::IsProcessStartup::kNo &&
command_line.HasSwitch(switches::kDumpBrowserHistograms)) {
base::FilePath output_file(
command_line.GetSwitchValuePath(switches::kDumpBrowserHistograms));
if (!output_file.empty()) {
base::ThreadPool::PostTask(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
base::BindOnce(&DumpBrowserHistograms, output_file));
}
silent_launch = true;
}
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
if (base::FeatureList::IsEnabled(features::kListWebAppsSwitch) &&
command_line.HasSwitch(switches::kListApps)) {
base::FilePath output_file(
command_line.GetSwitchValuePath(switches::kListApps));
if (!output_file.empty() && output_file.IsAbsolute()) {
base::FilePath profile_base_name(
command_line.GetSwitchValuePath(switches::kProfileBaseName));
chrome::startup::WriteWebAppsToFile(output_file, profile_base_name);
}
return true;
}
#endif
#if !BUILDFLAG(IS_CHROMEOS)
if (base::FeatureList::IsEnabled(features::kOnConnectNative) &&
command_line.HasSwitch(switches::kNativeMessagingConnectHost) &&
command_line.HasSwitch(switches::kNativeMessagingConnectExtension)) {
if (profile_info.mode == StartupProfileMode::kProfilePicker) {
NOTREACHED()
<< "Failed to launch a native message host: couldn't pick a profile";
} else {
extensions::LaunchNativeMessageHostFromNativeApp(
command_line.GetSwitchValueASCII(
switches::kNativeMessagingConnectExtension),
command_line.GetSwitchValueASCII(
switches::kNativeMessagingConnectHost),
command_line.GetSwitchValueASCII(switches::kNativeMessagingConnectId),
privacy_safe_profile);
}
}
if (web_app::IsolatedWebAppInstallationManager::HasIwaInstallSwitch(
command_line)) {
if (profile_info.mode == StartupProfileMode::kProfilePicker) {
auto* profile_manager = g_browser_process->profile_manager();
LOG(ERROR) << "Command line switches to install IWAs are incompatible "
"with the Profile Picker. If you have multiple profiles, "
"consider using the --"
<< switches::kProfileDirectory
<< " switch to select a profile (it accepts the name of a "
"profile directory in "
<< profile_manager->user_data_dir() << ", such as '"
<< profile_manager->GetLastUsedProfileDir().BaseName()
<< "').";
return false;
} else {
web_app::IsolatedWebAppInstallationManager::
MaybeInstallIwaFromCommandLine(command_line, *privacy_safe_profile);
}
}
#endif
if (command_line.HasSwitch(switches::kNoStartupWindow)) {
silent_launch = true;
}
if (silent_launch) {
bool should_block_browser_startup_metrics =
process_startup == chrome::startup::IsProcessStartup::kYes;
#if BUILDFLAG(IS_CHROMEOS)
should_block_browser_startup_metrics &=
!command_line.HasSwitch(ash::switches::kLoginManager);
#endif
if (should_block_browser_startup_metrics) {
startup_metric_utils::GetBrowser().SetNonBrowserUIDisplayed();
}
return true;
}
#if BUILDFLAG(IS_WIN)
if (command_line.HasSwitch(switches::kUninstallAppId)) {
CHECK_EQ(profile_info.mode, StartupProfileMode::kBrowserWindow)
<< "Failed to uninstall app: couldn't pick a profile";
std::string app_id =
command_line.GetSwitchValueASCII(switches::kUninstallAppId);
web_app::WebAppProvider::GetForWebApps(privacy_safe_profile)
->ui_manager()
.AsImpl()
->UninstallWebAppFromStartupSwitch(app_id);
return true;
}
#endif
if (command_line.HasSwitch(extensions::switches::kLoadApps) &&
can_use_profile) {
if (!ProcessLoadApps(command_line, cur_dir, privacy_safe_profile)) {
return false;
}
if (chrome::GetBrowserCount(privacy_safe_profile) != 0) {
return true;
}
}
if (command_line.HasSwitch(apps::kLoadAndLaunchApp) && can_use_profile) {
base::CommandLine::StringType path =
command_line.GetSwitchValueNative(apps::kLoadAndLaunchApp);
if (!apps::AppLoadService::Get(privacy_safe_profile)
->LoadAndLaunch(base::FilePath(path), command_line, cur_dir)) {
return false;
}
if (chrome::GetBrowserCount(privacy_safe_profile) != 0) {
return true;
}
}
#if BUILDFLAG(IS_WIN)
if (command_line.HasSwitch(switches::kWinJumplistAction)) {
if (profile_info.mode == StartupProfileMode::kBrowserWindow) {
privacy_safe_profile->SetUserData(
chrome::kJumpListIconDirname,
base::WrapUnique(new base::SupportsUserData::Data()));
} else {
DUMP_WILL_BE_NOTREACHED()
<< "Failed start for jumplist action: couldn't pick a profile";
}
}
if (command_line.HasSwitch(switches::kNotificationLaunchId)) {
if (NotificationPlatformBridgeWin::HandleActivation(command_line)) {
return true;
}
return false;
}
if (command_line.HasSwitch(credential_provider::kGcpwSigninSwitch)) {
CHECK_EQ(profile_info.mode, StartupProfileMode::kBrowserWindow)
<< "Failed start for GCPW signin: couldn't pick a profile";
Profile* incognito_profile =
privacy_safe_profile->GetPrimaryOTRProfile(true);
DCHECK(incognito_profile->IsIncognitoProfile());
if (!StartGCPWSignin(command_line, incognito_profile)) {
return false;
}
return true;
}
#endif
if (command_line.HasSwitch(switches::kAppId)) {
CHECK_EQ(profile_info.mode, StartupProfileMode::kBrowserWindow)
<< "Failed launch with app: couldn't pick a profile";
std::string app_id = command_line.GetSwitchValueASCII(switches::kAppId);
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
if (apps::OpenDeprecatedApplicationPrompt(privacy_safe_profile, app_id)) {
return true;
}
#endif
if (apps::OpenExtensionApplicationWithReenablePrompt(
privacy_safe_profile, app_id, command_line, cur_dir)) {
return true;
}
}
if (MaybeLaunchAppShortcutWindow(command_line, cur_dir, is_first_run,
privacy_safe_profile)) {
return true;
}
if (!CanOpenWebApp(privacy_safe_profile)) {
LaunchBrowserForLastProfiles(
command_line, cur_dir, process_startup, is_first_run, profile_info,
last_opened_profiles, true);
return true;
}
if (MaybeLaunchExtensionApp(command_line, cur_dir, is_first_run,
privacy_safe_profile)) {
return true;
}
#if !BUILDFLAG(IS_CHROMEOS)
if (web_app::startup::MaybeHandleWebAppLaunch(
command_line, cur_dir, privacy_safe_profile, is_first_run)) {
return true;
}
#endif
LaunchBrowserForLastProfiles(command_line, cur_dir, process_startup,
is_first_run, profile_info, last_opened_profiles,
true);
return true;
}
void StartupBrowserCreator::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) {
base::CommandLine command_line_without_urls(command_line.GetProgram());
for (auto& switch_pair : command_line.GetSwitches()) {
command_line_without_urls.AppendSwitchNative(switch_pair.first,
switch_pair.second);
}
for (Profile* profile : last_opened_profiles) {
DCHECK(!profile->IsGuestSession());
#if !BUILDFLAG(IS_CHROMEOS)
if (!CanOpenProfileOnStartup(
{profile, StartupProfileMode::kBrowserWindow})) {
continue;
}
if (last_used_profile->IsGuestSession()) {
last_used_profile = profile;
}
#endif
SessionStartupPref startup_pref =
GetSessionStartupPref(command_line, profile);
if (profile != last_used_profile &&
startup_pref.type == SessionStartupPref::DEFAULT &&
!HasPendingUncleanExit(profile)) {
continue;
}
LaunchBrowser((profile == last_used_profile) ? command_line
: command_line_without_urls,
profile, cur_dir, process_startup, is_first_run,
true);
process_startup = chrome::startup::IsProcessStartup::kNo;
}
#if !BUILDFLAG(IS_CHROMEOS)
if (process_startup == chrome::startup::IsProcessStartup::kYes) {
ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint(
ProfilePicker::EntryPoint::kOnStartup));
} else
#endif
{
profile_launch_observer.Get().set_profile_to_activate(last_used_profile);
}
}
bool StartupBrowserCreator::ProcessLoadApps(
const base::CommandLine& command_line,
const base::FilePath& cur_dir,
Profile* profile) {
base::CommandLine::StringType path_list =
command_line.GetSwitchValueNative(extensions::switches::kLoadApps);
base::StringTokenizerT<base::CommandLine::StringType,
base::CommandLine::StringType::const_iterator>
tokenizer(path_list, FILE_PATH_LITERAL(","));
if (!tokenizer.GetNext()) {
return false;
}
base::FilePath app_absolute_dir =
base::MakeAbsoluteFilePath(base::FilePath(tokenizer.token_piece()));
if (!apps::AppLoadService::Get(profile)->LoadAndLaunch(
app_absolute_dir, command_line, cur_dir)) {
return false;
}
while (tokenizer.GetNext()) {
app_absolute_dir =
base::MakeAbsoluteFilePath(base::FilePath(tokenizer.token_piece()));
if (!apps::AppLoadService::Get(profile)->Load(app_absolute_dir)) {
return false;
}
}
return true;
}
void StartupBrowserCreator::ProcessCommandLineWithProfile(
const base::CommandLine& command_line,
const base::FilePath& cur_dir,
StartupProfileMode mode,
Profile* profile) {
DCHECK_NE(mode, StartupProfileMode::kError);
if (mode == StartupProfileMode::kBrowserWindow && !profile) {
LOG(ERROR) << "Failed to load the profile.";
return;
}
if (command_line.HasSwitch(switches::kRefreshPlatformPolicy)) {
g_browser_process->browser_policy_connector()->RefreshPlatformPolicies();
return;
}
Profiles last_opened_profiles;
#if !BUILDFLAG(IS_CHROMEOS)
if (chrome::GetTotalBrowserCount() == 0) {
last_opened_profiles =
g_browser_process->profile_manager()->GetLastOpenedProfiles();
}
#endif
StartupBrowserCreator startup_browser_creator;
startup_browser_creator.ProcessCmdLineImpl(
command_line, cur_dir, chrome::startup::IsProcessStartup::kNo,
{profile, mode}, last_opened_profiles);
}
void StartupBrowserCreator::RegisterProcessCommandLineCallback(
ProcessCommandLineCallback cb) {
*GetProcessCommandLineCallback() = cb;
}
void StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
const base::CommandLine& command_line,
const base::FilePath& cur_dir,
const StartupProfilePathInfo& profile_path_info) {
if (profile_path_info.mode == StartupProfileMode::kError) {
return;
}
auto* cb = GetProcessCommandLineCallback();
if (!cb->is_null() && cb->Run(command_line, cur_dir)) {
return;
}
Profile* profile = nullptr;
if (profile_path_info.mode == StartupProfileMode::kBrowserWindow) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
profile = profile_manager->GetProfileByPath(profile_path_info.path);
if (!profile) {
profile_manager->CreateProfileAsync(
profile_path_info.path,
base::BindOnce(&ProcessCommandLineWithProfile, command_line, cur_dir,
profile_path_info.mode));
return;
}
}
ProcessCommandLineWithProfile(command_line, cur_dir, profile_path_info.mode,
profile);
}
void StartupBrowserCreator::OpenStartupPages(
Browser* browser,
chrome::startup::IsProcessStartup process_startup) {
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
chrome::startup::IsFirstRun is_first_run =
first_run::IsChromeFirstRun() ? chrome::startup::IsFirstRun::kYes
: chrome::startup::IsFirstRun::kNo;
StartupBrowserCreatorImpl startup_browser_creator_impl(
base::FilePath(), command_line, is_first_run);
SessionStartupPref session_startup_pref =
StartupBrowserCreator::GetSessionStartupPref(command_line,
browser->profile());
startup_browser_creator_impl.OpenURLsInBrowser(browser, process_startup,
session_startup_pref.urls);
}
bool StartupBrowserCreator::ActivatedProfile() {
return profile_launch_observer.Get().activated_profile();
}
bool HasPendingUncleanExit(Profile* profile) {
return ExitTypeService::GetLastSessionExitType(profile) ==
ExitType::kCrashed &&
!profile_launch_observer.Get().HasBeenLaunchedAndBrowserOpen(
profile) &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kHideCrashRestoreBubble);
}
void AddLaunchedProfile(Profile* profile) {
profile_launch_observer.Get().AddLaunched(profile);
}
StartupProfilePathInfo GetStartupProfilePath(
const base::FilePath& cur_dir,
const base::CommandLine& command_line,
bool ignore_profile_picker) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
const base::FilePath& user_data_dir = profile_manager->user_data_dir();
#if BUILDFLAG(IS_WIN)
base::FilePath profile_basename =
NotificationLaunchId::GetNotificationLaunchProfileBaseName(command_line);
if (!profile_basename.empty()) {
return {.path = user_data_dir.Append(profile_basename),
.mode = StartupProfileMode::kBrowserWindow};
}
#endif
if (profiles::IsGuestModeRequested(command_line,
g_browser_process->local_state(),
false)) {
return {.path = profiles::GetDefaultProfileDir(user_data_dir),
.mode = StartupProfileMode::kBrowserWindow};
}
base::FilePath command_line_profile_directory =
command_line.GetSwitchValuePath(switches::kProfileDirectory);
if (!command_line_profile_directory.empty() &&
command_line.HasSwitch(switches::kIgnoreProfileDirectoryIfNotExists)) {
base::FilePath profile_dir_path =
user_data_dir.Append(command_line_profile_directory);
base::ScopedAllowBlocking allow_blocking;
if (IsProfileDirectoryMarkedForDeletion(profile_dir_path) ||
!base::DirectoryExists(profile_dir_path)) {
command_line_profile_directory = base::FilePath();
}
}
#if BUILDFLAG(IS_MAC)
if (command_line_profile_directory.empty() &&
command_line.HasSwitch(switches::kAppId)) {
std::string app_id = command_line.GetSwitchValueASCII(switches::kAppId);
std::set<base::FilePath> profile_paths =
AppShimRegistry::Get()->GetInstalledProfilesForApp(app_id);
if (!profile_paths.empty()) {
command_line_profile_directory = profile_paths.begin()->BaseName();
}
}
#endif
if (!command_line_profile_directory.empty()) {
return {.path = user_data_dir.Append(command_line_profile_directory),
.mode = StartupProfileMode::kBrowserWindow};
}
#if !BUILDFLAG(IS_CHROMEOS)
auto has_tabs =
StartupTabProviderImpl().HasCommandLineTabs(command_line, cur_dir);
#endif
if (command_line.HasSwitch(switches::kProfileEmail)) {
base::CommandLine::StringType email_native =
command_line.GetSwitchValueNative(switches::kProfileEmail);
if (!email_native.empty()) {
std::string email;
#if BUILDFLAG(IS_WIN)
email = base::WideToUTF8(email_native);
#else
email = std::move(email_native);
#endif
base::FilePath profile_dir =
g_browser_process->profile_manager()->GetProfileDirForEmail(email);
if (!profile_dir.empty()) {
return {.path = profile_dir,
.mode = StartupProfileMode::kBrowserWindow};
}
if (command_line.HasSwitch(switches::kCreateProfileEmailIfNotExists)) {
#if !BUILDFLAG(IS_CHROMEOS)
if (has_tabs != CommandLineTabsPresent::kNo) {
ProfilePicker::SetOpenCommandLineUrlsInNextProfileOpened(true);
}
#endif
if (base::FeatureList::IsEnabled(
features::kCreateProfileIfNoneExists)) {
return {.path = base::FilePath(),
.mode = StartupProfileMode::kProfilePicker};
}
}
}
}
#if BUILDFLAG(IS_CHROMEOS)
return {.path = profile_manager->GetLastUsedProfileDir(),
.mode = StartupProfileMode::kBrowserWindow};
#else
if (ignore_profile_picker) {
return {.path = profile_manager->GetLastUsedProfileDir(),
.mode = StartupProfileMode::kBrowserWindow};
}
if (has_tabs != CommandLineTabsPresent::kNo) {
return {.path = profile_manager->GetLastUsedProfileDir(),
.mode = StartupProfileMode::kBrowserWindow};
}
StartupProfileMode startup_mode = GetStartupProfileMode(
profile_manager, !command_line_profile_directory.empty(), command_line);
if (startup_mode == StartupProfileMode::kProfilePicker) {
return {.path = base::FilePath(), .mode = startup_mode};
}
return {.path = profile_manager->GetLastUsedProfileDir(),
.mode = startup_mode};
#endif
}
#if !BUILDFLAG(IS_CHROMEOS)
StartupProfileInfo GetStartupProfile(const base::FilePath& cur_dir,
const base::CommandLine& command_line) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
StartupProfilePathInfo path_info = GetStartupProfilePath(
cur_dir, command_line, false);
DCHECK_NE(path_info.mode, StartupProfileMode::kError);
StartupProfileMode mode = path_info.mode;
switch (mode) {
case StartupProfileMode::kProfilePicker:
return GetProfilePickerStartupProfileInfo();
case StartupProfileMode::kError:
return {nullptr, StartupProfileMode::kError};
case StartupProfileMode::kBrowserWindow:
break;
}
Profile* profile = profile_manager->GetProfile(path_info.path);
auto* storage = &profile_manager->GetProfileAttributesStorage();
ProfileAttributesEntry* entry =
storage->GetProfileAttributesWithPath(path_info.path);
if (entry && !entry->IsSigninRequired() && profile) {
return {profile, StartupProfileMode::kBrowserWindow};
}
return GetProfilePickerStartupProfileInfo();
}
StartupProfileInfo GetFallbackStartupProfile() {
ProfileManager* profile_manager = g_browser_process->profile_manager();
auto* storage = &profile_manager->GetProfileAttributesStorage();
for (Profile* profile : ProfileManager::GetLastOpenedProfiles()) {
ProfileAttributesEntry* entry =
storage->GetProfileAttributesWithPath(profile->GetPath());
if (!entry || !entry->IsSigninRequired()) {
return {profile, StartupProfileMode::kBrowserWindow};
}
}
StartupProfileInfo profile_picker_info = GetProfilePickerStartupProfileInfo();
if (profile_picker_info.mode != StartupProfileMode::kError) {
return profile_picker_info;
}
for (ProfileAttributesEntry* entry : storage->GetAllProfilesAttributes()) {
if (!entry->IsSigninRequired()) {
Profile* profile = profile_manager->GetProfile(entry->GetPath());
if (profile) {
return {profile, StartupProfileMode::kBrowserWindow};
}
}
}
return {nullptr, StartupProfileMode::kError};
}
#endif