1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/startup/startup_browser_creator.h"
13 #include "apps/switches.h"
14 #include "base/bind.h"
15 #include "base/bind_helpers.h"
16 #include "base/command_line.h"
17 #include "base/debug/alias.h"
18 #include "base/files/file_path.h"
19 #include "base/files/file_util.h"
20 #include "base/lazy_instance.h"
21 #include "base/logging.h"
22 #include "base/macros.h"
23 #include "base/metrics/histogram_base.h"
24 #include "base/metrics/histogram_macros.h"
25 #include "base/metrics/statistics_recorder.h"
26 #include "base/strings/string16.h"
27 #include "base/strings/string_tokenizer.h"
28 #include "base/task_scheduler/post_task.h"
29 #include "base/threading/thread_restrictions.h"
30 #include "base/trace_event/trace_event.h"
31 #include "build/build_config.h"
32 #include "chrome/browser/app_mode/app_mode_utils.h"
33 #include "chrome/browser/apps/app_load_service.h"
34 #include "chrome/browser/browser_process.h"
35 #include "chrome/browser/chrome_notification_types.h"
36 #include "chrome/browser/extensions/startup_helper.h"
37 #include "chrome/browser/first_run/first_run.h"
38 #include "chrome/browser/net/predictor.h"
39 #include "chrome/browser/prefs/incognito_mode_prefs.h"
40 #include "chrome/browser/prefs/session_startup_pref.h"
41 #include "chrome/browser/profiles/profile.h"
42 #include "chrome/browser/profiles/profile_attributes_entry.h"
43 #include "chrome/browser/profiles/profile_attributes_storage.h"
44 #include "chrome/browser/profiles/profile_manager.h"
45 #include "chrome/browser/search_engines/template_url_service_factory.h"
46 #include "chrome/browser/ui/browser.h"
47 #include "chrome/browser/ui/browser_finder.h"
48 #include "chrome/browser/ui/browser_window.h"
49 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
50 #include "chrome/common/buildflags.h"
51 #include "chrome/common/chrome_constants.h"
52 #include "chrome/common/chrome_switches.h"
53 #include "chrome/common/pref_names.h"
54 #include "chrome/common/url_constants.h"
55 #include "components/prefs/pref_registry_simple.h"
56 #include "components/prefs/pref_service.h"
57 #include "components/search_engines/util.h"
58 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
59 #include "components/url_formatter/url_fixer.h"
60 #include "content/public/browser/browser_thread.h"
61 #include "content/public/browser/child_process_security_policy.h"
62 #include "content/public/browser/navigation_controller.h"
63 #include "content/public/browser/notification_observer.h"
64 #include "content/public/browser/notification_registrar.h"
65 #include "content/public/browser/notification_service.h"
66 #include "content/public/browser/notification_source.h"
67 #include "content/public/common/content_switches.h"
68 #include "extensions/common/switches.h"
69 #include "net/base/port_util.h"
70 #include "printing/buildflags/buildflags.h"
72 #if defined(OS_CHROMEOS)
73 #include "chrome/browser/chromeos/app_mode/app_launch_utils.h"
74 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
75 #include "chrome/browser/chromeos/profiles/profile_helper.h"
76 #include "chrome/browser/lifetime/application_lifetime.h"
77 #include "chromeos/chromeos_switches.h"
78 #include "chromeos/cryptohome/cryptohome_parameters.h"
79 #include "components/user_manager/user_manager.h"
81 #include "chrome/browser/ui/user_manager.h"
84 #if defined(TOOLKIT_VIEWS) && (defined(OS_LINUX) || defined(OS_BSD))
85 #include "ui/events/devices/x11/touch_factory_x11.h" // nogncheck
88 #if defined(OS_MACOSX)
89 #include "chrome/browser/web_applications/web_app_mac.h"
93 #include "base/strings/utf_string_conversions.h"
94 #include "chrome/browser/metrics/jumplist_metrics_win.h"
95 #include "chrome/browser/notifications/notification_platform_bridge_win.h"
96 #include "chrome/browser/ui/webui/settings/reset_settings_handler.h"
99 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
100 #include "chrome/browser/printing/print_dialog_cloud.h"
103 using content::BrowserThread;
104 using content::ChildProcessSecurityPolicy;
108 // Keeps track on which profiles have been launched.
109 class ProfileLaunchObserver : public content::NotificationObserver {
111 ProfileLaunchObserver()
112 : profile_to_activate_(NULL),
113 activated_profile_(false) {
114 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
115 content::NotificationService::AllSources());
116 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
117 content::NotificationService::AllSources());
119 ~ProfileLaunchObserver() override {}
121 void Observe(int type,
122 const content::NotificationSource& source,
123 const content::NotificationDetails& details) override {
125 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
126 Profile* profile = content::Source<Profile>(source).ptr();
127 launched_profiles_.erase(profile);
128 opened_profiles_.erase(profile);
129 if (profile == profile_to_activate_)
130 profile_to_activate_ = NULL;
131 // If this profile was the last launched one without an opened window,
132 // then we may be ready to activate |profile_to_activate_|.
133 MaybeActivateProfile();
136 case chrome::NOTIFICATION_BROWSER_OPENED: {
137 Browser* browser = content::Source<Browser>(source).ptr();
139 opened_profiles_.insert(browser->profile());
140 MaybeActivateProfile();
148 bool HasBeenLaunched(const Profile* profile) const {
149 return launched_profiles_.find(profile) != launched_profiles_.end();
152 void AddLaunched(Profile* profile) {
153 launched_profiles_.insert(profile);
154 if (chrome::FindBrowserWithProfile(profile)) {
155 // A browser may get opened before we get initialized (e.g., in tests),
156 // so we never see the NOTIFICATION_BROWSER_OPENED for it.
157 opened_profiles_.insert(profile);
162 launched_profiles_.clear();
163 opened_profiles_.clear();
166 bool activated_profile() { return activated_profile_; }
168 void set_profile_to_activate(Profile* profile) {
169 profile_to_activate_ = profile;
170 MaybeActivateProfile();
174 void MaybeActivateProfile() {
175 if (!profile_to_activate_)
177 // Check that browsers have been opened for all the launched profiles.
178 // Note that browsers opened for profiles that were not added as launched
179 // profiles are simply ignored.
180 std::set<const Profile*>::const_iterator i = launched_profiles_.begin();
181 for (; i != launched_profiles_.end(); ++i) {
182 if (opened_profiles_.find(*i) == opened_profiles_.end())
185 // Asynchronous post to give a chance to the last window to completely
186 // open and activate before trying to activate |profile_to_activate_|.
187 BrowserThread::PostTask(
188 BrowserThread::UI, FROM_HERE,
189 base::BindOnce(&ProfileLaunchObserver::ActivateProfile,
190 base::Unretained(this)));
191 // Avoid posting more than once before ActivateProfile gets called.
192 registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_OPENED,
193 content::NotificationService::AllSources());
194 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
195 content::NotificationService::AllSources());
198 void ActivateProfile() {
199 // We need to test again, in case the profile got deleted in the mean time.
200 if (profile_to_activate_) {
201 Browser* browser = chrome::FindBrowserWithProfile(profile_to_activate_);
202 // |profile| may never get launched, e.g., if it only had
203 // incognito Windows and one of them was used to exit Chrome.
204 // So it won't have a browser in that case.
206 browser->window()->Activate();
207 // No need try to activate this profile again.
208 profile_to_activate_ = NULL;
210 // Assign true here, even if no browser was actually activated, so that
211 // the test can stop waiting, and fail gracefully when needed.
212 activated_profile_ = true;
215 // These are the profiles that get launched by
216 // StartupBrowserCreator::LaunchBrowser.
217 std::set<const Profile*> launched_profiles_;
218 // These are the profiles for which at least one browser window has been
219 // opened. This is needed to know when it is safe to activate
220 // |profile_to_activate_|, otherwise, new browser windows being opened will
221 // be activated on top of it.
222 std::set<const Profile*> opened_profiles_;
223 content::NotificationRegistrar registrar_;
224 // This is NULL until the profile to activate has been chosen. This value,
225 // should only be set once all profiles have been launched, otherwise,
226 // activation may not happen after the launch of newer profiles.
227 Profile* profile_to_activate_;
228 // Set once we attempted to activate a profile. We only get one shot at this.
229 bool activated_profile_;
231 DISALLOW_COPY_AND_ASSIGN(ProfileLaunchObserver);
234 base::LazyInstance<ProfileLaunchObserver>::DestructorAtExit
235 profile_launch_observer = LAZY_INSTANCE_INITIALIZER;
237 // Dumps the current set of the browser process's histograms to |output_file|.
238 // The file is overwritten if it exists. This function should only be called in
239 // the blocking pool.
240 void DumpBrowserHistograms(const base::FilePath& output_file) {
241 base::AssertBlockingAllowed();
243 std::string output_string(
244 base::StatisticsRecorder::ToJSON(base::JSON_VERBOSITY_LEVEL_FULL));
245 base::WriteFile(output_file, output_string.data(),
246 static_cast<int>(output_string.size()));
249 // Returns whether |profile| can be opened during Chrome startup without
250 // explicit user action.
251 bool CanOpenProfileOnStartup(Profile* profile) {
252 #if defined(OS_CHROMEOS)
253 // On ChromeOS, the user has already chosen and logged into the profile before
257 // Profiles that require signin are not available.
258 ProfileAttributesEntry* entry = nullptr;
259 if (g_browser_process->profile_manager()
260 ->GetProfileAttributesStorage()
261 .GetProfileAttributesWithPath(profile->GetPath(), &entry) &&
262 entry->IsSigninRequired()) {
266 // Guest or system profiles are not available unless a separate process
267 // already has a window open for the profile.
268 return (!profile->IsGuestSession() && !profile->IsSystemProfile()) ||
269 (chrome::GetBrowserCount(profile->GetOffTheRecordProfile()) > 0);
273 void ShowUserManagerOnStartup(const base::CommandLine& command_line) {
274 #if !defined(OS_CHROMEOS)
275 // TODO(crbug/821659): Clean up the desktop UserManager webui.
276 profiles::UserManagerAction action =
277 command_line.HasSwitch(switches::kShowAppList) ?
278 profiles::USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER :
279 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION;
280 UserManager::Show(base::FilePath(), action);
281 #endif // !defined(OS_CHROMEOS)
286 StartupBrowserCreator::StartupBrowserCreator()
287 : is_default_browser_dialog_suppressed_(false),
288 show_main_browser_window_(true) {}
290 StartupBrowserCreator::~StartupBrowserCreator() {}
293 bool StartupBrowserCreator::was_restarted_read_ = false;
296 bool StartupBrowserCreator::in_synchronous_profile_launch_ = false;
298 void StartupBrowserCreator::AddFirstRunTab(const GURL& url) {
299 first_run_tabs_.push_back(url);
302 bool StartupBrowserCreator::Start(const base::CommandLine& cmd_line,
303 const base::FilePath& cur_dir,
304 Profile* last_used_profile,
305 const Profiles& last_opened_profiles) {
306 TRACE_EVENT0("startup", "StartupBrowserCreator::Start");
307 SCOPED_UMA_HISTOGRAM_TIMER("Startup.StartupBrowserCreator_Start");
308 return ProcessCmdLineImpl(cmd_line, cur_dir, true, last_used_profile,
309 last_opened_profiles);
313 bool StartupBrowserCreator::InSynchronousProfileLaunch() {
314 return in_synchronous_profile_launch_;
317 bool StartupBrowserCreator::LaunchBrowser(
318 const base::CommandLine& command_line,
320 const base::FilePath& cur_dir,
321 chrome::startup::IsProcessStartup process_startup,
322 chrome::startup::IsFirstRun is_first_run) {
324 in_synchronous_profile_launch_ =
325 process_startup == chrome::startup::IS_PROCESS_STARTUP;
327 // ChromeOS does a direct browser launch from UserSessionManager, so this is
328 // the earliest place we can enable the log.
329 if (command_line.HasSwitch(switches::kDnsLogDetails))
330 chrome_browser_net::EnablePredictorDetailedLog(true);
332 // Continue with the incognito profile from here on if Incognito mode
334 if (IncognitoModePrefs::ShouldLaunchIncognito(command_line,
335 profile->GetPrefs())) {
336 profile = profile->GetOffTheRecordProfile();
337 } else if (command_line.HasSwitch(switches::kIncognito)) {
338 LOG(WARNING) << "Incognito mode disabled by policy, launching a normal "
339 << "browser session.";
342 // Note: This check should have been done in ProcessCmdLineImpl()
343 // before calling this function. However chromeos/login/login_utils.cc
344 // calls this function directly (see comments there) so it has to be checked
346 const bool silent_launch = command_line.HasSwitch(switches::kSilentLaunch);
348 if (!silent_launch) {
349 StartupBrowserCreatorImpl lwp(cur_dir, command_line, this, is_first_run);
350 const std::vector<GURL> urls_to_launch =
351 GetURLsFromCommandLine(command_line, cur_dir, profile);
352 const bool launched =
353 lwp.Launch(profile, urls_to_launch, in_synchronous_profile_launch_);
354 in_synchronous_profile_launch_ = false;
356 LOG(ERROR) << "launch error";
360 in_synchronous_profile_launch_ = false;
363 profile_launch_observer.Get().AddLaunched(profile);
365 #if defined(OS_CHROMEOS)
366 chromeos::ProfileHelper::Get()->ProfileStartup(profile, process_startup);
372 bool StartupBrowserCreator::WasRestarted() {
373 // Stores the value of the preference kWasRestarted had when it was read.
374 static bool was_restarted = false;
376 if (!was_restarted_read_) {
377 PrefService* pref_service = g_browser_process->local_state();
378 was_restarted = pref_service->GetBoolean(prefs::kWasRestarted);
379 pref_service->SetBoolean(prefs::kWasRestarted, false);
380 was_restarted_read_ = true;
382 return was_restarted;
386 SessionStartupPref StartupBrowserCreator::GetSessionStartupPref(
387 const base::CommandLine& command_line,
390 PrefService* prefs = profile->GetPrefs();
391 SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
393 // IsChromeFirstRun() looks for a sentinel file to determine whether the user
394 // is starting Chrome for the first time. On Chrome OS, the sentinel is stored
395 // in a location shared by all users and the check is meaningless. Query the
396 // UserManager instead to determine whether the user is new.
397 #if defined(OS_CHROMEOS)
398 const bool is_first_run =
399 user_manager::UserManager::Get()->IsCurrentUserNew();
400 // On ChromeOS restarts force the user to login again. The expectation is that
401 // after a login the user gets clean state. For this reason we ignore
402 // StartupBrowserCreator::WasRestarted(). However
403 // StartupBrowserCreator::WasRestarted has to be called in order to correctly
404 // update pref values.
405 const bool did_restart = false;
406 StartupBrowserCreator::WasRestarted();
408 const bool is_first_run = first_run::IsChromeFirstRun();
409 const bool did_restart = StartupBrowserCreator::WasRestarted();
412 // The pref has an OS-dependent default value. For the first run only, this
413 // default is overridden with SessionStartupPref::DEFAULT so that first run
414 // behavior (sync promo, welcome page) is consistently invoked.
415 // This applies only if the pref is still at its default and has not been
416 // set by the user, managed prefs or policy.
417 if (is_first_run && SessionStartupPref::TypeIsDefault(prefs))
418 pref.type = SessionStartupPref::DEFAULT;
420 // The switches::kRestoreLastSession command line switch is used to restore
421 // sessions after a browser self restart (e.g. after a Chrome upgrade).
422 // However, new profiles can be created from a browser process that has this
423 // switch so do not set the session pref to SessionStartupPref::LAST for
424 // those as there is nothing to restore.
425 if ((command_line.HasSwitch(switches::kRestoreLastSession) || did_restart) &&
426 !profile->IsNewProfile()) {
427 pref.type = SessionStartupPref::LAST;
430 // A browser starting for a profile being unlocked should always restore.
431 if (!profile->IsGuestSession()) {
432 ProfileAttributesEntry* entry = nullptr;
434 g_browser_process->profile_manager()
435 ->GetProfileAttributesStorage()
436 .GetProfileAttributesWithPath(profile->GetPath(), &entry);
438 if (has_entry && entry->IsSigninRequired())
439 pref.type = SessionStartupPref::LAST;
442 if (pref.type == SessionStartupPref::LAST &&
443 IncognitoModePrefs::ShouldLaunchIncognito(command_line, prefs)) {
444 // We don't store session information when incognito. If the user has
445 // chosen to restore last session and launched incognito, fallback to
446 // default launch behavior.
447 pref.type = SessionStartupPref::DEFAULT;
454 void StartupBrowserCreator::ClearLaunchedProfilesForTesting() {
455 profile_launch_observer.Get().Clear();
459 void StartupBrowserCreator::RegisterLocalStatePrefs(
460 PrefRegistrySimple* registry) {
462 registry->RegisterStringPref(prefs::kLastWelcomedOSVersion, std::string());
463 registry->RegisterBooleanPref(prefs::kWelcomePageOnOSUpgradeEnabled, true);
464 registry->RegisterBooleanPref(prefs::kHasSeenWin10PromoPage, false);
465 registry->RegisterBooleanPref(prefs::kResetHasSeenWin10PromoPage, true);
467 registry->RegisterBooleanPref(prefs::kSuppressUnsupportedOSWarning, false);
468 registry->RegisterBooleanPref(prefs::kWasRestarted, false);
472 void StartupBrowserCreator::RegisterProfilePrefs(PrefRegistrySimple* registry) {
473 // Default to true so that existing users are not shown the Welcome page.
474 // ProfileManager handles setting this to false for new profiles upon
476 registry->RegisterBooleanPref(prefs::kHasSeenWelcomePage, true);
480 std::vector<GURL> StartupBrowserCreator::GetURLsFromCommandLine(
481 const base::CommandLine& command_line,
482 const base::FilePath& cur_dir,
486 std::vector<GURL> urls;
488 const base::CommandLine::StringVector& params = command_line.GetArgs();
489 for (size_t i = 0; i < params.size(); ++i) {
490 base::FilePath param = base::FilePath(params[i]);
491 // Handle Vista way of searching - "? <search-term>"
492 if ((param.value().size() > 2) && (param.value()[0] == '?') &&
493 (param.value()[1] == ' ')) {
494 GURL url(GetDefaultSearchURLForSearchTerms(
495 TemplateURLServiceFactory::GetForProfile(profile),
496 param.LossyDisplayName().substr(2)));
497 if (url.is_valid()) {
503 // Otherwise, fall through to treating it as a URL.
505 // This will create a file URL or a regular URL.
506 // This call can (in rare circumstances) block the UI thread.
507 // Allow it until this bug is fixed.
508 // http://code.google.com/p/chromium/issues/detail?id=60641
509 GURL url = GURL(param.MaybeAsASCII());
511 // http://crbug.com/371030: Only use URLFixerUpper if we don't have a valid
512 // URL, otherwise we will look in the current directory for a file named
513 // 'about' if the browser was started with a about:foo argument.
514 // http://crbug.com/424991: Always use URLFixerUpper on file:// URLs,
515 // otherwise we wouldn't correctly handle '#' in a file name.
516 if (!url.is_valid() || url.SchemeIsFile()) {
517 base::ThreadRestrictions::ScopedAllowIO allow_io;
518 url = url_formatter::FixupRelativeFile(cur_dir, param);
520 // Exclude dangerous schemes.
524 const GURL settings_url = GURL(chrome::kChromeUISettingsURL);
525 bool url_points_to_an_approved_settings_page = false;
526 #if defined(OS_CHROMEOS)
527 // In ChromeOS, allow any settings page to be specified on the command line.
528 url_points_to_an_approved_settings_page =
529 url.GetOrigin() == settings_url.GetOrigin();
531 // Exposed for external cleaners to offer a settings reset to the
532 // user. The allowed URLs must match exactly.
533 const GURL reset_settings_url =
534 settings_url.Resolve(chrome::kResetProfileSettingsSubPage);
535 url_points_to_an_approved_settings_page = url == reset_settings_url;
537 // On Windows, also allow a hash for the Chrome Cleanup Tool.
538 const GURL reset_settings_url_with_cct_hash = reset_settings_url.Resolve(
540 settings::ResetSettingsHandler::kCctResetSettingsHash);
541 url_points_to_an_approved_settings_page =
542 url_points_to_an_approved_settings_page ||
543 url == reset_settings_url_with_cct_hash;
544 #endif // defined(OS_WIN)
545 #endif // defined(OS_CHROMEOS)
547 ChildProcessSecurityPolicy* policy =
548 ChildProcessSecurityPolicy::GetInstance();
549 if (policy->IsWebSafeScheme(url.scheme()) ||
550 url.SchemeIs(url::kFileScheme) ||
551 url_points_to_an_approved_settings_page ||
552 (url.spec().compare(url::kAboutBlankURL) == 0)) {
559 bool StartupBrowserCreator::ProcessCmdLineImpl(
560 const base::CommandLine& command_line,
561 const base::FilePath& cur_dir,
562 bool process_startup,
563 Profile* last_used_profile,
564 const Profiles& last_opened_profiles) {
565 DCHECK_CURRENTLY_ON(BrowserThread::UI);
566 TRACE_EVENT0("startup", "StartupBrowserCreator::ProcessCmdLineImpl");
568 DCHECK(last_used_profile);
569 if (process_startup &&
570 command_line.HasSwitch(switches::kDisablePromptOnRepost)) {
571 content::NavigationController::DisablePromptOnRepost();
574 bool silent_launch = false;
575 bool can_use_last_profile =
576 (CanOpenProfileOnStartup(last_used_profile) &&
577 !IncognitoModePrefs::ShouldLaunchIncognito(
578 command_line, last_used_profile->GetPrefs()));
580 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
581 // If we are just displaying a print dialog we shouldn't open browser
583 if (command_line.HasSwitch(switches::kCloudPrintFile) &&
584 can_use_last_profile &&
585 print_dialog_cloud::CreatePrintDialogFromCommandLine(last_used_profile,
587 silent_launch = true;
589 #endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
591 if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) {
592 std::string allowed_ports =
593 command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts);
594 net::SetExplicitlyAllowedPorts(allowed_ports);
597 if (command_line.HasSwitch(switches::kValidateCrx)) {
598 if (!process_startup) {
599 LOG(ERROR) << "chrome is already running; you must close all running "
600 << "instances before running with the --"
601 << switches::kValidateCrx << " flag";
604 extensions::StartupHelper helper;
607 if (helper.ValidateCrx(command_line, &error))
608 message = std::string("ValidateCrx Success");
610 message = std::string("ValidateCrx Failure: ") + error;
611 printf("%s\n", message.c_str());
615 #if defined(OS_CHROMEOS)
617 // The browser will be launched after the user logs in.
618 if (command_line.HasSwitch(chromeos::switches::kLoginManager))
619 silent_launch = true;
621 if (chrome::IsRunningInAppMode() &&
622 command_line.HasSwitch(switches::kAppId)) {
623 chromeos::LaunchAppOrDie(
625 command_line.GetSwitchValueASCII(switches::kAppId));
627 // Skip browser launch since app mode launches its app window.
628 silent_launch = true;
631 // If we are a demo app session and we crashed, there is no safe recovery
632 // possible. We should instead cleanly exit and go back to the OOBE screen,
633 // where we will launch again after the timeout has expired.
634 if (chromeos::DemoAppLauncher::IsDemoAppSession(
635 cryptohome::Identification::FromString(
636 command_line.GetSwitchValueASCII(chromeos::switches::kLoginUser))
638 chrome::AttemptUserExit();
641 #endif // OS_CHROMEOS
643 #if defined(TOOLKIT_VIEWS) && defined(USE_X11)
644 ui::TouchFactory::SetTouchDeviceListFromCommandLine();
647 #if defined(OS_MACOSX)
648 if (web_app::MaybeRebuildShortcut(command_line))
652 if (!process_startup &&
653 command_line.HasSwitch(switches::kDumpBrowserHistograms)) {
654 // Only handle --dump-browser-histograms from a rendezvous. In this case, do
655 // not open a new browser window even if no output file was given.
656 base::FilePath output_file(
657 command_line.GetSwitchValuePath(switches::kDumpBrowserHistograms));
658 if (!output_file.empty()) {
659 base::PostTaskWithTraits(
661 {base::MayBlock(), base::TaskPriority::BACKGROUND,
662 base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
663 base::BindOnce(&DumpBrowserHistograms, output_file));
665 silent_launch = true;
668 // If --no-startup-window is specified and Chrome is already running then do
669 // not open a new window.
670 if (!process_startup && command_line.HasSwitch(switches::kNoStartupWindow))
671 silent_launch = true;
673 // If we don't want to launch a new browser window or tab we are done here.
676 startup_metric_utils::SetNonBrowserUIDisplayed();
680 if (command_line.HasSwitch(extensions::switches::kLoadApps) &&
681 can_use_last_profile) {
682 if (!ProcessLoadApps(command_line, cur_dir, last_used_profile))
685 // Return early here to avoid opening a browser window.
686 // The exception is when there are no browser windows, since we don't want
687 // chrome to shut down.
688 // TODO(jackhou): Do this properly once keep-alive is handled by the
689 // background page of apps. Tracked at http://crbug.com/175381
690 if (chrome::GetBrowserCount(last_used_profile) != 0)
694 // Check for --load-and-launch-app.
695 if (command_line.HasSwitch(apps::kLoadAndLaunchApp) && can_use_last_profile) {
696 base::CommandLine::StringType path =
697 command_line.GetSwitchValueNative(apps::kLoadAndLaunchApp);
699 if (!apps::AppLoadService::Get(last_used_profile)->LoadAndLaunch(
700 base::FilePath(path), command_line, cur_dir)) {
704 // Return early here since we don't want to open a browser window.
705 // The exception is when there are no browser windows, since we don't want
706 // chrome to shut down.
707 // TODO(jackhou): Do this properly once keep-alive is handled by the
708 // background page of apps. Tracked at http://crbug.com/175381
709 if (chrome::GetBrowserCount(last_used_profile) != 0)
714 // Log whether this process was a result of an action in the Windows Jumplist.
715 if (command_line.HasSwitch(switches::kWinJumplistAction)) {
716 jumplist::LogJumplistActionFromSwitchValue(
717 command_line.GetSwitchValueASCII(switches::kWinJumplistAction));
718 // Use a non-NULL pointer to indicate JumpList has been used. We re-use
719 // chrome::kJumpListIconDirname as the key to the data.
720 last_used_profile->SetUserData(
721 chrome::kJumpListIconDirname,
722 base::WrapUnique(new base::SupportsUserData::Data()));
724 #endif // defined(OS_WIN)
726 return LaunchBrowserForLastProfiles(command_line, cur_dir, process_startup,
727 last_used_profile, last_opened_profiles);
730 bool StartupBrowserCreator::LaunchBrowserForLastProfiles(
731 const base::CommandLine& command_line,
732 const base::FilePath& cur_dir,
733 bool process_startup,
734 Profile* last_used_profile,
735 const Profiles& last_opened_profiles) {
736 chrome::startup::IsProcessStartup is_process_startup = process_startup ?
737 chrome::startup::IS_PROCESS_STARTUP :
738 chrome::startup::IS_NOT_PROCESS_STARTUP;
739 chrome::startup::IsFirstRun is_first_run = first_run::IsChromeFirstRun() ?
740 chrome::startup::IS_FIRST_RUN : chrome::startup::IS_NOT_FIRST_RUN;
741 // |last_opened_profiles| will be empty in the following circumstances:
742 // - This is the first launch. |last_used_profile| is the initial profile.
743 // - The user exited the browser by closing all windows for all
744 // profiles. |last_used_profile| is the profile which owned the last open
746 // - Only incognito windows were open when the browser exited.
747 // |last_used_profile| is the last used incognito profile. Restoring it will
748 // create a browser window for the corresponding original profile.
749 // - All of the last opened profiles fail to initialize.
750 if (last_opened_profiles.empty()) {
751 if (CanOpenProfileOnStartup(last_used_profile)) {
752 Profile* profile_to_open =
753 last_used_profile->IsGuestSession()
754 ? last_used_profile->GetOffTheRecordProfile()
757 return LaunchBrowser(command_line, profile_to_open, cur_dir,
758 is_process_startup, is_first_run);
760 // Show UserManager if |last_used_profile| can't be auto opened.
761 ShowUserManagerOnStartup(command_line);
764 return ProcessLastOpenedProfiles(command_line, cur_dir, is_process_startup,
765 is_first_run, last_used_profile,
766 last_opened_profiles);
769 bool StartupBrowserCreator::ProcessLastOpenedProfiles(
770 const base::CommandLine& command_line,
771 const base::FilePath& cur_dir,
772 chrome::startup::IsProcessStartup is_process_startup,
773 chrome::startup::IsFirstRun is_first_run,
774 Profile* last_used_profile,
775 const Profiles& last_opened_profiles) {
776 base::CommandLine command_line_without_urls(command_line.GetProgram());
777 for (auto& switch_pair : command_line.GetSwitches()) {
778 command_line_without_urls.AppendSwitchNative(switch_pair.first,
782 // TODO(scottmg): DEBUG_ variables added for https://crbug.com/614753.
783 size_t DEBUG_num_profiles_on_entry = last_opened_profiles.size();
784 base::debug::Alias(&DEBUG_num_profiles_on_entry);
785 int DEBUG_loop_counter = 0;
786 base::debug::Alias(&DEBUG_loop_counter);
788 base::debug::Alias(&last_opened_profiles);
789 const Profile* DEBUG_profile_0 = nullptr;
790 const Profile* DEBUG_profile_1 = nullptr;
791 if (last_opened_profiles.size() > 0)
792 DEBUG_profile_0 = last_opened_profiles[0];
793 if (last_opened_profiles.size() > 1)
794 DEBUG_profile_1 = last_opened_profiles[1];
795 base::debug::Alias(&DEBUG_profile_0);
796 base::debug::Alias(&DEBUG_profile_1);
798 size_t DEBUG_num_profiles_at_loop_start = std::numeric_limits<size_t>::max();
799 base::debug::Alias(&DEBUG_num_profiles_at_loop_start);
801 Profiles::const_iterator DEBUG_it_begin = last_opened_profiles.begin();
802 base::debug::Alias(&DEBUG_it_begin);
803 Profiles::const_iterator DEBUG_it_end = last_opened_profiles.end();
804 base::debug::Alias(&DEBUG_it_end);
806 // Launch the profiles in the order they became active.
807 for (Profiles::const_iterator it = last_opened_profiles.begin();
808 it != last_opened_profiles.end(); ++it, ++DEBUG_loop_counter) {
809 DEBUG_num_profiles_at_loop_start = last_opened_profiles.size();
810 DCHECK(!(*it)->IsGuestSession());
812 #if !defined(OS_CHROMEOS)
813 // Skip any locked profile.
814 if (!CanOpenProfileOnStartup(*it))
817 // Guest profiles should not be reopened on startup. This can happen if
818 // the last used profile was a Guest, but other profiles were also open
819 // when Chrome was closed. In this case, pick a different open profile
820 // to be the active one, since the Guest profile is never added to the
821 // list of open profiles.
822 if (last_used_profile->IsGuestSession())
823 last_used_profile = *it;
826 // Don't launch additional profiles which would only open a new tab
827 // page. When restarting after an update, all profiles will reopen last
829 SessionStartupPref startup_pref = GetSessionStartupPref(command_line, *it);
830 if (*it != last_used_profile &&
831 startup_pref.type == SessionStartupPref::DEFAULT &&
832 !HasPendingUncleanExit(*it))
834 if (!LaunchBrowser((*it == last_used_profile) ? command_line
835 : command_line_without_urls,
836 *it, cur_dir, is_process_startup, is_first_run))
838 // We've launched at least one browser.
839 is_process_startup = chrome::startup::IS_NOT_PROCESS_STARTUP;
842 // Set the |last_used_profile| to activate if a browser is launched for at
843 // least one profile. Otherwise, show UserManager.
844 // Note that this must be done after all profiles have
845 // been launched so the observer knows about all profiles to wait before
846 // activation this one.
847 #if !defined(OS_CHROMEOS)
848 if (is_process_startup == chrome::startup::IS_PROCESS_STARTUP)
849 ShowUserManagerOnStartup(command_line);
852 profile_launch_observer.Get().set_profile_to_activate(last_used_profile);
857 bool StartupBrowserCreator::ProcessLoadApps(
858 const base::CommandLine& command_line,
859 const base::FilePath& cur_dir,
861 base::CommandLine::StringType path_list =
862 command_line.GetSwitchValueNative(extensions::switches::kLoadApps);
864 base::StringTokenizerT<base::CommandLine::StringType,
865 base::CommandLine::StringType::const_iterator>
866 tokenizer(path_list, FILE_PATH_LITERAL(","));
868 if (!tokenizer.GetNext())
871 base::FilePath app_absolute_dir =
872 base::MakeAbsoluteFilePath(base::FilePath(tokenizer.token()));
873 if (!apps::AppLoadService::Get(profile)->LoadAndLaunch(
874 app_absolute_dir, command_line, cur_dir)) {
878 while (tokenizer.GetNext()) {
880 base::MakeAbsoluteFilePath(base::FilePath(tokenizer.token()));
882 if (!apps::AppLoadService::Get(profile)->Load(app_absolute_dir)) {
891 void StartupBrowserCreator::ProcessCommandLineOnProfileCreated(
892 const base::CommandLine& command_line,
893 const base::FilePath& cur_dir,
895 Profile::CreateStatus status) {
896 if (status != Profile::CREATE_STATUS_INITIALIZED)
898 StartupBrowserCreator startup_browser_creator;
899 startup_browser_creator.ProcessCmdLineImpl(command_line, cur_dir, false,
900 profile, Profiles());
904 void StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
905 const base::CommandLine& command_line,
906 const base::FilePath& cur_dir,
907 const base::FilePath& profile_path) {
908 ProfileManager* profile_manager = g_browser_process->profile_manager();
909 Profile* profile = profile_manager->GetProfileByPath(profile_path);
911 // The profile isn't loaded yet and so needs to be loaded asynchronously.
913 profile_manager->CreateProfileAsync(
915 base::Bind(&ProcessCommandLineOnProfileCreated, command_line, cur_dir),
916 base::string16(), std::string(), std::string());
919 StartupBrowserCreator startup_browser_creator;
920 startup_browser_creator.ProcessCmdLineImpl(command_line, cur_dir, false,
921 profile, Profiles());
925 void StartupBrowserCreator::OpenStartupPages(Browser* browser,
926 bool process_startup) {
927 base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
928 chrome::startup::IsFirstRun is_first_run =
929 first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN
930 : chrome::startup::IS_NOT_FIRST_RUN;
931 StartupBrowserCreatorImpl startup_browser_creator_impl(
932 base::FilePath(), command_line, is_first_run);
933 SessionStartupPref session_startup_pref =
934 StartupBrowserCreator::GetSessionStartupPref(command_line,
936 startup_browser_creator_impl.OpenURLsInBrowser(browser, process_startup,
937 session_startup_pref.urls);
941 bool StartupBrowserCreator::ActivatedProfile() {
942 return profile_launch_observer.Get().activated_profile();
945 bool HasPendingUncleanExit(Profile* profile) {
946 return profile->GetLastSessionExitType() == Profile::EXIT_CRASHED &&
947 !profile_launch_observer.Get().HasBeenLaunched(profile);
950 base::FilePath GetStartupProfilePath(const base::FilePath& user_data_dir,
951 const base::CommandLine& command_line) {
952 if (command_line.HasSwitch(switches::kProfileDirectory)) {
953 return user_data_dir.Append(
954 command_line.GetSwitchValuePath(switches::kProfileDirectory));
958 if (command_line.HasSwitch(switches::kNotificationLaunchId)) {
959 std::string profile_id =
960 NotificationPlatformBridgeWin::GetProfileIdFromLaunchId(
961 command_line.GetSwitchValueNative(switches::kNotificationLaunchId));
962 if (!profile_id.empty()) {
963 return user_data_dir.Append(
964 base::FilePath(base::UTF8ToUTF16(profile_id)));
967 #endif // defined(OS_WIN)
969 return g_browser_process->profile_manager()->GetLastUsedProfileDir(
973 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
974 Profile* GetStartupProfile(const base::FilePath& user_data_dir,
975 const base::CommandLine& command_line) {
976 ProfileManager* profile_manager = g_browser_process->profile_manager();
978 base::FilePath profile_path =
979 GetStartupProfilePath(user_data_dir, command_line);
980 Profile* profile = profile_manager->GetProfile(profile_path);
982 // If there is no entry in profile attributes storage, the profile is deleted,
983 // and we should show the user manager. Also, when using
984 // --new-profile-management, if the profile is locked we should show the user
985 // manager as well. When neither of these is true, we can safely start up with
987 auto* storage = &profile_manager->GetProfileAttributesStorage();
988 ProfileAttributesEntry* entry;
989 bool has_entry = storage->GetProfileAttributesWithPath(profile_path, &entry);
990 if (has_entry && (!entry->IsSigninRequired() || !profile)) {
994 // We want to show the user manager. To indicate this, return the guest
995 // profile. However, we can only do this if the system profile (where the user
996 // manager lives) also exists (or is creatable).
997 return profile_manager->GetProfile(ProfileManager::GetSystemProfilePath()) ?
998 profile_manager->GetProfile(ProfileManager::GetGuestProfilePath()) :
1002 Profile* GetFallbackStartupProfile() {
1003 ProfileManager* profile_manager = g_browser_process->profile_manager();
1004 // The only known reason for profiles to fail initialization is being unable
1005 // to create the profile directory, and this has already happened in
1006 // GetStartupProfilePath() before calling this function. In this case,
1007 // creation of new profiles is expected to fail. So only existing profiles are
1008 // attempted for fallback.
1010 // If the last used profile could not be initialized, see if any of other last
1011 // opened profiles can be initialized successfully.
1012 auto* storage = &profile_manager->GetProfileAttributesStorage();
1013 for (Profile* profile : ProfileManager::GetLastOpenedProfiles()) {
1014 // Return any profile that is not locked.
1015 ProfileAttributesEntry* entry;
1016 bool has_entry = storage->GetProfileAttributesWithPath(profile->GetPath(),
1018 if (!has_entry || !entry->IsSigninRequired())
1022 // Couldn't initialize any last opened profiles. Try to show the user manager,
1023 // which requires successful initialization of the guest and system profiles.
1024 Profile* guest_profile =
1025 profile_manager->GetProfile(ProfileManager::GetGuestProfilePath());
1026 Profile* system_profile =
1027 profile_manager->GetProfile(ProfileManager::GetSystemProfilePath());
1028 if (guest_profile && system_profile)
1029 return guest_profile;
1031 // Couldn't show the user manager either. Try to open any profile that is not
1033 for (ProfileAttributesEntry* entry : storage->GetAllProfilesAttributes()) {
1034 if (!entry->IsSigninRequired()) {
1035 Profile* profile = profile_manager->GetProfile(entry->GetPath());
1043 #endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)